/////////////////////////////////////////////////////////////////////////////
//                                                                         //
// TUTPROG10.CPP - VGA Trainer Program 10 (in Turbo C++ 3.0)               //
//                                                                         //
// "The VGA Trainer Program" was originally written by Denthor of          //
// Asphyxia.  It contained some nice pascal source and documentation.  But //
// then Snowman came along.  He saw disorder, he saw inefficiency, he      //
// saw PASCAL.  Denthor couldn't stop Snowman, so Snowman went on to       //
// convert tha pascal source to C++.  ...and the people were happy.        //
//                                                                         //
// Program Notes : This program presents the basics of Chain-4.            //
//                                                                         //
//                 Just for reference, this is the command line I use:     //
//                                                                         //
//                    tcc -mc -a -G -2 -O tut10.cpp                        //
//                                                                         //
//                 The way things are set up, there is no need to compile  //
//                 or link tut10.cpp and gfx2.cpp seperately.              //
//                                                                         //
// Author        : Grant Smith (Denthor) - [email protected]    //
// Translator    : Christopher G. Mann   - [email protected]         //
//                                                                         //
// Last Modified : February 1, 1995                                        //
//                                                                         //
/////////////////////////////////////////////////////////////////////////////

//               //
// INCLUDE FILES //
//               //

  #include <conio.h>
                           // clrscr(), getch(), kbhit()
  #include <iostream.h>
                           // cout
  #include <stdlib.h>
                           // rand()
  #include "gfx2.cpp"
                           // SetText(), WaitRetrace(), Pal::

//          //
// TYPEDEFS //
//          //

  // unsigned chars are sissy
  typedef unsigned char byte;
  typedef unsigned int  word;

