home *** CD-ROM | disk | FTP | other *** search
/ Stars of Shareware: Programmierung / SOURCE.mdf / programm / msdos / pascal / rehack / demosrc / dungeon.cpp < prev    next >
Encoding:
C/C++ Source or Header  |  1993-06-21  |  15.5 KB  |  500 lines

  1.  
  2. // DUNGEON.CPP Version 1.0 -- Demonstrates tile scrolling through a dungeon
  3. //        layout
  4. // Written by Chris Lampton, 5/26/91
  5. // All art by Mike Barrs
  6. // All contents copyright (c) 1991 by the GAMERS Programming Workshop.
  7.  
  8. // A brief note on data structures:
  9.  
  10. //   This program is oriented around two arrays that contain two
  11. // different forms of a 48 by 48 tile dungeon map. The first array,
  12. // dungeon[], contains a description of the dungeon in terms of
  13. // "quadtiles," each of which is constructed out of four of the
  14. // small tiles contained in the file DUNTIL4B.GRF, arranged in a
  15. // square. See the #defines below for a list of the 18 types of big
  16. // tile. During initialization, this array is translated into a
  17. // second array, dungeon2[], which contains a description of the
  18. // dungeon in terms of the actual small tiles used on the screen.
  19. // This system, which may or may not be used in the final version
  20. // of REHACK, facilitates dungeon design while allowing more versa-
  21. // tile use of the tile set.
  22.  
  23. #include <alloc.h>
  24. #include <conio.h>
  25. #include <dos.h>
  26. #include <stdio.h>
  27. #include <stdlib.h>
  28.  
  29. #define  TILE_NUM 39                    // Number of small tiles
  30. #define  TILE_HEIGHT 21                 // Height of small tile in pixels
  31. #define  TILE_WIDTH 21                  // Width of small tile in pixels
  32. #define  QUAD_TILE_NUM 18               // Number of quadtiles
  33. #define  QUAD_TILE_WIDTH TILE_WIDTH*2   // Width of quadtile in pixels
  34. #define  QUAD_TILE_HEIGHT TILE_HEIGHT*2 // Height of quadtile in pixels
  35. #define  WIND_WIDTH 7                   // Width of dungeon window in small tiles
  36. #define  WIND_HEIGHT 7                  // Height of dungeon window in small tiles
  37. #define  DUNGEON_WIDTH 48               // Width of dungeon map in small tiles
  38. #define  DUNGEON_HEIGHT 48              // Height of dungeon map in small tiles
  39. #define  SCROLL_RATE 21                 // Number of pixels scrolled per frame
  40.  
  41. // The following #defines represent the 18 types of "quadtiles," each
  42. // constructed out of four small tiles, that are the basic building blocks
  43. // of the dungeon in this program.
  44.  
  45. #define  UL 0        // Upper left corner
  46. #define  UR 1        // Upper right corner
  47. #define  FL 2        // Floor
  48. #define  LL 3        // Lower left corner
  49. #define  LR 4        // Lower right corner
  50. #define  HO 5        // Horizontal wall
  51. #define  VE 6        // Vertical wall
  52. #define  NT 7        // North 't' intersection
  53. #define  ST 8        // South 't' intersection
  54. #define  WT 9        // West 't' intersection
  55. #define  ET 10       // East 't' intersection
  56. #define  NE 11       // North wall end
  57. #define  SE 12       // South wall end
  58. #define  WE 13       // West wall end
  59. #define  EE 14       // East wall end
  60. #define  CC 15       // Central cross
  61. #define  HD 16       // Horizontal door
  62. #define  VD 17       // Vertical door
  63.  
  64. // Function prototypes:
  65.  
  66. void setmode(int);
  67. void setpalette();
  68. void translate();
  69. void load_screen();
  70. void blit(void far *,int,int,int,int,int,int,int,int);
  71. void draw_window(int,int,int,int);
  72. void draw_tile(int,int,int,int,int,int,int);
  73. void putscreen();
  74. void putwindow(int,int,int,int);
  75. void wait_for_vbl(void);
  76.  
  77. unsigned char far *tile[TILE_NUM];      // Array of tile bitmaps
  78. char far colregs[3*256];                // Array of color register values
  79. unsigned char far screen_buffer[64000]; // Screen buffer
  80. char quadtile[QUAD_TILE_NUM][4]={       // Array of quadtile definitions for translate()
  81.     {0,10,3,4},
  82.     {1,2,6,7},
  83.     {5,5,5,5},
  84.     {8,9,13,14},
  85.     {11,12,15,16},
  86.     {10,10,15,15},
  87.     {3,12,3,12},
  88.     {26,10,6,4},
  89.     {17,9,15,15},
  90.     {19,9,3,4},
  91.     {24,12,6,12},
  92.     {18,2,3,7},
  93.     {25,12,13,27},
  94.     {20,10,13,14},
  95.     {22,2,15,23},
  96.     {21,9,6,4},
  97.     {10,10,29,30},
  98.     {3,32,3,33}
  99. };
  100.  
  101. // Dungeon map defined in terms of quadtiles (see above):
  102.  
  103. char dungeon[DUNGEON_HEIGHT/2][DUNGEON_WIDTH/2]={
  104.     {UL,HO,HO,HO,HO,HO,HO,HO,HO,HO,HO,HO,HO,HO,HO,HO,HO,HO,HO,NT,HO,HO,HO,UR},
  105.     {VD,FL,FL,FL,FL,FL,FL,FL,FL,FL,FL,FL,FL,FL,FL,FL,FL,FL,FL,VE,FL,FL,FL,VE},
  106.     {VE,FL,UL,HO,HO,HO,HO,UR,FL,FL,FL,FL,FL,FL,FL,FL,FL,FL,FL,WT,HO,UR,FL,VE},
  107.     {VE,FL,VE,FL,FL,FL,FL,VE,FL,FL,UL,HO,HO,HO,HO,HO,HO,UR,FL,VE,FL,VE,FL,VE},
  108.     {VE,FL,VD,FL,FL,FL,FL,VE,FL,FL,VE,FL,FL,FL,FL,FL,FL,VE,FL,VE,FL,SE,FL,VE},
  109.     {VE,FL,VE,FL,FL,FL,FL,VE,FL,FL,VE,FL,FL,FL,FL,FL,FL,VE,FL,VE,FL,FL,FL,VE},
  110.     {VE,FL,LL,HO,HO,HO,HO,LR,FL,FL,LL,HO,UR,FL,FL,UL,HO,LR,FL,VE,FL,NE,FL,VE},
  111.     {VE,FL,FL,FL,FL,FL,FL,FL,FL,FL,FL,FL,VE,FL,FL,VE,FL,FL,FL,VE,FL,VE,FL,VE},
  112.     {VE,FL,FL,FL,FL,FL,FL,FL,FL,FL,FL,FL,VE,FL,FL,VE,FL,FL,FL,WT,HO,LR,FL,VE},
  113.     {VE,FL,UL,HO,HO,HO,UR,FL,FL,FL,FL,FL,VE,FL,FL,VE,FL,UL,HO,ET,FL,FL,FL,VE},
  114.     {VE,FL,VE,FL,FL,FL,LL,HO,UR,FL,FL,FL,LL,HO,HD,LR,FL,VE,FL,VE,FL,FL,FL,VE},
  115.     {VE,FL,VE,FL,FL,FL,FL,FL,VE,FL,FL,FL,FL,FL,FL,FL,FL,VE,FL,LL,UR,FL,FL,VE},
  116.     {VE,FL,VE,FL,FL,FL,FL,FL,VE,FL,FL,FL,FL,UL,HO,HO,HO,ET,FL,FL,LL,EE,FL,VE},
  117.     {VE,FL,LL,HO,HD,HO,HO,HO,LR,FL,FL,FL,FL,VE,FL,FL,FL,LL,HO,EE,FL,FL,FL,VE},
  118.     {VE,FL,FL,FL,FL,FL,FL,FL,FL,FL,FL,FL,FL,VE,FL,NE,FL,FL,FL,FL,FL,FL,FL,VE},
  119.     {VE,FL,UL,HO,HD,UR,FL,FL,FL,FL,FL,FL,FL,WT,HO,LR,FL,WE,HO,NT,HO,UR,FL,VE},
  120.     {VE,FL,VE,FL,FL,LL,HO,UR,FL,FL,FL,FL,FL,VD,FL,FL,FL,FL,FL,VE,FL,VE,FL,VE},
  121.     {VE,FL,VE,FL,FL,FL,FL,VE,FL,FL,FL,FL,FL,VE,FL,FL,FL,FL,FL,VE,FL,VE,FL,VE},
  122.     {VE,FL,LL,HO,UR,FL,FL,LL,HO,UR,FL,FL,FL,WT,HO,HO,HO,UR,FL,VE,FL,VE,FL,VE},
  123.     {VE,FL,FL,FL,VE,FL,FL,FL,FL,VD,FL,FL,FL,VE,FL,FL,FL,VE,FL,VE,FL,VE,FL,VE},
  124.     {VE,FL,FL,FL,VE,FL,FL,FL,FL,VE,FL,FL,FL,VE,FL,NE,FL,VE,FL,VE,FL,VE,FL,VE},
  125.     {VE,FL,FL,FL,LL,HO,HO,HO,HO,LR,FL,FL,FL,VE,FL,LL,HO,ST,HO,LR,FL,SE,FL,VE},
  126.     {VE,FL,FL,FL,FL,FL,FL,FL,FL,FL,FL,FL,FL,VE,FL,FL,FL,FL,FL,FL,FL,FL,FL,VE},
  127.     {LL,HO,HO,HO,HO,HO,HO,HO,HO,HO,HO,HO,HO,ST,HO,HO,HO,HO,HO,HO,HO,HO,HO,LR},
  128. };
  129.  
  130. char dungeon2[DUNGEON_HEIGHT][DUNGEON_WIDTH]; // Array for small tile map
  131.  
  132.  
  133. int main()
  134. {
  135.     int    i,j,d,row=0,column=0,xoff,yoff;
  136.     long  l;
  137.     char far *temp;
  138.     char    ch;
  139.     FILE    *fp;
  140.  
  141.     setmode(0x13); // Set graphics mode to 13h
  142.  
  143.    // Open file containing bitmaps for tiles
  144.  
  145.     if ((fp=fopen("..\\pics\\duntil4b.grf","rb"))==NULL) {
  146.         setmode(3);
  147.         printf("Cannot open ..\\pics\\duntil4b.grf\n");
  148.         exit(1);
  149.     }
  150.  
  151.    // Load palette from file into colregs[]
  152.  
  153.     for (i=0; i<(3*256); i++) colregs[i]=getc(fp);
  154.  
  155.     load_screen(); // Load background screen into graphics buffer
  156.  
  157.    // Load tiles into tile[]
  158.  
  159.     for (i=0; i<TILE_NUM; i++) {
  160.         tile[i]=(unsigned char far *)farmalloc(TILE_HEIGHT * TILE_WIDTH);
  161.         for (j=0; j<(TILE_HEIGHT * TILE_WIDTH); j++)
  162.             tile[i][j]=(unsigned char)getc(fp);
  163.     }
  164.     fclose(fp);
  165.     translate();   // Translate quadtiles into small tiles
  166.     setpalette();  // Set palette to palette in tile file
  167.     draw_window(0,0,0,0); // Draw initial contents of dungeon window in graphics buffer
  168.     putscreen();   // Move graphics buffer to the screen
  169.  
  170.    // Main program loop
  171.    // Waits for cursor arrow to be pressed, then scrolls dungeon window
  172.  
  173.     do {
  174.         ch=getch();
  175.         if (ch==0) {
  176.             ch=getch();
  177.             switch (ch) {
  178.                 case 72: { // Up arrow, so scroll up
  179.                     if (row>0) {
  180.                         --row;
  181.                         for (yoff=TILE_HEIGHT-SCROLL_RATE; yoff>0; yoff-=SCROLL_RATE)
  182.                             draw_window(column,row,0,yoff);
  183.                             putwindow(10,8,WIND_WIDTH*TILE_WIDTH,WIND_HEIGHT*TILE_HEIGHT);
  184.                     }
  185.                     break;
  186.                 }
  187.                 case 80: {    // Down arrow, so scroll down
  188.                     if (row<(DUNGEON_HEIGHT-WIND_HEIGHT)) {
  189.                         for (yoff=SCROLL_RATE; yoff<TILE_HEIGHT; yoff+=SCROLL_RATE)
  190.                             draw_window(column,row,0,yoff);
  191.                             putwindow(10,8,WIND_WIDTH*TILE_WIDTH,WIND_HEIGHT*TILE_HEIGHT);
  192.                         row++;
  193.                     }
  194.                     break;
  195.                 }
  196.                 case 75: {    // Left arrow, so scroll left
  197.                     if (column>0) {
  198.                         --column;
  199.                         for (xoff=TILE_WIDTH-SCROLL_RATE; xoff>0; xoff-=SCROLL_RATE)
  200.                             draw_window(column,row,xoff,0);
  201.                             putwindow(10,8,WIND_WIDTH*TILE_WIDTH,WIND_HEIGHT*TILE_HEIGHT);
  202.                     }
  203.                     break;
  204.                 }
  205.                 case 77: { // Right arrow, so scroll right
  206.                     if (column<(DUNGEON_WIDTH-WIND_WIDTH)) {
  207.                         for (xoff=SCROLL_RATE; xoff<TILE_WIDTH; xoff+=SCROLL_RATE)
  208.                             draw_window(column,row,xoff,0);
  209.                             putwindow(10,8,WIND_WIDTH*TILE_WIDTH,WIND_HEIGHT*TILE_HEIGHT);
  210.                         column++;
  211.                     }
  212.                     break;
  213.                 }
  214.             }
  215.             draw_window(column,row,0,0);
  216.             putwindow(10,8,WIND_WIDTH*TILE_WIDTH,WIND_HEIGHT*TILE_HEIGHT);
  217.         }
  218.     } while (ch!=27);  // Terminate if ESC pressed
  219.     setmode(3);        // Restore DOS screen mode
  220.  
  221.     for (i=0; i<TILE_NUM; i++) {
  222.         farfree( tile[ i ] );
  223.     }
  224.  
  225.     return 0;
  226. }
  227.  
  228. // translate()
  229.  
  230. // Translates dungeon array from quadtile format in dungeon[] to
  231. // small tile format in dungeon2[].
  232.  
  233. void translate()
  234. {
  235.     int    x,y;
  236.  
  237.    // Translate quadtiles to small tiles
  238.  
  239.     for (x=0;x<DUNGEON_WIDTH/2;x++)
  240.         for (y=0;y<DUNGEON_HEIGHT/2;y++) {
  241.             dungeon2[y*2][x*2]=quadtile[dungeon[y][x]][0];
  242.             dungeon2[y*2][x*2+1]=quadtile[dungeon[y][x]][1];
  243.             dungeon2[y*2+1][x*2]=quadtile[dungeon[y][x]][2];
  244.             dungeon2[y*2+1][x*2+1]=quadtile[dungeon[y][x]][3];
  245.         }
  246.  
  247.    // Add corners of doors to tiles next to door tiles
  248.  
  249.     for (x=0;x<DUNGEON_WIDTH/2;x++)
  250.         for (y=0;y<DUNGEON_HEIGHT/2;y++) {
  251.             if (dungeon[y][x]==HD) dungeon2[y*2+1][x*2-1]=28;
  252.             if (dungeon[y][x]==VD) dungeon2[y*2+2][x*2+1]=34;
  253.         }
  254. }
  255.  
  256. // load_screen()
  257.  
  258. // Loads background screen from disk into screen_buffer[]
  259.  
  260. void load_screen()
  261. {
  262.     long    i;
  263.     unsigned char far *screen;
  264.     FILE *fp;
  265.  
  266.     if ((fp=fopen("..\\pics\\mbs08-b.grf","rb"))==NULL) {
  267.         setmode(3);
  268.         printf("Cannot open ..\\pics\\mbs08-b.grf\n");
  269.         exit(1);
  270.     }
  271.     for (i=0; i<(3*256); i++) getc(fp);
  272.     for (i=0; i<64000; i++) screen_buffer[i]=(unsigned char)getc(fp);
  273.     fclose(fp);
  274. }
  275.  
  276. // draw_window(int xtile,int ytile,int xoff,int yoff)
  277.  
  278. // Draws dungeon window with dimensions (in small tiles) of WIND_WIDTH,
  279. // WIND_HEIGHT at screen coordinates xpos, ypos. The first row and
  280. // column of tiles is offset by xoff, yoff pixels.
  281.  
  282. void draw_window(int xtile,int ytile,int xoff,int yoff)
  283. {
  284.     int    x,y,xpos,ypos,xoff1,yoff1,xext,yext;
  285.  
  286.     for (x=0; x<(WIND_WIDTH+1);x++)
  287.         for (y=0; y<(WIND_HEIGHT+1);y++) {
  288.             xpos=(x==0)?10:10+x*TILE_WIDTH-xoff;
  289.             ypos=(y==0)?8:8+y*TILE_HEIGHT-yoff;
  290.             if (x==0) {
  291.                 xoff1=xoff;
  292.                 xext=TILE_WIDTH-xoff;
  293.             }
  294.             else {
  295.                 xoff1=0;
  296.                 xext=TILE_WIDTH;
  297.             };
  298.             if (y==0) {
  299.                 yoff1=yoff;
  300.                 yext=TILE_HEIGHT-yoff;
  301.             }
  302.             else {
  303.                 yoff1=0;
  304.                 yext=TILE_HEIGHT;
  305.             };
  306.             if (x==WIND_WIDTH) xext=xoff;
  307.             if (y==WIND_HEIGHT) yext=yoff;
  308.             if    (!(((x==WIND_WIDTH)&&(xoff==0))||((y==WIND_HEIGHT)&&(yoff==0))))
  309.                 draw_tile((int)dungeon2[ytile+y][xtile+x],xpos,ypos,xoff1,yoff1,xext,yext);
  310.         }
  311. }
  312.  
  313. // draw_tile(int tnum,int xpos,int ypos,int xoff,int yoff,int xext,int yext)
  314.  
  315. // Draw xext,yext pixels of tile tnum starting at pixel xoff,yoff at
  316. // screen coordinates xpos,ypos
  317.  
  318. void draw_tile(int tnum,int xpos,int ypos,int xoff,int yoff,int xext,int yext)
  319. {
  320.     blit(tile[tnum],xpos,ypos,TILE_WIDTH,TILE_HEIGHT,xoff,yoff,xext,yext);
  321. }
  322.  
  323. // blit(void far *tile,int xpos,int ypos,int xsize,int ysize,int xoff,int yoff,int xext,int yext)
  324.  
  325. // Draw rectangular bitmap, or portion of bitmap, in screen_buffer[]
  326. // Parameters:
  327. //   *tile - pointer to bitmap
  328. //   xpos  - x coordinate to draw bitmap at
  329. //   ypos  - y coordinate to draw bitmap at
  330. //   xsize - horizontal dimension, in pixels, of bitmap
  331. //   ysize - vertical dimension, in pixels, of bitmap
  332. //   xoff  - horizontal offset within bitmap, measured in pixels, to start drawing at
  333. //   yoff  - vertical offset within bitmap, measured in pixels, to start drawing at
  334. //   xext  - number of pixels to draw horizontally in bitmap
  335. //   yext  - number of pixels to draw vertically in bitmap
  336.  
  337. void blit(void far *tile,int xpos,int ypos,int xsize,int ysize,int xoff,int yoff,int xext,int yext)
  338. {
  339.     int    screen;
  340.     int   offscr,segscr,offtil,segtil,xjump;
  341.  
  342.     offscr=FP_OFF(screen_buffer);
  343.     segscr=FP_SEG(screen_buffer);
  344.     offtil=FP_OFF(tile)+xoff+yoff*xsize;
  345.     segtil=FP_SEG(tile);
  346.     screen=offscr+320*ypos+xpos;
  347.     xjump=xsize-xext;
  348.     asm {
  349.         mov    dx,es          // Save segment registers
  350.         push    dx
  351.         mov    dx,ds
  352.         push    dx
  353.         mov    dx,segscr        // Get screen buffer segment in ES
  354.         mov    es,dx
  355.         mov    dx,segtil        // Get tile segment in DS
  356.         mov    ds,dx
  357.         mov    si,offtil      // Point SI at tile bitmap plus xoff,yoff
  358.         mov    di,screen      // Point DI at address in screen buffer
  359.         mov    dx,yext        // Get line count in DX
  360.         cld
  361.     }
  362.     loop1:
  363.     asm {
  364.         mov    cx,xext        // Get pixel count in CX
  365.         push  di             // Save screen buffer address
  366.         rep    movsb          // Move one line of tile to screen buffer
  367.         pop    di             // Restore screen buffer address
  368.         add    di,320         // ...and advance it to next line on screen
  369.         add    si,xjump       // Advance SI to next line of tile bitmap
  370.         dec    dx             // Count off one line
  371.         jnz    loop1          // If more lines in tile, loop back and draw them
  372.         pop    dx             // Else restore segment registers and return
  373.         mov    ds,dx
  374.         pop    dx
  375.         mov   es,dx
  376.     }
  377. }
  378.  
  379. // putwindow(int xpos,int ypos,int xsize,int ysize)
  380.  
  381. // Move rectangle at xpos,ypos with dimensions xsize,ysize from
  382. // screen_buffer[] to video memory
  383.  
  384. void putwindow(int xpos,int ypos,int xsize,int ysize)
  385. {
  386.     int   offbuf,segbuf,offscr,segscr,xjump;
  387.  
  388.     wait_for_vbl();
  389.     offbuf=FP_OFF(screen_buffer);
  390.     segbuf=FP_SEG(screen_buffer);
  391.     offscr=320*ypos+xpos;
  392.     offbuf=offbuf+offscr;
  393.     asm {
  394.         mov    dx,es          // Save segment registers
  395.         push    dx
  396.         mov    dx,ds
  397.         push    dx
  398.         mov    dx,0a000h        // Get screen segment in ES
  399.         mov    es,dx
  400.         mov    dx,segbuf        // Get screen buffer segment in DS
  401.         mov    ds,dx
  402.         mov    si,offbuf      // Point SI at window address within buffer
  403.         mov    di,offscr      // Point DI at window address on screen
  404.         mov    dx,ysize       // Get line count into DX
  405.         cld }
  406.     loop1:
  407.     asm {
  408.         mov    cx,xsize       // Get pixel width of window into CX
  409.         push  di             // Save screen and buffer addresses
  410.         push    si
  411.         rep    movsb          // Move one line of window to screen
  412.         pop    si             // Restore screen and buffer addresses
  413.         pop    di
  414.         add    si,320         // ...and advance them to next line
  415.         add    di,320
  416.         dec    dx             // Count off one line
  417.         jnz    loop1          // If more lines in window, loop back and draw them
  418.         pop    dx             // Else restore segment registers and return
  419.         mov    ds,dx
  420.         pop    dx
  421.         mov   es,dx
  422.     }
  423. }
  424.  
  425.  
  426. void putscreen()
  427. {
  428.     int offbuf,segbuf;
  429.  
  430.     offbuf=FP_OFF(screen_buffer);
  431.     segbuf=FP_SEG(screen_buffer);
  432.     asm {
  433.         mov    dx,es          // Save segment registers
  434.         push    dx
  435.         mov    dx,ds
  436.         push    dx
  437.         mov    dx,0a000h      // Get screen segment into ES
  438.         mov    es,dx
  439.          mov    dx,segbuf      // Get buffer segment into DS
  440.         mov    ds,dx
  441.         mov    si,offbuf      // Point SI at start of buffer
  442.         mov    di,0           // Point DI at start of screen
  443.         mov    cx,32000       // Count 32,000 words
  444.         rep    movsw          // Move 32,000 words from buffer to screen
  445.         pop    dx             // Restore segment registers
  446.         mov    ds,dx
  447.         pop    dx
  448.         mov    es,dx
  449.     }
  450. }
  451.  
  452. // setmode(int mode)
  453.  
  454. // Calls video interrupt to set graphics adaptor to mode
  455.  
  456. void setmode(int mode)
  457. {
  458.     union REGS inregs, outregs;
  459.     struct SREGS segregs;
  460.  
  461.     inregs.h.ah = 0x00;
  462.     inregs.h.al = mode;
  463.     int86x(0x10, &inregs, &outregs, &segregs);
  464. }
  465.  
  466. // setpalette()
  467.  
  468. // Sets all 256 VGA color registers to RGB values in colregs[]
  469.  
  470. void setpalette()
  471. {
  472.     int    offcol,segcol;
  473.  
  474.     offcol=FP_OFF(colregs);
  475.     segcol=FP_SEG(colregs);
  476.     asm{
  477.         mov    dx,es
  478.         push    dx
  479.         mov    dx,segcol
  480.         mov    es,dx
  481.         mov    ah,10h
  482.         mov    al,12h
  483.         mov    bx,0
  484.         mov    cx,100h
  485.         mov    dx,offcol
  486.         int    10h
  487.         pop    dx
  488.         mov    es,dx
  489.     }
  490. }
  491.  
  492. // wait_for_vbl(void)
  493.  
  494. // Loop to delay until next vertical blank
  495.  
  496. void wait_for_vbl(void)
  497. {
  498.     while ((inport(0x3da)&8)==0);
  499. }
  500.