02

Enter Mode X

One of my best BBS finds was Mode X. Aside from the library being genuinely useful, it included demo code that I spent ages digging through to try to understand. The first demo below is their demo out of the box, and the second is my own stripped down version. Many of the later entries continue to use this library.
the 256 DAC registers. Two 61-entry banks are set up, at 50 and 150. Only the first is ever on screen.

TEST5.PAS: The ModeX Demo

This is from MODEX104, release 1.04 of 14 March 1993, a library of Mode X assembly routines by Matt Pritchard, placed by him in the public domain. Its README credits two more people: Michael Abrash "He told us all how to do it in the first place" and Scott Wyatt, "He ported the Main Demo code to Turbo Pascal." TEST5.PAS is Scott Wyatt's file, and MODEX2.OBJ in the archive is Pritchard's MODEX.OBJ renamed (5,208 bytes, matching the packing list to the byte). Abrash → Pritchard → Wyatt. It shows off everything the library could do: a 360×240 virtual page larger than the 320×200 display, three pages, hardware panning, page flipping, transparent sprite blits, and palette cycling. The labels down the left are a list of its own entry points.

The panning is the part worth watching. Nothing moves. Set_Window rewrites the CRTC start address and the card begins reading video memory somewhere else; no pixels are copied, no frame is redrawn. Tick the box to show the whole page and you can watch the window slide over a picture that is standing perfectly still. Sixty-four sprites bounce around on top, drawn onto whichever page is about to be displayed and erased from the other one by copying 16×16 boxes back from page 2, the clean master. That is why there are three pages and not two.

JTEST.PAS: My Study Cut

This is Page_Demo with the sixteen label lines, the sixty-four sprites and the keyboard handler deleted. What is left is the fan, the panning and the chaser, and it runs unchanged. This is where entry 08's P10, P14 and P15 come from. The fan - DRAW_LINE(ScreenX div 2 - 1, ScreenY div 4, X, ScreenY-1, c+50) with the index walking a triangle 0..60..0 - and the four-line chaser over two palette banks at 50 and 150 are lifted into my ALL.PAS fifteen months later, verbatim. More details on what was then changed are in the later entry.

Two fossils left behind. The second palette bank at 150..210 is set up and written every single frame, and nothing on screen is ever drawn in it, here or in TEST5. And For c := 1 to 4 DO Set_Dac_Register(19+c, 63-(c*10), 0, 0) is still there, setting four shades of red for registers 20 to 23, which are the colors baked into the four sprite bitmaps I deleted. Dead palette entries for sprites that no longer exist. One more seam: ERROR_OUT writes int 10h in hex while the main block ends with my int 16 in decimal. Two hands, one file.

Where this entry sits in the archive

The unit goes into the compiler the day before JTEST.BAK. JMODEX.PAS is saved 1995-06-09 17:46 and TURBO.TPL is rebuilt at 17:51, five minutes later, with JMODEX installed into the standard unit library beside Borland's own. From that moment uses jmodex compiles with no paths set, and every Mode X program in the rest of the archive is one line away from building.

JTEST.PAS is re-saved three months after that (original timestamp pulled from the .BAK), at 1995-09-21 17:59, the opening file of the twenty-one hours that also produced MYDEMO, BOX2 and the PATTERN1 → JUAN → DOODLE sequence.

TEST5.PAS

1995-05-16 19:23 · 15,873 bytes · Scott Wyatt's Turbo Pascal port of Pritchard's demo, the file everything here descends from.

{                      ModeX Turbo Pascal Demo Program                       }
{                  Converted to Turbo Pascal by Scott Wyatt                  }
{          Original program written in QuickBasic by Matt Prichard           }
{                       Released to the Public Domain                        }
{                                                                            }
{          Thanks to Matt Prichard for his *EXCELLENT* ModeX Library         }
{		   Additional Comments by Matt Pritchard							 }

Uses Crt;

{$L modex2.obj}		{ This file is the external ModeX Library .OBJ }
{$F+}

	{ Mode Setting Routines }

Function SET_VGA_MODEX (Mode,MaxXpos,MaxYpos,Pages : integer) : integer; external;
Function SET_MODEX (Mode:integer) : Integer; external;

	{ Graphics Primitives }

