/* Programme d'animation 3D affichant un cube en rotation en Mode X. Le point de vue est à l'origine (0,0,0) de l'espace monde, l'observateur regarde dans le sens des Z négatifs croissants. Le système de coordonnées main-droite est utilisé. Testé avec Borland C++ 4.02 en modèle small par Jim Mischel 12/16/94. */ #include #include #include #include "polygon.h" #define ROTATION (M_PI / 30.0) /* effectue une rotation de 6 degrés */ /* Offset de base de la page dans laquelle afficher */ unsigned int CurrentPageBase = 0; /* Rectangle de clipping; clippe l'écran*/ int ClipMinX=0, ClipMinY=0; int ClipMaxX=SCREEN_WIDTH, ClipMaxY=SCREEN_HEIGHT; /* Rectangle spécifiant la superficie à effacer dans chaque page */ struct Rect EraseRect[2] = { {0, 0, SCREEN_WIDTH, SCREEN_HEIGHT}, {0, 0, SCREEN_WIDTH, SCREEN_HEIGHT} }; static unsigned int PageStartOffsets[2] = {PAGE0_START_OFFSET,PAGE1_START_OFFSET}; int DisplayedPage, NonDisplayedPage; /* Transformation du cube de l'espace objet dans l'espace monde. Configuré initialement pour ne pas faire de rotation et pour déplacer le cube dans l'espace monde de -100 unités de l'origine selon l'axe des Z. En fonction du point de vue -100 selon l'axe des Z signifie une distance à l'observateur accrue de 100 unités. Le programme change de manière dynamique la translation et la rotation. */ static double CubeWorldXform[4][4] = { {1.0, 0.0, 0.0, 0.0}, {0.0, 1.0, 0.0, 0.0}, {0.0, 0.0, 1.0, -100.0}, {0.0, 0.0, 0.0, 1.0} }; /* Transformation de l'espace monde dans l'espace de visualisation. Comme dans cette application le point de vue est fixé à l'origine de l'espace monde, en regardant l'axe Z dans le sens des Z croissants, l'espace monde est identique à l'espace de visualisation, c'est la matrice identité */ static double WorldViewXform[4][4] = { {1.0, 0.0, 0.0, 0.0}, {0.0, 1.0, 0.0, 0.0}, {0.0, 0.0, 1.0, 0.0}, {0.0, 0.0, 0.0, 1.0} }; /* Tous les points du cube */ static struct Point3 CubeVerts[] = { {15,15,15,1},{15,15,-15,1},{15,-15,15,1},{15,-15,-15,1}, {-15,15,15,1},{-15,15,-15,1},{-15,-15,15,1},{-15,-15,-15,1}}; /* Points après transformation */ static struct Point3 XformedCubeVerts[sizeof(CubeVerts)/sizeof(struct Point3)]; /* Points après projection */ static struct Point3 ProjectedCubeVerts[sizeof(CubeVerts)/sizeof(struct Point3)]; /* Point dans les coordonnées de l'écran */ static struct Point ScreenCubeVerts[sizeof(CubeVerts)/sizeof(struct Point3)]; /* Indices des points pour les faces */ static int Face1[] = {1,3,2,0}; static int Face2[] = {5,7,3,1}; static int Face3[] = {4,5,1,0}; static int Face4[] = {3,7,6,2}; static int Face5[] = {5,4,6,7}; static int Face6[] = {0,2,6,4}; /* Liste des faces du cube*/ static struct Face CubeFaces[] = {{Face1,4,15},{Face2,4,14}, {Face3,4,12},{Face4,4,11},{Face5,4,10},{Face6,4,9}}; /* Description principale du cube */ static struct Object Cube = {sizeof(CubeVerts)/sizeof(struct Point3), CubeVerts, XformedCubeVerts, ProjectedCubeVerts, ScreenCubeVerts, sizeof(CubeFaces)/sizeof(struct Face), CubeFaces}; void main() { int Done = 0, RecalcXform = 1; double WorkingXform[4][4]; union REGS regset; /* Configure la transformation initiale */ Set320x240Mode(); /* set the screen to Mode X */ ShowPage(PageStartOffsets[DisplayedPage = 0]); /* La transformation du cube se poursuit, en le traçant dans la page offscreen, et en permutant page pour l'afficher */ do { /* Régénère la transformation objet->visualisation et retransforme/projette si nécessaire */ if (RecalcXform) { ConcatXforms(WorldViewXform, CubeWorldXform, WorkingXform); /* Transforme et projette tous les points du cube */ XformAndProjectPoints(WorkingXform, &Cube); RecalcXform = 0; } CurrentPageBase = /* sélectionne l'autre page dans laquelle afficher */ PageStartOffsets[NonDisplayedPage = DisplayedPage ^ 1]; /* Vide la partie de la page offscreen qui a été affichée en dernier, puis réinitialise la superficie à effacer */ FillRectangleX(EraseRect[NonDisplayedPage].Left, EraseRect[NonDisplayedPage].Top, EraseRect[NonDisplayedPage].Right, EraseRect[NonDisplayedPage].Bottom, CurrentPageBase, 0); EraseRect[NonDisplayedPage].Left = EraseRect[NonDisplayedPage].Top = 0x7FFF; EraseRect[NonDisplayedPage].Right = EraseRect[NonDisplayedPage].Bottom = 0; /* Affiche toutes les faces visibles du cube */ DrawVisibleFaces(&Cube); /* Permute pour afficher la page dans laquelle nous venons d'afficher */ ShowPage(PageStartOffsets[DisplayedPage = NonDisplayedPage]); while (kbhit()) { switch (getch()) { case 0x1B: /* Esc pour quitter */ Done = 1; break; case 'A': case 'a': CubeWorldXform[2][3] -= 3.0; RecalcXform = 1; break; case 'T': case 't': if (CubeWorldXform[2][3] < -40.0) { CubeWorldXform[2][3] += 3.0; RecalcXform = 1; } break; case '4': /* effectue une rotation dans le sens des aiguilles d'une montre autour de Y */ AppendRotationY(CubeWorldXform, -ROTATION); RecalcXform=1; break; case '6': /* effectue une rotation dans le sens contraire des aiguilles d'une montre autour de Y */ AppendRotationY(CubeWorldXform, ROTATION); RecalcXform=1; break; case '8': /* effectue une rotation dans le sens des aiguilles d'une montre autour de X */ AppendRotationX(CubeWorldXform, -ROTATION); RecalcXform=1; break; case '2': /* effectue une rotation dans le sens contraire des aiguilles d'une montre autour de X */ AppendRotationX(CubeWorldXform, ROTATION); RecalcXform=1; break; case 0: /* code étendu */ switch (getch()) { case 0x3B: /* effectue une rotation dans le sens contraire des aiguilles d'une montre autour de Z */ AppendRotationZ(CubeWorldXform, ROTATION); RecalcXform=1; break; case 0x3C: /* effectue une rotation dans le sens des aiguilles d'une montre autour de Z */ AppendRotationZ(CubeWorldXform, -ROTATION); RecalcXform=1; break; case 0x4B: /* gauche (-X) */ CubeWorldXform[0][3] -= 3.0; RecalcXform=1; break; case 0x4D: /* droit(+X) */ CubeWorldXform[0][3] += 3.0; RecalcXform=1; break; case 0x48: /* en haut(+Y) */ CubeWorldXform[1][3] += 3.0; RecalcXform=1; break; case 0x50: /* en bas(-Y) */ CubeWorldXform[1][3] -= 3.0; RecalcXform=1; break; default: break; } break; default: /* les touches autres touches clavier pause le programme/ getch(); break; } } } while (!Done); /* Revient en mode texte et quitte */ regset.x.ax = 0x0003; /* AL = 3 sélectionne le mode texte 80x25 */ int86(0x10, ®set, ®set); }