//           //
// CONSTANTS //
//           //

  const byte BIT[897] = {
       0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,33,2,151,5,149,6,148,7,147,8,49,2,
       95,8,49,4,93,9,49,3,93,4,2,3,49,4,92,4,3,3,48,4,92,4,3,4,48,4,91,4,4,
       3,48,4,92,4,3,4,48,3,58,2,32,4,4,4,47,4,57,3,31,4,5,3,48,3,57,4,30,4,
       5,4,47,3,57,5,29,4,6,4,46,4,57,4,29,4,7,3,47,3,58,2,30,4,7,4,46,4,90,
       4,7,4,46,3,90,4,8,4,27,2,16,3,90,4,8,9,22,3,16,3,89,4,5,13,8,6,8,3,15,
       3,90,4,2,15,6,10,6,3,16,3,6,1,21,1,9,2,7,1,21,6,14,18,9,5,2,4,5,4,1,4,
       10,3,4,5,10,2,7,3,8,2,5,3,9,3,7,8,13,13,1,4,9,4,5,3,5,3,1,6,9,3,3,6,9,
       4,5,4,8,3,3,4,9,3,6,9,11,10,6,4,8,4,6,3,4,11,8,3,2,7,9,5,4,4,9,3,2,4,
       9,3,6,4,4,2,8,10,9,4,7,4,6,3,5,5,3,3,8,3,1,8,8,5,4,5,8,3,3,3,9,4,5,4,
       5,2,5,10,12,4,7,3,5,5,4,5,4,3,7,3,1,4,1,3,9,4,5,4,9,3,2,3,10,3,6,3,5,
       3,4,10,13,3,8,3,2,7,5,4,5,3,7,7,1,3,9,4,5,5,9,3,1,3,10,3,6,3,5,4,4,5,
       1,4,12,4,8,3,2,5,6,4,5,4,6,6,2,4,8,4,5,5,10,6,10,4,5,4,5,3,5,2,3,4,13,
       4,8,3,3,1,9,3,6,3,7,5,3,3,5,1,3,3,5,5,4,2,5,5,11,3,6,3,5,4,10,3,14,4,
       8,3,12,3,6,4,6,5,3,3,5,2,2,4,4,6,4,2,5,5,6,1,3,4,5,3,6,3,10,4,14,4,5,
       1,2,4,11,3,6,3,7,5,3,3,4,3,1,4,4,6,4,3,5,4,6,2,3,3,6,3,5,4,9,4,15,3,5,
       2,3,4,9,3,6,4,7,4,3,3,5,2,2,3,4,7,3,3,6,3,6,3,2,4,5,4,5,3,10,3,15,4,4,
       3,4,3,9,3,6,3,7,4,4,3,4,3,1,4,3,3,1,3,3,3,6,4,6,2,3,3,6,3,5,4,9,4,15,
       4,4,3,4,4,7,3,6,4,7,4,3,3,4,3,2,3,3,3,2,3,2,4,5,5,5,3,2,4,6,3,5,4,8,4,
       16,4,4,2,6,3,7,3,5,4,7,4,4,3,3,3,3,8,2,3,2,4,5,6,4,3,3,3,7,3,4,5,8,4,
       16,4,4,2,6,3,6,3,5,4,8,3,5,8,3,9,2,3,1,4,6,6,3,3,4,3,7,3,3,6,7,4,17,4,
       4,3,5,3,6,3,4,4,9,3,5,8,3,7,3,8,6,3,1,4,1,4,3,4,7,3,2,3,1,3,7,4,17,4,
       4,3,5,3,5,11,9,3,6,7,4,6,4,7,6,3,2,8,4,3,8,7,2,3,6,4,18,3,5,4,3,4,5,
       10,10,3,6,6,6,4,4,6,7,3,4,6,5,3,8,7,2,4,4,4,19,3,5,10,5,3,1,6,11,3,7,
       3,16,5,7,4,4,5,6,3,8,6,3,5,3,4,19,3,6,9,5,3,18,2,25,5,9,3,6,3,7,2,10,
       3,6,4,3,3,20,3,8,5,6,3,44,6,10,2,39,3,3,2,22,2,19,3,43,7,101,3,42,8,
       102,3,41,4,1,4,101,4,39,5,2,3,102,3,39,4,4,3,102,3,38,4,4,4,101,3,38,
       4,5,3,102,3,37,4,5,4,101,4,36,4,6,3,102,3,37,3,6,4,102,3,36,4,6,3,102,
       3,37,3,6,3,103,3,37,3,5,4,102,4,37,3,4,4,103,3,38,10,104,3,38,9,105,2,
       40,7,106,2,41,4,0};

//                     //
// FUNCTION PROTOTYPES //
//                     //

  void InitChain4();
  void C4PutPixel(word X, word Y, byte Col);
  void Plane     (byte Which);
  void MoveTo    (word X, word Y);
  void Putpic    (int x, int y);
  void Play      ();

//                  //
// GLOBAL VARIABLES //
//                  //

  // Just for fun, change this to "const byte SIZE = 80" and try to run
  // the program.  It is generally a good programming practice to use
  // contant variables when you know that the values should not change.
  // However, this program uses lots of assembler.  I guess that a constant
  // byte is stored differently than just a normal byte.  Go figure!  :)

  byte SIZE = 80;      // Size =  40 = 1 across, 4 down
                       // Size =  80 = 2 across, 2 down
                       // Size = 160 = 4 across, 1 down


///////////////////////////////////////////////////////////////////////////////
//                                                                           //
//                                MAIN FUNCTION                              //
//                                                                           //
///////////////////////////////////////////////////////////////////////////////