Procedure CLEAR_VGA_SCREEN (Color:integer); external;
Procedure SET_POINT (Xpos,Ypos,Color : integer); external;
Function READ_POINT (Xpos,Ypos:integer) : integer; external;
Procedure FILL_BLOCK (Xpos1,Ypos1,Xpos2,Ypos2,Color:integer); external;
Procedure DRAW_LINE (Xpos1,Ypos1,Xpos2,Ypos2,Color:integer); external;

	{ VGA DAC Routines }

Procedure SET_DAC_REGISTER (RegNo,Red,Green,Blue:integer); external;
Procedure GET_DAC_REGISTER (RegNo,Red,Green,Blue:integer); external;

	{ Page and Window Control Routines }

Procedure SET_ACTIVE_PAGE (PageNo:integer); external;
Function GET_ACTIVE_PAGE : integer; external;
Procedure SET_DISPLAY_PAGE (PageNo:integer); external;
Function GET_DISPLAY_PAGE : integer; external;
Procedure SET_WINDOW (DisplayPage,XOffset,YOffset : integer); external;
Function GET_X_OFFSET : integer; external;
Function GET_Y_OFFSET : integer; external;
Procedure SYNC_DISPLAY; external;

	{ Text Display Routines }

Procedure GPRINTC (CharNum,Xpos,Ypos,ColorF,ColorB:integer); external;
Procedure TGPRINTC ( CharNum,Xpos,Ypos,ColorF : integer); external;
Procedure PRINT_STR (Var Text;MaxLen,Xpos,Ypos,ColorF,ColorB:integer); external;
Procedure TPRINT_STR (Var Text;MaxLen,Xpos,Ypos,ColorF:integer); external;
Procedure SET_DISPLAY_FONT (Var FontData;FontNumber:integer); external;

	{ Sprite and VGA memory -> Vga memory Copy Routines }

Procedure DRAW_BITMAP (Var Image;Xpos,Ypos,Width,Height:integer); external;
Procedure TDRAW_BITMAP (Var Image;Xpos,Ypos,Width,Height:integer); external;
Procedure COPY_PAGE (SourcePage,DestPage:integer); external;
Procedure COPY_BITMAP (SourcePage,X1,Y1,X2,Y2,DestPage,DestX1,DestY1:integer); external;

{$F-}


TYPE Sprite = Record
	Xpos : INTEGER;
	Ypos : INTEGER;
	XDir : INTEGER;
	YDir : INTEGER;
	Shape : INTEGER;
	LastX : INTEGER;
	LastY : INTEGER;
     END;


