/* programme test d'animation par recouvrement de rectangle. N'essaie pas de fusionner les rectangles pour minimiser les accès en mémoire vidéo. N'est même pas optimisé! Testé avec Borland C++ 4.02 en modèle small par Jim Mischel 12/16/94. */ #include #include #include #include #include #define SCREEN_WIDTH 320 #define SCREEN_HEIGHT 200 #define SCREEN_SEGMENT 0xA000 /* Décrit un rectangle */ typedef struct { int Top; int Left; int Right; int Bottom; } Rectangle; /* Décrit un objet animé */ typedef struct { int X; /* coin supérieur gauche dans la bitmap virtuelle */ int Y; int XDirection; /* direction et distance du mouvement */ int YDirection; } Entity; /* Stockage utilisé pour les rectangles par recouvrement */ #define MAX_DIRTY_RECTANGLES 100 int NumDirtyRectangles; Rectangle DirtyRectangles[MAX_DIRTY_RECTANGLES]; /* Si à 1, ignore la liste des rectangles par recouvrement et copie tout l'écran. */ int DrawWholeScreen = 0; /* Pixels pour l'image que nous animerons */ #define IMAGE_WIDTH 11 #define IMAGE_HEIGHT 11 char ImagePixels[] = { 15,15,15, 9, 9, 9, 9, 9,15,15,15, 15,15, 9, 9, 9, 9, 9, 9, 9,15,15, 15, 9, 9,14,14,14,14,14, 9, 9,15, 9, 9,14,14,14,14,14,14,14, 9, 9, 9, 9,14,14,14,14,14,14,14, 9, 9, 9, 9,14,14,14,14,14,14,14, 9, 9, 9, 9,14,14,14,14,14,14,14, 9, 9, 9, 9,14,14,14,14,14,14,14, 9, 9, 15, 9, 9,14,14,14,14,14, 9, 9,15, 15,15, 9, 9, 9, 9, 9, 9, 9,15,15, 15,15,15, 9, 9, 9, 9, 9,15,15,15, }; /* Entités animées */ #define NUM_ENTITIES 10 Entity Entities[NUM_ENTITIES]; /* Pointeur sur le tampon système dans lequel nous afficherons */ char far *SystemBufferPtr; /* Pointeur sur l'écran */ char far *ScreenPtr; void EraseEntities(void); void CopyDirtyRectanglesToScreen(void); void DrawEntities(void); void main() { int i, XTemp, YTemp; unsigned int TempCount; char far *TempPtr; union REGS regs; /* Alloue de la mémoire au tampon système dans lequel nous afficherons */ if (!(SystemBufferPtr = farmalloc((unsigned int)SCREEN_WIDTH* SCREEN_HEIGHT))) { printf("Couldn't get memory\n"); exit(1); } /* Vide le tampon système */ TempPtr = SystemBufferPtr; for (TempCount = ((unsigned)SCREEN_WIDTH*SCREEN_HEIGHT); TempCount--; ) { *TempPtr++ = 0; } /* Pointe sur l'écran */ ScreenPtr = MK_FP(SCREEN_SEGMENT, 0); /* Configure les entités que nous animerons, à des emplacements aléatoires */ randomize(); for (i = 0; i < NUM_ENTITIES; i++) { Entities[i].X = random(SCREEN_WIDTH - IMAGE_WIDTH); Entities[i].Y = random(SCREEN_HEIGHT - IMAGE_HEIGHT); Entities[i].XDirection = 1; Entities[i].YDirection = -1; } /* Paramètre le mode graphique 320x200 en 256 couleurs */ regs.x.ax = 0x0013; int86(0x10, ®s, ®s); /* Effectue une boucle et affiche jusqu'à une touche clavier */ do { /* Affiche les entités dans le tampon système à leur emplacement courant, en mettant à jour la liste des rectangles par recouvrement */ DrawEntities(); /* Affiche les rectangles par recouvrement, ou tout le tampon système si nécessaire*/ CopyDirtyRectanglesToScreen(); /* Réinitialise la liste des rectangles par recouvrement pour vider */ NumDirtyRectangles = 0; /* Supprime les entités dans le tampon système à leur ancien emplacement, en mettant à jour la liste des rectangles par recouvrement */ EraseEntities(); /* Déplace les entités, en rebondissant sur les cotés de l'écran */ for (i = 0; i < NUM_ENTITIES; i++) { XTemp = Entities[i].X + Entities[i].XDirection; YTemp = Entities[i].Y + Entities[i].YDirection; if ((XTemp < 0) || ((XTemp + IMAGE_WIDTH) > SCREEN_WIDTH)) { Entities[i].XDirection = -Entities[i].XDirection; XTemp = Entities[i].X + Entities[i].XDirection; } if ((YTemp < 0) || ((YTemp + IMAGE_HEIGHT) > SCREEN_HEIGHT)) { Entities[i].YDirection = -Entities[i].YDirection; YTemp = Entities[i].Y + Entities[i].YDirection; } Entities[i].X = XTemp; Entities[i].Y = YTemp; } } while (!kbhit()); getch(); /* clear the keypress */ /* Revient en mode texte */ regs.x.ax = 0x0003; int86(0x10, ®s, ®s); } /* Affiche les entités à leur emplacement courant, en mettant à jour la liste des rectangles par recouvrement. */ void DrawEntities() { int i, j, k; char far *RowPtrBuffer; char far *TempPtrBuffer; char far *TempPtrImage; for (i = 0; i < NUM_ENTITIES; i++) { /* Mémorise l'info du rectangle par recouvrement pour cette entité */ if (NumDirtyRectangles >= MAX_DIRTY_RECTANGLES) { /*Il y a trop de rectangles par recouvrement; réaffichons seulement tout l'écran */ DrawWholeScreen = 1; } else { /* Mémorise ce rectangle par recouvrement */ DirtyRectangles[NumDirtyRectangles].Left = Entities[i].X; DirtyRectangles[NumDirtyRectangles].Top = Entities[i].Y; DirtyRectangles[NumDirtyRectangles].Right = Entities[i].X + IMAGE_WIDTH; DirtyRectangles[NumDirtyRectangles++].Bottom = Entities[i].Y + IMAGE_HEIGHT; } /* Pointe sur la destination dans le tampon système */ RowPtrBuffer = SystemBufferPtr + (Entities[i].Y * SCREEN_WIDTH) + Entities[i].X; /* Pointe sur l'image à afficher*/ TempPtrImage = ImagePixels; /* Copie l'image dans le tampon système */ for (j = 0; j < IMAGE_HEIGHT; j++) { /* Copie une rangée */ for (k = 0, TempPtrBuffer = RowPtrBuffer; k < IMAGE_WIDTH; k++) { *TempPtrBuffer++ = *TempPtrImage++; } /* Pointe sur la prochaine rangée du tampon système */ RowPtrBuffer += SCREEN_WIDTH; } } } /* Copie les rectangles par recouvrement, ou tout le tampon système si nécessaire, sur l'écran. */ void CopyDirtyRectanglesToScreen() { int i, j, k, RectWidth, RectHeight; unsigned int TempCount; unsigned int Offset; char far *TempPtrScreen; char far *TempPtrBuffer; if (DrawWholeScreen) { /* Copie seulement tout le tampon système sur l'écran */ DrawWholeScreen = 0; TempPtrScreen = ScreenPtr; TempPtrBuffer = SystemBufferPtr; for (TempCount = ((unsigned)SCREEN_WIDTH*SCREEN_HEIGHT); TempCount--; ) { *TempPtrScreen++ = *TempPtrBuffer++; } } else { /* Copie seulement les rectangles par recouvrement */ for (i = 0; i < NumDirtyRectangles; i++) { /* Offset à la fois dans le tampon système et dans l'écran de l'image */ Offset = (unsigned int) (DirtyRectangles[i].Top * SCREEN_WIDTH) + DirtyRectangles[i].Left; /* Dimensions du rectangle par recouvrement */ RectWidth = DirtyRectangles[i].Right - DirtyRectangles[i].Left; RectHeight = DirtyRectangles[i].Bottom - DirtyRectangles[i].Top; /* Copy a dirty rectangle */ for (j = 0; j < RectHeight; j++) { /* Pointe sur le début de la rangée sur l'écran */ TempPtrScreen = ScreenPtr + Offset; /* Pointe sur le début de la rangée dans le tampon système */ TempPtrBuffer = SystemBufferPtr + Offset; /* Copie une rangée */ for (k = 0; k < RectWidth; k++) { *TempPtrScreen++ = *TempPtrBuffer++; } /* Pointe sur la prochaine rangée */ Offset += SCREEN_WIDTH; } } } } /* Supprime les entités dans le tampon système à leur emplacement courant, en mettant à jour la liste des rectangles par recouvrement. */ void EraseEntities() { int i, j, k; char far *RowPtr; char far *TempPtr; for (i = 0; i < NUM_ENTITIES; i++) { /* Mémorise l'info du rectangle par recouvrement pour cette entité */ if (NumDirtyRectangles >= MAX_DIRTY_RECTANGLES) { /* Il y a trop de rectangles par recouvrement; réaffichons seulement tout l'écran */ DrawWholeScreen = 1; } else { /* mémorise ce rectangle par recouvrement */ DirtyRectangles[NumDirtyRectangles].Left = Entities[i].X; DirtyRectangles[NumDirtyRectangles].Top = Entities[i].Y; DirtyRectangles[NumDirtyRectangles].Right = Entities[i].X + IMAGE_WIDTH; DirtyRectangles[NumDirtyRectangles++].Bottom = Entities[i].Y + IMAGE_HEIGHT; } /* Pointe sur la destination dans le tampon système */ RowPtr = SystemBufferPtr + (Entities[i].Y*SCREEN_WIDTH) + Entities[i].X; /* Efface le rectangle de l'entité */ for (j = 0; j < IMAGE_HEIGHT; j++) { /* Efface la rangée */ for (k = 0, TempPtr = RowPtr; k < IMAGE_WIDTH; k++) { *TempPtr++ = 0; } /* Pointe sur la prochaine rangée */ RowPtr += SCREEN_WIDTH; } } }