void main() {

  clrscr();
  cout
    << "Hello there! Here is the tenth tutorial, on Chain-4! You will notice\n"
    << "that there are two files here : one contains all of our graphics\n"
    << "based routines, and one is the demo program.\n\n"
    << "In the demo program, we will do the necessary port stuff to get into\n"
    << "Chain-4. Once in Chain-4 mode, I will put down text saying ASPHYXIA\n"
    << "over the entire screen. After a key is pressed, the viewport will\n"
    << "bounce around, displaying the entire Chain-4 screen. The program will\n"
    << "end when [ESC] is pressed. The code here is really basic (except for\n"
    << "those port values), and should be very easy to understand.\n\n";

  cout
    << "Yo, Snowman here.  Frankly I'm tired of just converting these\n"
    << "bloody tutorials!  :)  I am going to start doing some ""creative""\n"
    << "things in these programs.  The first deviant thing I'm doing is\n"
    << "flipping Denthor's snazzy logo so that <Asphyxia> is reversed.\n"
    << "Hey, we all got to break out and have fun sometime, right?  :)\n\n";
  cout << "Hit any key to continue ...";
  getch();

  InitChain4();
  Play();

  SetText();
  cout
    << "All done. This concludes the tenth sample program in the ASPHYXIA\n"
    << "Training series. You may reach DENTHOR under the names of GRANT\n"
    << "SMITH/DENTHOR/ASPHYXIA on the ASPHYXIA BBS. I am also an avid\n"
    << "Connectix BBS user, and occasionally read RSAProg. E-mail me at :\n"
    << "    [email protected]\n"
    << "The numbers are available in the main text. You may also write to me at:\n"
    << "             Grant Smith\n"
    << "             P.O. Box 270\n"
    << "             Kloof\n"
    << "             3640\n"
    << "             Natal\n"
    << "             South Africa\n"
    << "I hope to hear from you soon!\n\n";
  cout << "Hit any key to exit ...";
  getch();

}


/////////////////////////////////////////////////////////////////////////////
//                                                                         //
// InitChain4() - This function gets you into Chain 4 mode.                //
//                Note: As soon as I find documentation, this function     //
//                will be better documented.  - Snowman                    //
//                                                                         //
/////////////////////////////////////////////////////////////////////////////

void InitChain4() {

  asm {
    mov    ax, 0x13      // routine 13 = MCGA mode
    int    0x10          // do it!
    mov    dx, 0x3C4     // Port 0x3C4 = Sequencer Address Register
    mov    al, 4         // Index 4 = memory mode
    out    dx, al        // send it
    inc    dx            // Port 0x3C5 ... here we set the mem mode
    in     al, dx
    and    al, not 0x08
    or     al, 0x04
    out    dx, al
    mov    dx, 0x3CE
    mov    al, 5
    out    dx, al
    inc    dx
    in     al, dx
    and    al, not 0x10
    out    dx, al
    dec    dx
    mov    al, 6
    out    dx, al
    inc    dx
    in     al, dx
    and    al, not 0x02
    out    dx, al
    mov    dx, 0x3C4
    mov    ax, (0x0F shl 8) + 2
    out    dx, ax
    mov    ax, 0xA000
    mov    es, ax
    sub    di, di
    mov    ax, 0x0000    // 0x8080
    mov    cx, 32768
    cld
    rep    stosw         // Clear garbage off the screen ...

    mov    dx, 0x3D4
    mov    al, 0x14
    out    dx, al
    inc    dx
    in     al, dx
    and    al, not 0x40
    out    dx, al
    dec    dx
    mov    al, 0x17
    out    dx, al
    inc    dx
    in     al, dx
    or     al, 0x40
    out    dx, al

    mov    dx, 0x3D4
    mov    al, 0x13
    out    dx, al
    inc    dx
    mov    al, [SIZE]    // Size * 8 = Pixels across. Only 320 are visible
    out    dx, al
  }
}


/////////////////////////////////////////////////////////////////////////////
//                                                                         //
// C4PutPixel() - This puts a pixel on the chain 4 screen.                 //
//                Note: As soon as I find documentation, this function     //
//                will be better documented.  - Snowman                    //
//                                                                         //
/////////////////////////////////////////////////////////////////////////////