CONST MaxShapes = 32;
      Circle_16 : Array[1..16,1..16] of byte =
      ((  0,  0,  0,  0,  0,  0, 20, 20, 20, 20,  0,  0,  0,  0,  0,  0),
       (  0,  0,  0,  0, 20, 20, 20, 20, 20, 20, 20, 20,  0,  0,  0,  0),
       (  0,  0,  0, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20,  0,  0,  0),
       (  0,  0, 20, 20, 20, 20,  0,  0,  0,  0, 20, 20, 20, 20,  0,  0),
       (  0, 20, 20, 20, 20,  0,  0,  0,  0,  0,  0, 20, 20, 20, 20,  0),
       (  0, 20, 20, 20,  0,  0,  0,  0,  0,  0,  0,  0, 20, 20, 20,  0),
       ( 20, 20, 20,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0, 20, 20, 20),
       ( 20, 20, 20,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0, 20, 20, 20),
       ( 20, 20, 20,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0, 20, 20, 20),
       ( 20, 20, 20,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0, 20, 20, 20),
       (  0, 20, 20, 20,  0,  0,  0,  0,  0,  0,  0,  0, 20, 20, 20,  0),
       (  0, 20, 20, 20, 20,  0,  0,  0,  0,  0,  0, 20, 20, 20, 20,  0),
       (  0,  0, 20, 20, 20, 20,  0,  0,  0,  0, 20, 20, 20, 20,  0,  0),
       (  0,  0,  0, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20,  0,  0,  0),
       (  0,  0,  0,  0, 20, 20, 20, 20, 20, 20, 20, 20,  0,  0,  0,  0),
       (  0,  0,  0,  0,  0,  0, 20, 20, 20, 20,  0,  0,  0,  0,  0,  0));
      Square_16 : Array[1..16,1..16] of byte =
      (( 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21),
       ( 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21),
       ( 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21),
       ( 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21),
       ( 21, 21, 21, 21,  0,  0,  0,  0,  0,  0,  0,  0, 21, 21, 21, 21),
       ( 21, 21, 21, 21,  0,  0,  0,  0,  0,  0,  0,  0, 21, 21, 21, 21),
       ( 21, 21, 21, 21,  0,  0,  0,  0,  0,  0,  0,  0, 21, 21, 21, 21),
       ( 21, 21, 21, 21,  0,  0,  0,  0,  0,  0,  0,  0, 21, 21, 21, 21),
       ( 21, 21, 21, 21,  0,  0,  0,  0,  0,  0,  0,  0, 21, 21, 21, 21),
       ( 21, 21, 21, 21,  0,  0,  0,  0,  0,  0,  0,  0, 21, 21, 21, 21),
       ( 21, 21, 21, 21,  0,  0,  0,  0,  0,  0,  0,  0, 21, 21, 21, 21),
       ( 21, 21, 21, 21,  0,  0,  0,  0,  0,  0,  0,  0, 21, 21, 21, 21),
       ( 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21),
       ( 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21),
       ( 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21),
       ( 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21));
       Diamond : Array[1..8,1..8] of byte =
      ((  0,  0,  0, 22, 22,  0,  0,  0),
       (  0,  0, 22, 22, 22, 22,  0,  0),
       (  0, 22, 22,  0,  0, 22, 22,  0),
       ( 22, 22,  0,  0,  0,  0, 22, 22),
       ( 22, 22,  0,  0,  0,  0, 22, 22),
       (  0, 22, 22,  0,  0, 22, 22,  0),
       (  0,  0, 22, 22, 22, 22,  0,  0),
       (  0,  0,  0, 22, 22,  0,  0,  0));
       Rectangle : Array[1..8,1..3] of byte =
      (( 23, 23, 23),
       ( 23, 23, 23),
       ( 23, 23, 23),
       ( 23, 23, 23),
       ( 23, 23, 23),
       ( 23, 23, 23),
       ( 23, 23, 23),
       ( 23, 23, 23));

	   { Global Variables ? }

Var
  XCenter,X1,Y1,X2,Y2,Z,Colr,XChars,YChars,X,Y,N,Gap : Integer;
  s : string;
  s1 : Array[1..35] of Char;
  ch : Char;
  obj : Array[1..64] of Sprite;
  ScreenX,ScreenY : Integer;
  c, dc, SpriteX, SpriteY, CurrentPage, LastPage : Integer;
  SetColor, SDir, PrevColor, PDir : Byte;
  XView, YView : Integer;
  XView_Change, YView_Change : Integer;
  Right : Boolean;
  Number_Of_Shapes : Byte;


	{ Error Handler - Returns to Text Mode & Displays Error }

Procedure ERROR_OUT(s : string);
  Begin
    asm
      mov ah,0
      mov al,3
      int 10h
    end;
  WriteLn(s);
  Halt(0);
END;

	{ Routine to Print a PASCAL string using Print_Str }

Procedure Print_Text(s : string; X,Y,BColor,FColor : integer);
Var
  s1 : Array[1..135] of Char;
  i : byte;
Begin
  For i := 1 to Length(s) DO
    s1[i] := s[i];
  Print_Str(s1,Length(s),X,Y,BColor,FColor);
End;

	{ Routine to Transparently Print a PASCAL string using TPrint_Str }

Procedure TPrint_Text(s : string; X,Y,Color : integer);
Var
  s1 : Array[1..135] of Char;
  i : byte;
Begin
  For i := 1 to Length(s) DO
    s1[i] := s[i];
  TPrint_Str(s1,Length(s),X,Y,Color);
End;

	{ Routines to show test patterns for a given mode }

