'=========================================================================== ' Subject: PANNING W/256 COLORS Date: 10-09-96 (14:03) ' Author: Douglas H. Lusher Code: QB, PDS ' Origin: comp.lang.basic.misc Packet: GRAPHICS.ABC '=========================================================================== 'Some of you, I trust, took note of the code that I posted a few 'days ago demonstrating how to create a large virtual screen in 'SCREEN 12 and pan the display screen over the virtual screen. 'Shortly after, some one posted a request to have this implemented 'in 320x200x256 mode. Well, it can be done, but it's not really 'worth it. SCREEN 13 only has 65536 bytes of memory available and 'is already using 98% of that - so there's really no room to 'expand in. In SCREEN 13, a virtual screen could not be any wider 'than 320 pixels and the most height you could add would be about 'four lines. By contrast, in SCREEN 12 the visible screen area 'requires only about 58% of the available memory, so there's plenty 'of extra space to use. One alternative, if a large virtual screen 'is needed in a 256 color mode is to use Mode-X. This is what I 'have done in the demo below. Since Mode-X has all 256K of video 'memory available, you have room to set up a large virtual screen. 'Unfortunately, the memory map in this mode is much more complex 'than in SCREEN 13, and that makes this mode difficult to work 'with. On the other hand, my Mode-X code is for 320x240, so you 'have square pixels and don't have to worry about adjusting for 'the aspect ratio of the screen. Anyway, if you want it, here it is: 'this code is a demo of how to set the VGA to 320x240x256 ' mode and then create a much larger virtual screen ' and pan the display screen around the virtual screen. 'by Douglas H. Lusher - Oct 8, 1996 DECLARE SUB XPAN () DECLARE SUB DrawCircle (X%, Y%, Radius%, Culler%) DECLARE SUB DrawLine (X1%, Y1%, X2%, Y2%, Culler%) DECLARE SUB XPRINT (X%, Y%, Text$, Culler%) DECLARE SUB XPSET (X%, Y%, Culler%) DECLARE SUB Screen320x240 () DECLARE SUB InitCharSet (Segment%, Offset%, CharHeight%) DEFINT A-Z '$INCLUDE: 'QB.BI' RANDOMIZE TIMER DIM ScrnWid%, ScrnHgt%, VScrnWid%, VScrnHgt%, BytesPerLine% DIM APage%, CharHgt% REDIM HiNibble%(0), LoNibble%(0), BitMask%(3) CALL Screen320x240 'the width of the virtual screen in pixels: VScrnWid% = 592 'In this screen mode, the following must be true: ' VScrnWid% must be equal to or greater than 320 ' VScrnWid% must be less than or equal to 1088 ' VScrnWid% must be evenly divisible by 8 BytesPerLine% = VScrnWid% \ 4 'the height of the virtual screen in pixels: VScrnHgt% = 442 'In this screen mode, the following must be true: ' VScrnHgt% must be equal to or greater than 240 ' VScrnHgt% must be less than or equal to 819 ' The product of VScrnHgt% multiplied by VScrnWid% must be less ' than or equal to 262144 'create the virtual screen: OUT &H3D4, &H13: OUT &H3D5, VScrnWid% \ 8 'put up some graphics CALL DrawLine(0, 0, VScrnWid% - 1, 0, 1) CALL DrawLine(VScrnWid% - 1, 0, VScrnWid% - 1, VScrnHgt% - 1, 2) CALL DrawLine(VScrnWid% - 1, VScrnHgt% - 1, 0, VScrnHgt% - 1, 3) CALL DrawLine(0, VScrnHgt% - 1, 0, 0, 4) RR% = VScrnHgt%: IF VScrnWid% < VScrnHgt% THEN RR% = VScrnWid% DO UNTIL LEN(INKEY$) X1% = INT(RND * VScrnWid%) Y1% = INT(RND * VScrnHgt%) X2% = INT(RND * VScrnWid%) Y2% = INT(RND * VScrnHgt%) C% = INT(RND * 14) + 1 CALL DrawLine(X1%, Y1%, X2%, Y2%, C%) R% = INT(RND * (RR% \ 4)) X1% = INT(RND * VScrnWid%) Y1% = INT(RND * VScrnHgt%) C% = INT(RND * 254) + 1 CALL DrawCircle(X1%, Y1%, R%, C%) LOOP CALL XPRINT(8, 0, "Upper Left", 15) CALL XPRINT(VScrnWid% - 96, 0, "Upper Right", 15) CALL XPRINT(8, VScrnHgt% - 16, "Lower Left", 15) CALL XPRINT(VScrnWid% - 96, VScrnHgt% - 16, "Lower Right", 15) CALL XPAN SCREEN 13: SCREEN 0: WIDTH 80 END SUB DrawCircle (X%, Y%, Radius%, Culler%) 'a routine to draw circles using only integers and integer math 'an implementation of Bresenham's algorithm 'by Douglas H. Lusher, 05-09-1996 A% = 0 B% = Radius% D% = (1 - Radius%) * 2 XX1% = X%: YY1% = Y% + B% XX2% = X%: YY2% = Y% - B% XY1% = X% + B%: YX1% = Y% XY2% = X% - B%: YX2% = Y% DO WHILE B% >= A% CALL XPSET(XX1%, YY1%, Culler%) CALL XPSET(XX1%, YY2%, Culler%) CALL XPSET(XX2%, YY1%, Culler%) CALL XPSET(XX2%, YY2%, Culler%) CALL XPSET(XY1%, YX1%, Culler%) CALL XPSET(XY1%, YX2%, Culler%) CALL XPSET(XY2%, YX1%, Culler%) CALL XPSET(XY2%, YX2%, Culler%) IF D% + B% > 0 THEN B% = B% - 1 D% = D% - (B% * 2) + 1 YY1% = YY1% - 1: YY2% = YY2% + 1 XY1% = XY1% - 1: XY2% = XY2% + 1 END IF IF A% > D% THEN A% = A% + 1 D% = D% + (A% * 2) + 1 XX1% = XX1% + 1: XX2% = XX2% - 1 YX1% = YX1% + 1: YX2% = YX2% - 1 END IF LOOP END SUB SUB DrawLine (X1%, Y1%, X2%, Y2%, Culler%) 'a routine to draw lines using only integers and integer math 'an implementation of Bresenham's algorithm 'by Douglas H. Lusher, 05-08-1996 A% = X2% - X1% B% = Y2% - Y1% DX2% = 1: DY2% = 1 IF A% < 0 THEN A% = -A%: DX2% = -1 IF B% < 0 THEN B% = -B%: DY2% = -1 DX1% = DX2%: DY1% = 0 IF A% < B% THEN SWAP A%, B%: DX1% = 0: DY1% = DY2% I1% = B% * 2 D% = I1% - A% I2% = D% - A% X% = X1%: Y% = Y1% FOR I% = 0 TO A% CALL XPSET(X%, Y%, Culler%) IF D% < 0 THEN X% = X% + DX1% Y% = Y% + DY1% D% = D% + I1% ELSE X% = X% + DX2% Y% = Y% + DY2% D% = D% + I2% END IF NEXT END SUB SUB InitCharSet (Segment%, Offset%, CharHeight%) 'this code initializes the data used by the routine XPRINT to ' define the characters 'Segment% and Offset% are the location in memory of the bitmaps ' of the characters. 'CharHeight% is the height of the characters in pixels. ' CharHeight% may be in the range 8 - 16 'by Douglas H. Lusher - Aug 2, 1996 SHARED HiNibble%(), LoNibble%(), CharHgt% REDIM HiNibble%(4096) REDIM LoNibble%(4096) DIM Mask%(15) Mask%(0) = 0: Mask%(1) = 8: Mask%(2) = 4 Mask%(3) = 12: Mask%(4) = 2: Mask%(5) = 10 Mask%(6) = 6: Mask%(7) = 14: Mask%(8) = 1 Mask%(9) = 9: Mask%(10) = 5: Mask%(11) = 13 Mask%(12) = 3: Mask%(13) = 11: Mask%(14) = 7 Mask%(15) = 15 DEF SEG = Segment% FOR Char% = 0 TO 255 CharPtr% = Char% * 16 FOR Ln% = 0 TO CharHeight% - 1 BitPattern% = PEEK(Offset% + (Char% * CharHeight%) + Ln%) HiNibble%(CharPtr% + Ln%) = Mask%(BitPattern% \ 16) LoNibble%(CharPtr% + Ln%) = Mask%(BitPattern% AND 15) NEXT NEXT CharHgt% = CharHeight% END SUB SUB Screen320x240 'this code puts the VGA in 320x240x256 mode, and initializes the ' character set and the bit masks needed in this mode. 'by Douglas H. Lusher - Aug 2, 1996 'begin with standard 320x200x256 mode SCREEN 13 'change the CPU addressing of video memory to linear (not odd/even, 'chain, or chain 4) to allow access to all 256K of display memory. 'using the Sequence Controller, select the Memory Mode register OUT &H3C4, &H4 '"AND NOT &H8" turns off chain 4, "OR &H4" turns off odd/even OUT &H3C5, (INP(&H3C5) AND NOT &H8) OR &H4 'using the Graphics Controller, select the Graphics Mode register OUT &H3CE, &H5 'turn off odd/even OUT &H3CF, INP(&H3CF) AND NOT &H10 'using the Graphics Controller, select the Miscellaneous register OUT &H3CE, &H6 'turn off chain OUT &H3CF, INP(&H3CF) AND NOT &H2 'clear all of video memory (setting mode 13 only cleared 64K) 'Do this before switching the CRT out of mode 13 so that garbage 'does not appear on the screen when the switch is made. 'using the Sequence Controller, select the Map Mask register 'and set it to write to all four bit-planes simultaneously OUT &H3C4, &H2: OUT &H3C5, &HF DEF SEG = &HA000 FOR Ptr% = 0 TO 31999: POKE Ptr%, 0: NEXT DEF SEG = &HA7D0 FOR Ptr% = 0 TO 31999: POKE Ptr%, 0: NEXT DEF SEG = &HAFA0 FOR Ptr% = 0 TO 1535: POKE Ptr%, 0: NEXT 'to reprogram the CRT controller 'remove write protect from the registers OUT &H3D4, &H11: OUT &H3D5, INP(&H3D5) AND &H7F OUT &H3D4, &H6: OUT &H3D5, &HD 'vertical total OUT &H3D4, &H7: OUT &H3D5, &H3E 'overflow 'select the Maximum Scan Line register, set it for double scan OUT &H3D4, &H9: OUT &H3D5, INP(&H3D5) OR &H1 OUT &H3D4, &H10: OUT &H3D5, &HEA 'vertical sync start OUT &H3D4, &H11: OUT &H3D5, &HAC 'vertical sync end OUT &H3D4, &H12: OUT &H3D5, &HDF 'vertical displayed 'select the Underline Location register, and turn off dword mode OUT &H3D4, &H14: OUT &H3D5, INP(&H3D5) AND NOT &H40 OUT &H3D4, &H15: OUT &H3D5, &HE7 'vertical blank start OUT &H3D4, &H16: OUT &H3D5, &H6 'vertical blank end 'select the Mode Control register, turn on the byte mode bit OUT &H3D4, &H17: OUT &H3D5, INP(&H3D5) OR &H40 SHARED ScrnWid%, ScrnHgt%, VScrnWid%, VScrnHgt% ScrnWid% = 320: ScrnHgt% = 240: VScrnWid% = 320: VScrnHgt% = 240 SHARED BytesPerLine%, APage% BytesPerLine% = 80: APage% = &HA000 SHARED BitMask%() BitMask%(0) = 1: BitMask%(1) = 2: BitMask%(2) = 4: BitMask%(3) = 8 DIM Reg AS RegTypeX Reg.AX = &H1130 Reg.BX = &H600 CALL INTERRUPTX(&H10, Reg, Reg) CALL InitCharSet(Reg.ES, Reg.BP, 16) END SUB SUB XPAN 'this routine allows the user to pan around a virtual screen ' in 320x240x256 mode 'by Douglas H. Lusher, Oct 8, 1996 SHARED ScrnWid%, ScrnHgt%, VScrnWid%, VScrnHgt%, BytesPerLine% HPanLimit% = (VScrnWid% - ScrnWid%) * 2 VPanLimit% = VScrnHgt% - ScrnHgt% X% = 0: Y% = 0 DO DO WHILE LEN(INKEY$): LOOP DO: KP$ = INKEY$: LOOP UNTIL LEN(KP$) KP% = ASC(KP$): IF KP% = 0 THEN KP% = -ASC(MID$(KP$, 2)) SELECT CASE KP% CASE 27 EXIT DO CASE 52, -75 'Four, LArrow IF X% > 0 THEN X% = X% - 2 ELSE BEEP CASE 54, -77 'Six, RArrow IF X% < HPanLimit% THEN X% = X% + 2 ELSE BEEP CASE 56, -72 'Eight, UpArrow IF Y% > 0 THEN Y% = Y% - 1 ELSE BEEP CASE 50, -80 'Two, DnArrow IF Y% < VPanLimit% THEN Y% = Y% + 1 ELSE BEEP END SELECT Ptr& = (BytesPerLine% * CLNG(Y%)) + (X% \ 8) WAIT &H3DA, 8, 8 DO: LOOP WHILE (INP(&H3DA) AND 8) = 0 OUT &H3C0, &H33: OUT &H3C0, X% MOD 8 OUT &H3D4, &HD: OUT &H3D5, Ptr& MOD 256 OUT &H3D4, &HC: OUT &H3D5, Ptr& \ 256 LOOP END SUB SUB XPRINT (X%, Y%, Text$, Culler%) 'this is code to print text in 320x240x256 mode 'X% and Y% are the screen coordinates where the upper left corner ' of the first character in the string should appear 'Text$ is the string to be printed 'Culler% is the color in which the characters will be printed ' Culler% must be in the range 0 - 255 'by Douglas H. Lusher - Aug 2, 1996 SHARED BytesPerLine%, APage% SHARED HiNibble%(), LoNibble%(), CharHgt% DEF SEG = APage% Offset& = (BytesPerLine% * CLNG(Y%)) + (X% \ 4) OUT &H3C4, 2 FOR Char% = 1 TO LEN(Text$) VideoPtr& = Offset& Ptr% = ASC(MID$(Text$, Char%, 1)) * 16 FOR Ln% = Ptr% TO Ptr% + CharHgt% - 1 OUT &H3C5, HiNibble%(Ln%): POKE VideoPtr&, Culler% OUT &H3C5, LoNibble%(Ln%): POKE VideoPtr& + 1, Culler% VideoPtr& = VideoPtr& + BytesPerLine% NEXT Offset& = Offset& + 2 NEXT END SUB SUB XPSET (X%, Y%, Culler%) 'this is code to write a pixel in 320x240x256 mode 'by Douglas H. Lusher - June 15, 1996 'X% and Y% are the coordinates of the pixel 'Culler% is the color of the pixel ' Culler% must be in the range 0 - 255 SHARED VScrnWid%, VScrnHgt%, BytesPerLine%, APage%, BitMask%() IF X% < 0 THEN EXIT SUB IF X% >= VScrnWid% THEN EXIT SUB IF Y% < 0 THEN EXIT SUB IF Y% >= VScrnHgt% THEN EXIT SUB OUT &H3C4, 2: OUT &H3C5, BitMask%(X% AND 3) DEF SEG = APage% POKE (BytesPerLine% * CLNG(Y%)) + (X% \ 4), Culler% END SUB