home *** CD-ROM | disk | FTP | other *** search
/ Graphics Programming Black Book (Special Edition) / BlackBook.bin / disk1 / source / chapter45 / l45-1.c next >
Encoding:
C/C++ Source or Header  |  1997-06-18  |  8.6 KB  |  260 lines

  1. /* Sample simple dirty-rectangle animation program. Doesn't attempt to coalesce
  2.    rectangles to minimize display memory accesses. Not even vaguely optimized!
  3.    Tested with Borland C++ 4.02 in small model. by Jim Mischel 12/16/94.
  4. */
  5. #include <stdlib.h>
  6. #include <conio.h>
  7. #include <alloc.h>
  8. #include <memory.h>
  9. #include <dos.h>
  10.  
  11. #define SCREEN_WIDTH  320
  12. #define SCREEN_HEIGHT 200
  13. #define SCREEN_SEGMENT 0xA000
  14.  
  15. /* Describes a rectangle */
  16. typedef struct {
  17.    int Top;
  18.    int Left;
  19.    int Right;
  20.    int Bottom;
  21. } Rectangle;
  22.  
  23. /* Describes an animated object */
  24. typedef struct {
  25.    int X;            /* upper left corner in virtual bitmap */
  26.    int Y;
  27.    int XDirection;   /* direction and distance of movement */
  28.    int YDirection;
  29. } Entity;
  30.  
  31. /* Storage used for dirty rectangles */
  32. #define MAX_DIRTY_RECTANGLES  100
  33. int NumDirtyRectangles;
  34. Rectangle DirtyRectangles[MAX_DIRTY_RECTANGLES];
  35.  
  36. /* If set to 1, ignore dirty rectangle list and copy the whole screen. */
  37. int DrawWholeScreen = 0;
  38.  
  39. /* Pixels for image we'll animate */
  40. #define IMAGE_WIDTH  11
  41. #define IMAGE_HEIGHT 11
  42. char ImagePixels[] = {
  43.   15,15,15, 9, 9, 9, 9, 9,15,15,15,
  44.   15,15, 9, 9, 9, 9, 9, 9, 9,15,15,
  45.   15, 9, 9,14,14,14,14,14, 9, 9,15,
  46.    9, 9,14,14,14,14,14,14,14, 9, 9,
  47.    9, 9,14,14,14,14,14,14,14, 9, 9,
  48.    9, 9,14,14,14,14,14,14,14, 9, 9,
  49.    9, 9,14,14,14,14,14,14,14, 9, 9,
  50.    9, 9,14,14,14,14,14,14,14, 9, 9,
  51.   15, 9, 9,14,14,14,14,14, 9, 9,15,
  52.   15,15, 9, 9, 9, 9, 9, 9, 9,15,15,
  53.   15,15,15, 9, 9, 9, 9, 9,15,15,15,
  54. };
  55. /* Animated entities */
  56. #define NUM_ENTITIES 10
  57. Entity Entities[NUM_ENTITIES];
  58.  
  59. /* Pointer to system buffer into which we'll draw */
  60. char far *SystemBufferPtr;
  61.  
  62. /* Pointer to screen */
  63. char far *ScreenPtr;
  64.  
  65. void EraseEntities(void);
  66. void CopyDirtyRectanglesToScreen(void);
  67. void DrawEntities(void);
  68.  
  69. void main()
  70. {
  71.    int i, XTemp, YTemp;
  72.    unsigned int TempCount;
  73.    char far *TempPtr;
  74.    union REGS regs;
  75.    /* Allocate memory for the system buffer into which we'll draw */
  76.    if (!(SystemBufferPtr = farmalloc((unsigned int)SCREEN_WIDTH*
  77.          SCREEN_HEIGHT))) {
  78.       printf("Couldn't get memory\n");
  79.       exit(1);
  80.    }
  81.    /* Clear the system buffer */
  82.    TempPtr = SystemBufferPtr;
  83.    for (TempCount = ((unsigned)SCREEN_WIDTH*SCREEN_HEIGHT); TempCount--; ) {
  84.       *TempPtr++ = 0;
  85.    }
  86.    /* Point to the screen */
  87.    ScreenPtr = MK_FP(SCREEN_SEGMENT, 0);
  88.  
  89.    /* Set up the entities we'll animate, at random locations */
  90.    randomize();
  91.    for (i = 0; i < NUM_ENTITIES; i++) {
  92.       Entities[i].X = random(SCREEN_WIDTH - IMAGE_WIDTH);
  93.       Entities[i].Y = random(SCREEN_HEIGHT - IMAGE_HEIGHT);
  94.       Entities[i].XDirection = 1;
  95.       Entities[i].YDirection = -1;
  96.    }
  97.    /* Set 320x200 256-color graphics mode */
  98.    regs.x.ax = 0x0013;
  99.    int86(0x10, ®s, ®s);
  100.  
  101.    /* Loop and draw until a key is pressed */
  102.    do {
  103.       /* Draw the entities to the system buffer at their current locations,
  104.          updating the dirty rectangle list */
  105.       DrawEntities();
  106.  
  107.       /* Draw the dirty rectangles, or the whole system buffer if
  108.          appropriate */
  109.       CopyDirtyRectanglesToScreen();
  110.  
  111.       /* Reset the dirty rectangle list to empty */
  112.       NumDirtyRectangles = 0;
  113.  
  114.       /* Erase the entities in the system buffer at their old locations,
  115.          updating the dirty rectangle list */
  116.       EraseEntities();
  117.  
  118.       /* Move the entities, bouncing off the edges of the screen */
  119.       for (i = 0; i < NUM_ENTITIES; i++) {
  120.          XTemp = Entities[i].X + Entities[i].XDirection;
  121.          YTemp = Entities[i].Y + Entities[i].YDirection;
  122.          if ((XTemp < 0) || ((XTemp + IMAGE_WIDTH) > SCREEN_WIDTH)) {
  123.             Entities[i].XDirection = -Entities[i].XDirection;
  124.             XTemp = Entities[i].X + Entities[i].XDirection;
  125.          }
  126.          if ((YTemp < 0) || ((YTemp + IMAGE_HEIGHT) > SCREEN_HEIGHT)) {
  127.             Entities[i].YDirection = -Entities[i].YDirection;
  128.             YTemp = Entities[i].Y + Entities[i].YDirection;
  129.          }
  130.          Entities[i].X = XTemp;
  131.          Entities[i].Y = YTemp;
  132.       }
  133.  
  134.    } while (!kbhit());
  135.    getch();    /* clear the keypress */
  136.    /* Back to text mode */
  137.    regs.x.ax = 0x0003;
  138.    int86(0x10, ®s, ®s);
  139. }
  140. /* Draw entities at current locations, updating dirty rectangle list. */
  141. void DrawEntities()
  142. {
  143.    int i, j, k;
  144.    char far *RowPtrBuffer;
  145.    char far *TempPtrBuffer;
  146.    char far *TempPtrImage;
  147.    for (i = 0; i < NUM_ENTITIES; i++) {
  148.       /* Remember the dirty rectangle info for this entity */
  149.       if (NumDirtyRectangles >= MAX_DIRTY_RECTANGLES) {
  150.          /* Too many dirty rectangles; just redraw the whole screen */
  151.          DrawWholeScreen = 1;
  152.       } else {
  153.          /* Remember this dirty rectangle */
  154.          DirtyRectangles[NumDirtyRectangles].Left = Entities[i].X;
  155.          DirtyRectangles[NumDirtyRectangles].Top = Entities[i].Y;
  156.          DirtyRectangles[NumDirtyRectangles].Right =
  157.                Entities[i].X + IMAGE_WIDTH;
  158.          DirtyRectangles[NumDirtyRectangles++].Bottom =
  159.                Entities[i].Y + IMAGE_HEIGHT;
  160.       }
  161.       /* Point to the destination in the system buffer */
  162.       RowPtrBuffer = SystemBufferPtr + (Entities[i].Y * SCREEN_WIDTH) +
  163.             Entities[i].X;
  164.       /* Point to the image to draw */
  165.       TempPtrImage = ImagePixels;
  166.       /* Copy the image to the system buffer */
  167.       for (j = 0; j < IMAGE_HEIGHT; j++) {
  168.          /* Copy a row */
  169.          for (k = 0, TempPtrBuffer = RowPtrBuffer; k < IMAGE_WIDTH; k++) {
  170.             *TempPtrBuffer++ = *TempPtrImage++;
  171.          }
  172.          /* Point to the next system buffer row */
  173.          RowPtrBuffer += SCREEN_WIDTH;
  174.       }
  175.    }
  176. }
  177. /* Copy the dirty rectangles, or the whole system buffer if appropriate,
  178.    to the screen. */
  179. void CopyDirtyRectanglesToScreen()
  180. {
  181.    int i, j, k, RectWidth, RectHeight;
  182.    unsigned int TempCount;
  183.    unsigned int Offset;
  184.    char far *TempPtrScreen;
  185.    char far *TempPtrBuffer;
  186.  
  187.    if (DrawWholeScreen) {
  188.       /* Just copy the whole buffer to the screen */
  189.       DrawWholeScreen = 0;
  190.       TempPtrScreen = ScreenPtr;
  191.       TempPtrBuffer = SystemBufferPtr;
  192.       for (TempCount = ((unsigned)SCREEN_WIDTH*SCREEN_HEIGHT); TempCount--; ) {
  193.          *TempPtrScreen++ = *TempPtrBuffer++;
  194.       }
  195.    } else {
  196.       /* Copy only the dirty rectangles */
  197.       for (i = 0; i < NumDirtyRectangles; i++) {
  198.          /* Offset in both system buffer and screen of image */
  199.          Offset = (unsigned int) (DirtyRectangles[i].Top * SCREEN_WIDTH) +
  200.                DirtyRectangles[i].Left;
  201.          /* Dimensions of dirty rectangle */
  202.          RectWidth = DirtyRectangles[i].Right - DirtyRectangles[i].Left;
  203.          RectHeight = DirtyRectangles[i].Bottom - DirtyRectangles[i].Top;
  204.          /* Copy a dirty rectangle */
  205.          for (j = 0; j < RectHeight; j++) {
  206.  
  207.             /* Point to the start of row on screen */
  208.             TempPtrScreen = ScreenPtr + Offset;
  209.  
  210.             /* Point to the start of row in system buffer */
  211.             TempPtrBuffer = SystemBufferPtr + Offset;
  212.  
  213.             /* Copy a row */
  214.             for (k = 0; k < RectWidth; k++) {
  215.                *TempPtrScreen++ = *TempPtrBuffer++;
  216.             }
  217.             /* Point to the next row */
  218.             Offset += SCREEN_WIDTH;
  219.          }
  220.       }
  221.    }
  222. }
  223. /* Erase the entities in the system buffer at their current locations,
  224.    updating the dirty rectangle list. */
  225. void EraseEntities()
  226. {
  227.    int i, j, k;
  228.    char far *RowPtr;
  229.    char far *TempPtr;
  230.  
  231.    for (i = 0; i < NUM_ENTITIES; i++) {
  232.       /* Remember the dirty rectangle info for this entity */
  233.       if (NumDirtyRectangles >= MAX_DIRTY_RECTANGLES) {
  234.          /* Too many dirty rectangles; just redraw the whole screen */
  235.          DrawWholeScreen = 1;
  236.       } else {
  237.          /* Remember this dirty rectangle */
  238.          DirtyRectangles[NumDirtyRectangles].Left = Entities[i].X;
  239.          DirtyRectangles[NumDirtyRectangles].Top = Entities[i].Y;
  240.          DirtyRectangles[NumDirtyRectangles].Right =
  241.                Entities[i].X + IMAGE_WIDTH;
  242.          DirtyRectangles[NumDirtyRectangles++].Bottom =
  243.                Entities[i].Y + IMAGE_HEIGHT;
  244.       }
  245.       /* Point to the destination in the system buffer */
  246.       RowPtr = SystemBufferPtr + (Entities[i].Y*SCREEN_WIDTH) + Entities[i].X;
  247.  
  248.       /* Clear the entity's rectangle */
  249.       for (j = 0; j < IMAGE_HEIGHT; j++) {
  250.          /* Clear a row */
  251.          for (k = 0, TempPtr = RowPtr; k < IMAGE_WIDTH; k++) {
  252.             *TempPtr++ = 0;
  253.          }
  254.          /* Point to the next row */
  255.          RowPtr += SCREEN_WIDTH;
  256.       }
  257.    }
  258. }
  259.  
  260.