Procedure Demo_Res(Mode, Xmax, Ymax : integer);
Begin

  Str(mode,s);
  If Set_ModeX(Mode) = 0 Then
    Error_Out('Unable to SET_MODEX '+s);
  Clear_VGA_Screen(0);

  XCenter := Xmax div 2;
  X1 := 10;
  Y1 := 10;
  X2 := Xmax - 1;
  Y2 := Ymax - 1;

  FOR Z := 0 TO 3 DO
    Begin
      Colr := 31 - Z * 2;
      Draw_Line(X1 + Z, Y1 + Z, X2 - Z, Y1 + Z, Colr);
      Draw_Line(X1 + Z, Y1 + Z, X1 + Z, Y2 - Z, Colr);
      Draw_Line(X1 + Z, Y2 - Z, X2 - Z, Y2 - Z, Colr);
      Draw_Line(X2 - Z, Y1 + Z, X2 - Z, Y2 - Z, Colr);
    End;

  XChars := Xmax div 10;
  YChars := Ymax div 10;

  FOR X := 0 TO XChars - 1 DO
    Begin
      TGPRINTC(48 + ((X + 1) MOD 10), X * 10 + 1, 1, 9 + ((X div 8) MOD 7));
      DRAW_LINE(X * 10 + 9, 0, X * 10 + 9, 3, 15);
    End;
  FOR Y := 0 TO YChars - 1 DO
    Begin
      TGPRINTC(48 + ((Y + 1) MOD 10), 1, Y * 10 + 1, 9 + ((Y div 10) MOD 7));
      DRAW_LINE(0, Y * 10 + 9, 3, Y * 10 + 9, 15);
    End;

   { Test Line Drawing }

  FOR X := 0 TO 63 DO
    Begin
      N := 15 + ((X * 3) div 4);
      SET_DAC_REGISTER(64 + X, N, N, N);
      SET_DAC_REGISTER(128 + X, 0, N, N);
      DRAW_LINE(103 - X, 60, 40 + X, 123, 64 + X);
      DRAW_LINE(40, 60 + X, 103, 123 - X, 128 + X);
    End;
  s := 'Line Test';
  PRINT_Text(s,37,130,1,0);

  { Test Block Fills }

  Y := 60;
  Gap := 0;
  FOR X := 0 TO 9 DO
    Begin
      FILL_BLOCK(120, Y, 120 + X, Y + Gap, 64 + X);
      FILL_BLOCK(140 - (15 - X), Y, 150 + X, Y + Gap, 230 + X);
      FILL_BLOCK(170 - (15 - X), Y, 170, Y + Gap, 128 + X);
      Y := Y + Gap + 2;
      Gap := Gap + 1;
    End;
  s := 'Fill Test';
  Print_Text(s,110, 46, 2,0);

  { Test Pixel Write and Read }

  FOR X := 190 TO 250 DO
    FOR Y := 60 TO 122 DO
      SET_POINT( X, Y, X + Y + X + Y);

  s := 'Pixel Test';
  Print_Text(s,182, 130, 3,0);

  FOR X := 190 TO 250 DO
    FOR Y := 60 TO 122 DO
      IF READ_POINT(X, Y) <> ((X + Y + X + Y) AND 255) THEN
        WriteLn('READ_PIXEL Failure');

	{ Display rest of screen }

  s := ' This is a MODE X demo ';
  Print_Text(s,XCenter - (Length(s) * 4), 20, 3, 1);
  s := 'Screen Resolution is     by    ';
  X := XCenter - (Length(s) * 4);
  Print_Text(s,X,30,4,0);
  Str(XMax,s);
  Print_Text(s, X + 8 * 21, 30, 8, 0);
  Str(YMax,s);
  Print_Text(s, X + 8 * 28, 30, 15, 0);

  FOR X := 0 TO 15 DO
    Begin
      SET_DAC_REGISTER( 230 + X, 63 - X * 4, 0, 15 + X * 3);
      DRAW_LINE(30 + X, Ymax - 6 - X, Xmax - 20 - X, Ymax - 6 - X, 230 + X);
    End;
  s := 'Press <ANY KEY> to Continue';
  For x := 1 to length(s) DO
    s1[x] := s[x];
  TPrint_Str(s1, length(s), XCenter - (26 * 4), Ymax - 18, 5);

  Ch := ReadKey;
  IF Ch = #27 Then
    Error_Out('Abort');

