home *** CD-ROM | disk | FTP | other *** search
/ Power-Programmierung / CD2.mdf / c / library / dos / grafik / hgraphic / graphics.c < prev    next >
Encoding:
C/C++ Source or Header  |  1988-04-12  |  19.5 KB  |  637 lines

  1. /*****************************************************************************/
  2. /*    Hercules Compatible graphics routines written for Microsoft Quick C  */
  3. /*    version 1.0.  Compile with large model (option /AL).             */
  4. /*                                         */
  5. /*    Written by:    Ben Bederson   (c) 1988                     */
  6. /*               bbb7889@acf5.NYU.EDU                     */
  7. /*                                         */
  8. /*               222 East 19th St.  #3H                     */
  9. /*               New York, NY  10003                     */
  10. /*               (212) 260-2667                         */
  11. /*                                         */
  12. /*    These routines were written by myself for my own purposes and I make */
  13. /*    no guarantees, warentees, expressed, or implied, etc.  However,      */
  14. /*    I hope they are useful.  Everybody is free and encouraged to copy    */
  15. /*    and use these routines under the condition that this statement is    */
  16. /*    kept at the top without modification.  I would appreciate any         */
  17. /*    comments or criticisms or improvement/ideas about these routines.    */
  18. /*                                         */
  19. /*    Good luck.                                 */
  20. /*****************************************************************************/
  21.  
  22. #include <stdio.h>
  23. #include <conio.h>
  24. #include <malloc.h>
  25. #include <dos.h>
  26. #include "graphics.h"
  27.  
  28. /*****************************************************************************/
  29. /*                                         */
  30. /*         Routines in this file:                         */
  31. /*                                         */
  32. /*         graphics() - Enter monochrome 720x348 graphics mode (clear scn) */
  33. /*         text()    - Enter text mode                     */
  34. /*         cls()    - Clear the text screen                  */
  35. /*         grcls()    - Clear the graphics screen                 */
  36. /*         fill_screen()    - Fill the graphics screen to white         */
  37. /*         dot(x,y,color)    - Put a dot of color WHITE,BLACK, or XOR     */
  38. /*                  at the location x,y on the graphics screen */
  39. /*         line(x1,y1,x2,y2,color)                         */
  40. /*                - Draw a line from x1,y1 to x2,y2 in color   */
  41. /*         draw(shape,x,y,color)                         */
  42. /*                - Draw the shape as specified by a         */
  43. /*                  shape_type structure in the specified      */
  44. /*                  color at the specified location x,y.         */
  45. /*                  Not too fast.  Try draw_block for some     */
  46. /*                  really fast drawing.                 */
  47. /*         draw_block(shape,x,y,color)                     */
  48. /*                - Draw the shape as specified by a         */
  49. /*                  shape_type structure in the specified      */
  50. /*                  color at the specified location x,y.         */
  51. /*                  The location must be a byte boundary         */
  52. /*                  as this routine does not shift pixels.     */
  53. /*                  But, it is very fast!!!  It will not         */
  54. /*                  give an error if x,y is not a byte         */
  55. /*                  boundary, but will shift the block to      */
  56. /*                  draw it on a byte boundary.  (This only    */
  57. /*                  applies to the x-axis.             */
  58. /*         shift_up(shape,x,y,shift_num)                     */
  59. /*         shift_down(shape,x,y,shift_num)                     */
  60. /*         shift_left(shape,x,y,shift_num)                     */
  61. /*         shift_right(shape,x,y,shift_num)                     */
  62. /*                - Shifts the specified shape at the         */
  63. /*                  specified location by shift_num pixels     */
  64. /*                  in the direction corresponding to the      */
  65. /*                  routine name.  Really, just a rectangle    */
  66. /*                  is shifted specified by the size in the    */
  67. /*                  shape.  This is relatively slow because    */
  68. /*                  bits have to be shifted from one byte to   */
  69. /*                  the next.                     */
  70. /*                                         */
  71. /*            Note: Currently, only shift_right is implemented.    */
  72. /*                  Either use the block shifts, or it should be   */
  73. /*                  very easy to write shift_up,down, and left as  */
  74. /*                  they are just mirror images of shift_right.    */
  75. /*         shift_up_block(shape,x,y)                         */
  76. /*         shift_down_block(shape,x,y)                     */
  77. /*         shift_left_block(shape,x,y)                     */
  78. /*         shift_right_block(shape,x,y)                     */
  79. /*                - Shifts the specified shape at the         */
  80. /*                  specified location by 8 pixels in the      */
  81. /*                  direction corresponding to the routine     */
  82. /*                  name.  Really, just a rectangle is shifted */
  83. /*                  specified by the size in the shape.  This  */
  84. /*                  is very fast as entire bytes are moved     */
  85. /*                  without worrying about shifting bits.      */
  86. /*                Note: The shape must start on a byte         */
  87. /*                  boundary, or extra pixels will be moved    */
  88. /*                  with it.                     */
  89. /*                                         */
  90. /*****************************************************************************/
  91.  
  92. /*****************************************************************************/
  93. /*                                         */
  94. /*         User Info:                              */
  95. /*         ----------                              */
  96. /*                                         */
  97. /*         struct shape_type                             */
  98. /*                                         */
  99. /*         This structure represents a general shape.  x and y contain     */
  100. /*         the size in bytes of a shape.  shape_array is a pointer to      */
  101. /*         an array that must be allocated by the user.  The array is      */
  102. /*         a two dimensional array of single-byte characters where each    */
  103. /*         bit describes the shape: 1 ON, and 0 OFF.                 */
  104. /*                                         */
  105. /*         The colors are:                             */
  106. /*           WHITE    - Draw with pixels on.                     */
  107. /*           BLACK    - Draw with pixels off.                  */
  108. /*           XOR    - Draw with pixels opposite state of what they were  */
  109. /*           OVERWRITE - For drawing shapes, 1's put a pixel on, and       */
  110. /*               0's put a pixel off.  For other colors, 0's       */
  111. /*               don't do anything.                                */
  112. /*                                         */
  113. /*****************************************************************************/
  114.  
  115. char far* screen = (char far *)0xb0000000;
  116. int gr6845[] = {0x38, 0x2d, 0x30, 0x08, 0x5a, 0x00, 0x57, 0x57, 0x02,
  117.         0x03, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00};
  118. int te6845[] = {0x61, 0x50, 0x52, 0x0f, 0x19, 0x06, 0x19, 0x19, 0x02,
  119.         0x0d, 0x0b, 0x0c, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00};
  120.  
  121. /*****************************************************************************/
  122. /*                                         */
  123. /*    I enter graphics mode by directly accessing the 6845 graphics         */
  124. /*    controller chip.  I found the register addresses and data by         */
  125. /*    debugging a sample graphics program that came with my Everex         */
  126. /*    Hercules compatible graphics card.  I have tried them on both         */
  127. /*    Leading Edge and Five Star computers with Hercules-compatible         */
  128. /*    graphics cards with 100% success, so I expect that it should         */
  129. /*    work.                                     */
  130. /*                                         */
  131. /*****************************************************************************/
  132.  
  133. graphics()
  134. {
  135.   int i;
  136.  
  137.   outp(0x3b8,0);
  138.   outp(0x3bf,3);
  139.   for (i=0; i<18; i++) {
  140.     outp(0x3b4,i);
  141.     outp(0x3b5,gr6845[i]);
  142.   }
  143.   outp(0x3b8,6);
  144.   grcls();
  145.   outp(0x3b8,14);
  146. }
  147.  
  148. /*****************************************************************************/
  149. /*                                         */
  150. /*    Read the comment before about the graphics() routine to find         */
  151. /*    about this routine.                             */
  152. /*                                         */
  153. /*****************************************************************************/
  154.  
  155. text()
  156. {
  157.   int i;
  158.   union REGS regs;
  159.  
  160.   regs.x.ax = 2;
  161.   int86(0x10, ®s, ®s);
  162.   outp(0x3bf,0);
  163.   outp(0x3b8,0x28);
  164.   for (i=0; i<18; i++) {
  165.     outp(0x3b4,i);
  166.     outp(0x3b5,te6845[i]);
  167.   }
  168.   cls();
  169. }
  170.  
  171. /*****************************************************************************/
  172. /*                                         */
  173. /*    The graphics memory starts at B000:0000, and very unfortunately      */
  174. /*    is not mapped as you might expect.  Each row is simple.  A byte      */
  175. /*    controls 8 pixels, one bit per pixel, high-order bit controlling     */
  176. /*    the left-most pixel.  This continues sequentially accross the         */
  177. /*    row.  To find the address of the next row, however, is not so         */
  178. /*    easy.  By plotting many points, I finally came upon the algorithm    */
  179. /*    in the macro byte_addr(x,y) in the graphics.h file.  Essentially,    */
  180. /*    you add 0x2000 to get the next row unless you are greater than         */
  181. /*    0x8000 in which case you subtract 0x8000 and add 0x5a.    If         */
  182. /*    anybody understands why the screen was memory mapped in this         */
  183. /*    crazy way, please tell me.  I am very curious.                 */
  184. /*                                         */
  185. /*****************************************************************************/
  186.  
  187. grcls()
  188. {
  189.   memset(&screen[0], 0, 0x1eef);
  190.   memset(&screen[0x2000], 0, 0x1eef);
  191.   memset(&screen[0x4000], 0, 0x1eef);
  192.   memset(&screen[0x6000], 0, 0x1eef);
  193. }
  194.  
  195. fill_screen()
  196. {
  197.   memset(&screen[0], 0xff, 0x1eef);
  198.   memset(&screen[0x2000], 0xff, 0x1eef);
  199.   memset(&screen[0x4000], 0xff, 0x1eef);
  200.   memset(&screen[0x6000], 0xff, 0x1eef);
  201. }
  202.  
  203. cls()
  204. {
  205.   memset(screen, ' ', 2*80*25);
  206. }
  207.  
  208. dot(x,y,color)          /* color: 1-dot on;  0-dot off */
  209. int x;              /*    -1 is xor         */
  210. int y;
  211. int color;
  212. {
  213.   int index;
  214.   int bit_pos;
  215.  
  216.   index = byte_addr(x,y);
  217.   bit_pos = bit_pos(x);
  218.   if (color == WHITE) {
  219.     screen[index] |= bit_pos;
  220.   }
  221.   else if (color == BLACK) {
  222.     screen[index] &= ~bit_pos;
  223.   }
  224.   else if (color == XOR) {
  225.     screen [index] ^= bit_pos;
  226.   }
  227. }
  228.  
  229. /*****************************************************************************/
  230. /*                                         */
  231. /*         This routine is taken from BYTE March 1988 page 252         */
  232. /*                                         */
  233. /*****************************************************************************/
  234.  
  235. line(xstart,ystart,xend,yend,color)
  236. int xstart,ystart,xend,yend,color;
  237. {
  238.   int x,y,d,a,b,i;
  239.   int dx_diag, dy_diag, dx_nondiag, dy_nondiag;
  240.   int diag_inc, nondiag_inc;
  241.   int swap;
  242.   int index, bit_pos;
  243.  
  244.   x = xstart;
  245.   y = ystart;
  246.   a = xend - xstart;
  247.   b = yend - ystart;
  248.   if (a<0) {
  249.     a = -1 * a;
  250.     dx_diag = -1;
  251.   }
  252.   else {
  253.     dx_diag = 1;
  254.   }
  255.   if (b<0) {
  256.     b = -1 * b;
  257.     dy_diag = -1;
  258.   }
  259.   else {
  260.     dy_diag = 1;
  261.   }
  262.   if (a<b) {
  263.     swap = a;
  264.     a = b;
  265.     b = swap;
  266.     dx_nondiag = 0;
  267.     dy_nondiag = dy_diag;
  268.   }
  269.   else {
  270.     dx_nondiag = dx_diag;
  271.     dy_nondiag = 0;
  272.   }
  273.   d = b +b - a;
  274.   nondiag_inc = b + b;
  275.   diag_inc = b + b - a - a;
  276.   for (i=0; i<=a; i++) {
  277.     index = byte_addr(x,y);        /* This is an exact copy of the      */
  278.     bit_pos = bit_pos(x);        /* dot routine to subroutine calls   */
  279.     if (color == WHITE) {        /* which actually speeds up the      */
  280.       screen[index] |= bit_pos;     /* line routine 30%!!!             */
  281.     }
  282.     else if (color == BLACK) {
  283.       screen[index] &= ~bit_pos;
  284.     }
  285.     else if (color == XOR) {
  286.       screen [index] ^= bit_pos;
  287.     }
  288.     if (d<0) {
  289.       x = x + dx_nondiag;
  290.       y = y + dy_nondiag;
  291.       d = d + nondiag_inc;
  292.     }
  293.     else {
  294.       x = x + dx_diag;
  295.       y = y + dy_diag;
  296.       d = d + diag_inc;
  297.     }
  298.   }
  299. }
  300.  
  301. /*****************************************************************************/
  302. /*                                         */
  303. /*         This is the line routine I wrote which is about 20% slower      */
  304. /*         than the BYTE routine, so I'll keep it for prosperity, but      */
  305. /*         won't use it.                                                   */
  306. /*                                         */
  307. /*****************************************************************************/
  308.  
  309. line1(x1,y1,x2,y2,color)
  310. int x1,y1,x2,y2,color;
  311. {
  312.   int i;
  313.   int dx,dy;
  314.   int dxs,dys;
  315.  
  316.   dx = x2-x1;
  317.   dy = y2-y1;
  318.   dxs = ((dx >= 0) ? (1) : (-1));
  319.   dys = ((dy >= 0) ? (1) : (-1));
  320.   dx = dxs * dx;
  321.   dy = dys * dy;
  322.   if (dx == 0) {
  323.     for (i=y1; ((dys==1) ? (i<=y2) : (i>=y2)); i += dys) {
  324.       dot(x1,i,color);
  325.     }
  326.   }
  327.   else if (dy == 0) {
  328.     for (i=x1; ((dxs==1) ? (i<=x2) : (i>=x2)); i += dxs) {
  329.       dot(i,y1,color);
  330.     }
  331.   }
  332.   else {
  333.     if (dx >= dy) {
  334.       for (i=x1; ((dxs==1) ? (i<=x2) : (i>=x2)); i += dxs) {
  335.     dot(i,((dys==1) ? (y1+(dxs*(i-x1)*dy)/dx) : (y1-(dxs*(i-x1)*dy)/dx)),color);
  336.       }
  337.     }
  338.     else {
  339.       for (i=y1; ((dys==1) ? (i<=y2) : (i>=y2)); i += dys) {
  340.     dot(((dxs==1) ? (x1+(dys*(i-y1)*dx)/dy) : (x1-(dys*(i-y1)*dx)/dy)),i,color);
  341.       }
  342.     }
  343.   }
  344. }
  345.  
  346. /*****************************************************************************/
  347. /*                                         */
  348. /* Module Name: draw                                 */
  349. /*                                         */
  350. /* Function: Draw draws the specified shape at the specified coordinates     */
  351. /*         in the specified color (white, black, or xor).  It does not     */
  352. /*         have to be on a byte boundary.                     */
  353. /*                                         */
  354. /*****************************************************************************/
  355.  
  356. draw(shape,x,y,color)
  357. struct shape_type shape;
  358. int x;
  359. int y;
  360. int color;
  361. {
  362.   int a;
  363.   int i;
  364.   int j;
  365.   int temp;
  366.   int scr_index;
  367.   int temp_index;
  368.   int shift_num;
  369.  
  370.   scr_index = byte_addr(x,y);
  371.   shift_num = bit_num(x);
  372.   for (i=0; i<shape.x; i++) {
  373.     temp_index = scr_index;
  374.     for (j=0; j<shape.y; j++) {
  375.       a = shape.shape_array[shape.x-i-1+j*shape.x] & 0xff;
  376.       temp = a >> shift_num;
  377.       if (color == OVERWRITE) {
  378.     screen[temp_index+shape.x-i] = (a^(temp << shift_num)) << (8-shift_num);
  379.     screen[temp_index+shape.x-i-1] = temp;
  380.       }
  381.       else if (color == WHITE) {
  382.     screen[temp_index+shape.x-i] |= (a^(temp << shift_num)) << (8-shift_num);
  383.     screen[temp_index+shape.x-i-1] |= temp;
  384.       }
  385.       else if (color == BLACK) {
  386.     screen[temp_index+shape.x-i] &= ~((a^(temp << shift_num)) << (8-shift_num));
  387.     screen[temp_index+shape.x-i-1] &= ~temp;
  388.       }
  389.       else if (color == XOR) {
  390.     screen[temp_index+shape.x-i] ^= (a^(temp << shift_num)) << (8-shift_num);
  391.     screen[temp_index+shape.x-i-1] ^= temp;
  392.       }
  393.       temp_index += 0x2000;
  394.       if (temp_index > 0x8000) {
  395.     temp_index = temp_index - 0x8000 + 0x5a;
  396.       }
  397.     }
  398.   }
  399. }
  400.  
  401. /*****************************************************************************/
  402. /*                                         */
  403. /* Module Name: draw_block                             */
  404. /*                                         */
  405. /* Function: Draw draws the specified shape at the specified coordinates     */
  406. /*         in the specified color (white, black, or xor).  You must         */
  407. /*         draw on byte boundaries only.  This is because this routine     */
  408. /*         does not shift bits at all.  It simply copies from the         */
  409. /*         shape structure directly to the screen.  Because of this,         */
  410. /*         it is very FAST.                             */
  411. /*                                         */
  412. /*****************************************************************************/
  413.  
  414. draw_block(shape,x,y,color)
  415. struct shape_type shape;
  416. int x;
  417. int y;
  418. int color;
  419. {
  420.   int i;
  421.   int j;
  422.   int scr_index;
  423.  
  424.   scr_index = byte_addr(x,y);
  425.   for (j=0; j<shape.y; j++) {
  426.     switch (color) {
  427.       case OVERWRITE:
  428.     memmove(&screen[scr_index], &shape.shape_array[j*shape.x], shape.x);
  429.     break;
  430.       case WHITE:
  431.     for (i=0; i<shape.x; i++) {
  432.       screen[scr_index+i] |= shape.shape_array[j*shape.x + i];
  433.     }
  434.     break;
  435.       case BLACK:
  436.     for (i=0; i<shape.x; i++) {
  437.       screen[scr_index+i] &= ~(shape.shape_array[j*shape.x + i]);
  438.     }
  439.     break;
  440.       case XOR:
  441.     for (i=0; i<shape.x; i++) {
  442.       screen[scr_index+i] ^= shape.shape_array[j*shape.x + i];
  443.     }
  444.     break;
  445.     }
  446.     scr_index += 0x2000;
  447.     if (scr_index > 0x8000) {
  448.       scr_index = scr_index - 0x8000 + 0x5a;
  449.     }
  450.   }
  451. }
  452.  
  453. shift_up(shape,x,y,shift_num)
  454. struct shape_type shape;
  455. int x;
  456. int y;
  457. int shift_num;
  458. {
  459. }
  460.  
  461. shift_down(shape,x,y,shift_num)
  462. struct shape_type shape;
  463. int x;
  464. int y;
  465. int shift_num;
  466. {
  467. }
  468.  
  469. shift_left(shape,x,y,shift_num)
  470. struct shape_type shape;
  471. int x;
  472. int y;
  473. int shift_num;
  474. {
  475. }
  476. /*****************************************************************************/
  477. /*                                         */
  478. /* Module Name: shift_right                             */
  479. /*                                         */
  480. /* Function: Shifts the rectangle whose upper-left corner is at x,y and      */
  481. /*         whose size is determined by the size of shape shift_num         */
  482. /*         pixels to the right, with a maximum shift_num of 8.  It is      */
  483. /*         not too fast because it computes the addresses of all pixels    */
  484. /*         in every call, and it has to shift the bits from byte into      */
  485. /*         the next.    To shift right by 8 pixels (one byte), use the         */
  486. /*         routine shift_right_block which does not have to shift pixels,  */
  487. /*         but can just move a byte of memory.                 */
  488. /*                                         */
  489. /*****************************************************************************/
  490.  
  491. shift_right(shape,x,y,shift_num)
  492. struct shape_type shape;
  493. int x;
  494. int y;
  495. int shift_num;
  496. {
  497.   int a;
  498.   int b;
  499.   int i;
  500.   int j;
  501.   int temp;
  502.   int scr_index;
  503.   int temp_index;
  504.  
  505.   scr_index = byte_addr(x,y);
  506.   for (i=0; i<shape.x+2; i++) {
  507.     temp_index = scr_index;
  508.     for (j=0; j<shape.y; j++) {
  509.       a = screen[temp_index + shape.x-i] & 0xff;
  510.       b = screen[temp_index + shape.x-i+1] & 0xff;
  511.       temp = a >> shift_num;
  512.       screen[temp_index+shape.x-i+1] = b >> shift_num;
  513.       screen[temp_index+shape.x-i+1] |= (a^(temp << shift_num)) << (8-shift_num);
  514.       temp_index += 0x2000;
  515.       if (temp_index > 0x8000) {
  516.     temp_index = temp_index - 0x8000 + 0x5a;
  517.       }
  518.     }
  519.   }
  520. }
  521.  
  522. /*****************************************************************************/
  523. /*                                         */
  524. /* Module Name: shift_xxx_block                          */
  525. /*                                         */
  526. /* Function: The shift block routines shift a specified shape by 8 bits      */
  527. /*         in any direction.    The shape must be "left-justified" on a      */
  528. /*         byte boundary.  That means, drawing the shape at x-coord         */
  529. /*         16, 24, 32, etc. is ok, but not 25 (unless you want to shift    */
  530. /*         extra pixels).                             */
  531. /*                                         */
  532. /*         These are the FASTEST way to move shape around.             */
  533. /*                                         */
  534. /*****************************************************************************/
  535.  
  536. shift_up_block(shape,x,y)
  537. struct shape_type shape;
  538. int x;
  539. int y;
  540. {
  541.   int i;
  542.   int old_index;
  543.   int scr_index;
  544.  
  545.   old_index = byte_addr(x,y);
  546.   scr_index = old_index - 2*0x5a;
  547.   for (i=0; i<shape.y; i++) {
  548.     memmove(screen+scr_index, screen+old_index, shape.x);
  549.     old_index += 0x2000;
  550.     if (old_index > 0x8000) {
  551.       old_index = old_index - 0x8000 + 0x5a;
  552.     }
  553.     scr_index += 0x2000;
  554.     if (scr_index > 0x8000) {
  555.       scr_index = scr_index - 0x8000 + 0x5a;
  556.     }
  557.   }
  558.   scr_index = byte_addr(x,y+shape.y-1);
  559.   for (i=0; i<8; i++) {
  560.     memset(screen+scr_index,0,shape.x);
  561.     scr_index -= 0x2000;
  562.     if (scr_index < 0) {
  563.       scr_index = scr_index + 0x8000 - 0x5a;
  564.     }
  565.   }
  566. }
  567.  
  568. shift_down_block(shape,x,y)
  569. struct shape_type shape;
  570. int x;
  571. int y;
  572. {
  573.   int i;
  574.   int old_index;
  575.   int scr_index;
  576.  
  577.   old_index = byte_addr(x,y+shape.y-1);
  578.   scr_index = old_index + 2*0x5a;
  579.   for (i=0; i<shape.y; i++) {
  580.     memmove(screen+scr_index, screen+old_index, shape.x);
  581.     old_index -= 0x2000;
  582.     if (old_index < 0) {
  583.       old_index = old_index + 0x8000 - 0x5a;
  584.     }
  585.     scr_index -= 0x2000;
  586.     if (scr_index < 0) {
  587.       scr_index = scr_index + 0x8000 - 0x5a;
  588.     }
  589.   }
  590.   scr_index = byte_addr(x,y);
  591.   for (i=0; i<8; i++) {
  592.     memset(screen+scr_index,0,shape.x);
  593.     scr_index += 0x2000;
  594.     if (scr_index > 0x8000) {
  595.       scr_index = scr_index - 0x8000 + 0x5a;
  596.     }
  597.   }
  598. }
  599.  
  600. shift_left_block(shape,x,y)
  601. struct shape_type shape;
  602. int x;
  603. int y;
  604. {
  605.   int i;
  606.   int scr_index;
  607.  
  608.   scr_index = byte_addr(x,y);
  609.   for (i=0; i<shape.y; i++) {
  610.     memmove(screen+scr_index-1, screen+scr_index, shape.x);
  611.     screen[scr_index + shape.x - 1] = 0;
  612.     scr_index += 0x2000;
  613.     if (scr_index > 0x8000) {
  614.       scr_index = scr_index - 0x8000 + 0x5a;
  615.     }
  616.   }
  617. }
  618.  
  619. shift_right_block(shape,x,y)
  620. struct shape_type shape;
  621. int x;
  622. int y;
  623. {
  624.   int i;
  625.   int scr_index;
  626.  
  627.   scr_index = byte_addr(x,y);
  628.   for (i=0; i<shape.y; i++) {
  629.     memmove(screen+scr_index+1, screen+scr_index, shape.x);
  630.     screen[scr_index] = 0;
  631.     scr_index += 0x2000;
  632.     if (scr_index > 0x8000) {
  633.       scr_index = scr_index - 0x8000 + 0x5a;
  634.     }
  635.   }
  636. }
  637.