void C4PutPixel(word X, word Y, byte Col) {

  asm {
    mov    ax,[Y]
    xor    bx,bx
    mov    bl,[SIZE]
    imul   bx
    shl    ax,1
    mov    bx,ax
    mov    ax, [X]
    mov    cx, ax
    shr    ax, 2
    add    bx, ax
    and    cx, 00000011b
    mov    ah, 1
    shl    ah, cl
    mov    dx, 0x3C4             // Sequencer Register
    mov    al, 2                 // Map Mask Index
    out    dx, ax
    mov    ax, 0xA000
    mov    es, ax
    mov    al, [Col]
    mov    es: [bx], al
  }
}


/////////////////////////////////////////////////////////////////////////////
//                                                                         //
// Plane() - This sets the plane to write to in Chain 4.                   //
//                Note: As soon as I find documentation, this function     //
//                will be better documented.  - Snowman                    //
//                                                                         //
/////////////////////////////////////////////////////////////////////////////

void Plane (byte Which) {

  asm {
    mov    al, 0x2
    mov    ah, 1
    mov    cl, [Which]
    shl    ah, cl
    mov    dx, 0x3C4              // Sequencer Register
    out    dx, ax
  }
}


/////////////////////////////////////////////////////////////////////////////
//                                                                         //
// MoveTo() - This moves to position X*4 on a chain 4 screen.              //
//                Note: As soon as I find documentation, this function     //
//                will be better documented.  - Snowman                    //
//                                                                         //
/////////////////////////////////////////////////////////////////////////////

void MoveTo (word X, word Y) {

  word O = Y*SIZE*2+X;

  asm {
    mov    bx, [O]
    mov    ah, bh
    mov    al, 0x0C

    mov    dx, 0x3D4
    out    dx, ax

    mov    ah, bl
    mov    al, 0x0D
    mov    dx, 0x3D4
    out    dx, ax
  }
}


/////////////////////////////////////////////////////////////////////////////
//                                                                         //
// Putpic() - This puts the picture at coordinates x,y on the chain-4      //
//            screen.                                                      //
//                                                                         //
/////////////////////////////////////////////////////////////////////////////

void Putpic (int x, int y) {

  int loop1, loop2, cur=0;
  word depth = 1;

  // for every element of the picture data...
  for (loop1=0; loop1<897; loop1++) {
    for (loop2=0; loop2<BIT[loop1]; loop2++) {
      // read the tut10.txt file for more information on what this does
      if (cur != 0)
        // take out the "155-" to make the logo face the right direction
        C4PutPixel(155-(depth % 155)+x, (depth / 155)+y,(depth / 155));
      depth++;
    }
    cur = (cur+1) % 2;
  }
}


/////////////////////////////////////////////////////////////////////////////
//                                                                         //
// Play() - The function that does it all...                               //
//                                                                         //
/////////////////////////////////////////////////////////////////////////////

void Play() {

  int loop1, loop2, xpos, ypos, xdir, ydir;
  Pal PicPal[64];
  char ch = 1;

  // This sets up the pallette for the picture
  for (loop1=1; loop1<63; loop1++) {
    PicPal[loop1].PalSet(loop1,0,62-loop1);
    PicPal[loop1].PalPut(loop1);
  }

  // This moves the view to the top left hand corner
  MoveTo(0,0);

  // This places the picture all over the chain-4 screen
  for (loop1=0; loop1<4; loop1++)
    for (loop2=0; loop2<6; loop2++)
      Putpic(loop1*160, loop2*66);
  getch();

  // Random start positions/movements for the view
  xpos = (rand() %  78) + 1;
  ypos = (rand() % 198) + 1;
  xdir = 1;
  ydir = 1;

  // Main loop (move around the Chain-4 Screen)
  do {
    if (kbhit()) ch = getch();
    MoveTo(xpos, ypos);
    // Take this out and watch the screen go crazy!
    WaitRetrace();
    xpos += xdir;
    ypos += ydir;
    // Hit a boundry, change direction
    if ((xpos >  79) || (xpos < 1)) xdir *= -1;
    if ((ypos > 199) || (ypos < 1)) ydir *= -1;
    if (ch == 0) ch = getch();
  } while (ch != 27); // if the escape code was 27 (escape key) then exit

}
Hosted by www.Geocities.ws

1