End;


	{ Initialize Sprites for Sprite Demo }

Procedure Init_Sprites;
Var i : byte;
Begin
  For i := 1 to 64 DO
    Begin
      Obj[i].XPos := Random(300)+10;
      Obj[i].YPos := Random(200)+20;
      Obj[i].XDir := Random(10)-5;
      Obj[i].YDir := Random(10)-5;
      If (Obj[i].XDir = 0) AND (Obj[i].YDir = 0) Then
        Begin
          Obj[i].XDir := Random(5) + 1;
          Obj[i].YDir := Random(5) + 1;
        End;
      Obj[i].Shape := Random(4)+1;
      Obj[i].LastX := obj[i].XPos;
      Obj[i].LastY := obj[i].YPos;
    End;
End;

Procedure Set_Sprites(number : byte);
Var i : Byte;
Begin
  For i := 1 to number DO
    Begin
      obj[i].LastX := obj[i].XPos;
      obj[i].LastY := obj[i].YPos;
      obj[i].XPos := obj[i].XPos + obj[i].XDir;
      obj[i].YPos := obj[i].YPos + obj[i].YDir;
      If (obj[i].XPos > 335) OR (obj[i].XPos < 5 ) Then
        obj[i].XDir := -(obj[i].XDir);
      If (obj[i].YPos > 220) OR (obj[i].YPos < 5) Then
        obj[i].YDir := -(obj[i].YDir);
    End;
  For i := 1 to number DO
    Case obj[i].Shape of
      1 : TDraw_Bitmap(Circle_16,obj[i].XPos,obj[i].YPos,16,16);
      2 : TDraw_Bitmap(Square_16,obj[i].XPos,obj[i].YPos,16,16);
      3 : TDraw_Bitmap(Diamond,obj[i].XPos,obj[i].YPos,8,8);
      4 : TDraw_Bitmap(Rectangle,obj[i].XPos,obj[i].YPos,3,8);
    End;
End;

Procedure Remove_Sprites(p,number : byte);
Var i : byte;
Begin
  For i := 1 to number DO
    Copy_Bitmap(2,obj[i].LastX,obj[i].LastY,obj[i].LastX+16,obj[i].LastY+16,p,Obj[i].LastX,Obj[i].LastY);
End;

Procedure Page_Demo;
Begin
  Number_Of_Shapes := 64;
  XView_Change := 1;
  YView_Change := 1;
  XView := 1;
  YView := 1;
  Right := TRUE;
  ScreenX := 360;
  ScreenY := 240;
  PrevColor := 0;
  SetColor := 3;
  SDir := 1;
  PDir := 1;
  Str(0,s);

  IF SET_VGA_MODEX(0, ScreenX, ScreenY, 3) = 0 THEN
    ERROR_OUT('Unable to SET_VGA_MODEX' + S);

  SET_ACTIVE_PAGE(0);
  CLEAR_VGA_SCREEN(0);
  PRINT_TEXT('This is a Test of the Following Functions:', 10, 9, 15, 0);
  DRAW_LINE( 10, 18, 350, 18, 4);
  Print_Text('SET_ACTIVE_PAGE', 10, 20, 1, 0);
  Print_Text('SET_DISPLAY_PAGE', 10, 30, 3,0);
  Print_Text('SET_DAC_REGISTER', 10, 40, 3, 0);
  Print_Text('CLEAR_VGA_SCREEN', 10, 50, 13, 0);
  Print_Text('TDRAW_BITMAP', 10, 60, 14, 0);
  Print_Text('COPY_PAGE', 10, 70, 3, 0);
  Print_Text('COPY_BITMAP', 10, 80, 13, 0);
  Print_Text('GPRINTC', 10, 90, 1, 0);
  Print_Text('TGPRINTC', 10, 100, 3, 0);
  Print_Text('SYNC_DISPLAY', 10, 110, 3, 0);
  Print_Text('SET_WINDOW', 10, 120, 14, 0);
  Print_Text('VIRTUAL SCREEN SIZES', 190, 20, 1, 0);
  Print_Text('    SMOOTH SCROLLING', 190, 30, 3, 0);
  Print_Text('    SPRITE ANIMATION', 190, 40, 13, 0);
  Print_Text('       PAGE FLIPPING', 190, 50, 3, 0);
  Print_Text('       COLOR CYCLING', 190, 60, 14, 0);

  FOR X := 0 TO 60 DO
    Begin
      SET_DAC_REGISTER( 50 + X, 3 + X, 0, 60 - X);
      SET_DAC_REGISTER( 150 + X, 3 + X, 0, 60 - X);
    End;

  c := 0;
  DC := 1;
  FOR X := 0 TO ScreenX div 2 DO
    Begin
      DRAW_LINE( ScreenX div 2 - 1, ScreenY div 4, X, ScreenY - 1, c + 50);
      DRAW_LINE( ScreenX div 2, ScreenY div 4, ScreenX - X - 1, ScreenY - 1, c + 50);
      c := c + DC;
      IF (c = 0) OR (c = 60) THEN DC := -DC;
    End;

  TPrint_Text('Press <ESC> to Continue', 82, 190, 15);
  TPrint_Text('<+> = Fewer Shapes  <-> = More Shapes', 32, 204, 12);
  COPY_PAGE( 0, 1);
  COPY_PAGE( 0, 2);

  Ch := #0;
  CurrentPage := 1;
  LastPage := 0;
  Set_Sprites(Number_Of_Shapes);
  For c := 1 to 4 DO
    Set_Dac_Register(19+c,63-(c*10),0,0);

  While Ch <> #27 DO
    Begin
      Set_Active_Page(currentpage);
      Set_Sprites(Number_Of_Shapes);
      If Right Then
        Begin
          XView := XView + XView_Change;
          If (XView > 38) OR (XView < 2) Then
            Begin
              XView_Change := -(XView_Change);
              Right := FALSE;
            End;
        End
      Else
        Begin
          YView := YView + YView_Change;
          If (YView > 38) OR (YView < 2) Then
            Begin
              YView_Change := -(YView_Change);
              Right := TRUE;
            End;
        End;

      Set_Window(currentpage,XView,YView);
      Set_Display_Page(currentpage);
      Set_Dac_Register(50 + PrevColor, 3 + PrevColor, 0, 60 - PrevColor);
      Set_Dac_Register(50 + SetColor, SetColor, 10, 63 - SetColor);
      Set_Dac_Register(150 + PrevColor, 3 + PrevColor, 0, 60 - PrevColor);
      Set_Dac_Register(150 + SetColor, 63, 63, SetColor);
      SetColor := SetColor + SDir;
      IF (SetColor = 60) OR (SetColor = 0) THEN SDir := -SDir;
      PrevColor := PrevColor + PDir;
      IF (PrevColor = 60) OR (PrevColor = 0) THEN PDir := -PDir;
      Remove_Sprites(lastpage,Number_Of_Shapes);

      If Keypressed Then
        Begin
          Ch := ReadKey;
          Case Ch of
            '-' : If Number_Of_Shapes > 1 Then
                    Begin
                      c := Number_Of_Shapes;
                      Copy_Bitmap(2,obj[c].XPos,obj[c].YPos,obj[c].XPos+16,obj[c].YPos+16,
                         currentpage,obj[c].XPos,obj[c].YPos);
                      Dec(Number_Of_Shapes);
                    End;
            '+' : If Number_Of_Shapes < 64 Then Inc(Number_Of_Shapes);
          End;
        End;
      lastpage := (lastpage+1) MOD 2;
      currentpage := (currentpage+1) MOD 2;
    End;
END;

	{ MAIN ROUTINE - Run Through Demos and Exit }

Begin

  Randomize;
  Init_Sprites;

  Demo_Res(0, 320, 200);
  Demo_Res(1, 320, 400);
  Demo_Res(2, 360, 200);
  Demo_Res(3, 360, 400);
  Demo_Res(4, 320, 240);
  Demo_Res(5, 320, 480);
  Demo_Res(6, 360, 240);
  Demo_Res(7, 360, 480);
  Page_Demo;

  asm
    mov ah,0
    mov al,3
    int 10h
  end;
  WriteLn('THIS MODE X DEMO IS FINISHED');

END.
JTEST.PAS

1995-09-21 17:59 · 2,771 bytes · My cut-down.

Uses Crt,jmodex;

Var
  XCenter,X1,Y1,X2,Y2,Z,Colr,XChars,YChars,X,Y,N,Gap : Integer;
  s : string;
  s1 : Array[1..35] of Char;
  ch : Char;
  ScreenX,ScreenY : Integer;
  c, dc,CurrentPage, LastPage : Integer;
  SetColor, SDir, PrevColor, PDir : Byte;
  XView, YView : Integer;
  XView_Change, YView_Change : Integer;
  Right : Boolean;

Procedure ERROR_OUT(s:string);Begin asm mov ah,0;mov al,3;int 10h;end;
WriteLn(s);Halt(0);END;

Procedure Page_Demo;
Begin
  XView_Change := 1;
  YView_Change := 1;
  XView := 1;
  YView := 1;
  Right := TRUE;
  ScreenX := 360;
  ScreenY := 240;
  PrevColor := 0;
  SetColor := 3;
  SDir := 1;
  PDir := 1;
  Str(0,s);

  IF SET_VGA_MODEX(0, ScreenX, ScreenY, 3) = 0 THEN
    ERROR_OUT('Unable to SET_VGA_MODEX' + S);

  SET_ACTIVE_PAGE(0);
  CLEAR_VGA_SCREEN(0);
  
  FOR X := 0 TO 60 DO
    Begin
      SET_DAC_REGISTER( 50 + X, 3 + X, 0, 60 - X);
      SET_DAC_REGISTER( 150 + X, 3 + X, 0, 60 - X);
    End;

  c := 0;
  DC := 1;
  FOR X := 0 TO ScreenX div 2 DO
    Begin
      DRAW_LINE( ScreenX div 2 - 1, ScreenY div 4, X, ScreenY - 1, c + 50);
      DRAW_LINE( ScreenX div 2, ScreenY div 4, ScreenX - X - 1, ScreenY - 1, c + 50);
      c := c + DC;
      IF (c = 0) OR (c = 60) THEN DC := -DC;
    End;

  COPY_PAGE( 0, 1);
  COPY_PAGE( 0, 2);

  Ch := #0;
  CurrentPage := 1;
  LastPage := 0;
  For c := 1 to 4 DO
    Set_Dac_Register(19+c,63-(c*10),0,0);

  While Ch <> #27 DO
    Begin
      Set_Active_Page(currentpage);
      If Right Then
        Begin
          XView := XView + XView_Change;
          If (XView > 38) OR (XView < 2) Then
            Begin
              XView_Change := -(XView_Change);
              Right := FALSE;
            End;
        End
      Else
        Begin
          YView := YView + YView_Change;
          If (YView > 38) OR (YView < 2) Then
            Begin
              YView_Change := -(YView_Change);
              Right := TRUE;
            End;
        End;

      Set_Window(currentpage,XView,YView);
      Set_Display_Page(currentpage);
      Set_Dac_Register(50 + PrevColor, 3 + PrevColor, 0, 60 - PrevColor);
      Set_Dac_Register(50 + SetColor, SetColor, 10, 63 - SetColor);
      Set_Dac_Register(150 + PrevColor, 3 + PrevColor, 0, 60 - PrevColor);
      Set_Dac_Register(150 + SetColor, 63, 63, SetColor);
      SetColor := SetColor + SDir;
      IF (SetColor = 60) OR (SetColor = 0) THEN SDir := -SDir;
      PrevColor := PrevColor + PDir;
      IF (PrevColor = 60) OR (PrevColor = 0) THEN PDir := -PDir;

      lastpage := (lastpage+1) MOD 2;
      currentpage := (currentpage+1) MOD 2;
    End;
END;

Begin
  Page_Demo;
  asm mov ah,0;mov al,3;int 16;end;
END.
JMODEX.PAS

1995-06-09 17:46 · 3,189 bytes · Pascal interface to Pritchard's object file.

unit jmodex;

interface

Function SET_VGA_MODEX (Mode,MaxXpos,MaxYpos,Pages : integer) : integer;
Function SET_MODEX (Mode:integer) : Integer;
Procedure CLEAR_VGA_SCREEN (Color:integer);
Procedure SET_POINT (Xpos,Ypos,Color : integer);
Function READ_POINT (Xpos,Ypos:integer) : integer;
Procedure FILL_BLOCK (Xpos1,Ypos1,Xpos2,Ypos2,Color:integer);
Procedure DRAW_LINE (Xpos1,Ypos1,Xpos2,Ypos2,Color:integer);
Procedure SET_DAC_REGISTER (RegNo,Red,Green,Blue:integer);
Procedure GET_DAC_REGISTER (RegNo,Red,Green,Blue:integer);
Procedure SET_ACTIVE_PAGE (PageNo:integer);
Function GET_ACTIVE_PAGE : integer;
Procedure SET_DISPLAY_PAGE (PageNo:integer);
Function GET_DISPLAY_PAGE : integer;
Procedure SET_WINDOW (DisplayPage,XOffset,YOffset : integer);
Function GET_X_OFFSET : integer;
Function GET_Y_OFFSET : integer;
Procedure SYNC_DISPLAY;
Procedure GPRINTC (CharNum,Xpos,Ypos,ColorF,ColorB:integer);
Procedure TGPRINTC ( CharNum,Xpos,Ypos,ColorF : integer);
Procedure PRINT_STR (Var Text;MaxLen,Xpos,Ypos,ColorF,ColorB:integer);
Procedure TPRINT_STR (Var Text;MaxLen,Xpos,Ypos,ColorF:integer);
Procedure SET_DISPLAY_FONT (Var FontData;FontNumber:integer);
Procedure DRAW_BITMAP (Var Image;Xpos,Ypos,Width,Height:integer);
Procedure TDRAW_BITMAP (Var Image;Xpos,Ypos,Width,Height:integer);
Procedure COPY_PAGE (SourcePage,DestPage:integer);
Procedure COPY_BITMAP (SourcePage,X1,Y1,X2,Y2,DestPage,DestX1,DestY1:integer);

implementation

Function SET_VGA_MODEX (Mode,MaxXpos,MaxYpos,Pages : integer) : integer; external;
Function SET_MODEX (Mode:integer) : Integer; external;
Procedure CLEAR_VGA_SCREEN (Color:integer); external;
Procedure SET_POINT (Xpos,Ypos,Color : integer); external;
Function READ_POINT (Xpos,Ypos:integer) : integer; external;
Procedure FILL_BLOCK (Xpos1,Ypos1,Xpos2,Ypos2,Color:integer); external;
Procedure DRAW_LINE (Xpos1,Ypos1,Xpos2,Ypos2,Color:integer); external;
Procedure SET_DAC_REGISTER (RegNo,Red,Green,Blue:integer); external;
Procedure GET_DAC_REGISTER (RegNo,Red,Green,Blue:integer); external;
Procedure SET_ACTIVE_PAGE (PageNo:integer); external;
Function GET_ACTIVE_PAGE : integer; external;
Procedure SET_DISPLAY_PAGE (PageNo:integer); external;
Function GET_DISPLAY_PAGE : integer; external;
Procedure SET_WINDOW (DisplayPage,XOffset,YOffset : integer); external;
Function GET_X_OFFSET : integer; external;
Function GET_Y_OFFSET : integer; external;
Procedure SYNC_DISPLAY; external;
Procedure GPRINTC (CharNum,Xpos,Ypos,ColorF,ColorB:integer); external;
Procedure TGPRINTC ( CharNum,Xpos,Ypos,ColorF : integer); external;
Procedure PRINT_STR (Var Text;MaxLen,Xpos,Ypos,ColorF,ColorB:integer); external;
Procedure TPRINT_STR (Var Text;MaxLen,Xpos,Ypos,ColorF:integer); external;
Procedure SET_DISPLAY_FONT (Var FontData;FontNumber:integer); external;
Procedure DRAW_BITMAP (Var Image;Xpos,Ypos,Width,Height:integer); external;
Procedure TDRAW_BITMAP (Var Image;Xpos,Ypos,Width,Height:integer); external;
Procedure COPY_PAGE (SourcePage,DestPage:integer); external;
Procedure COPY_BITMAP (SourcePage,X1,Y1,X2,Y2,DestPage,DestX1,DestY1:integer); external;
{$L \turbo\obj\modex2.obj}

END.