home *** CD-ROM | disk | FTP | other *** search
/ Cutting-Edge 3D Game Programming with C++ / CE3DC++.ISO / BOOK / CHAP03 / ORBITSIM.CPP < prev    next >
C/C++ Source or Header  |  1996-04-19  |  12KB  |  441 lines

  1. //
  2. // File name: OrbitSim.CPP
  3. //
  4. // Description: A simple orbit model illustrating 3-dimensional
  5. //              transformations
  6. //
  7. // Author: John De Goes
  8. //
  9. // Project: Cutting Edge 3D Game Programming
  10. //
  11.  
  12. // ------------------------------------------------------------
  13. // | Global headers:                                          |
  14. // ------------------------------------------------------------
  15.  
  16. #include <Dos.H>
  17. #include <Time.H>
  18. #include <Math.H>
  19. #include <Stdio.H>
  20. #include <Assert.H>
  21. #include <Conio.H>
  22. #include <Stdlib.H>
  23. #include <Iostream.H>
  24.  
  25. // ------------------------------------------------------------
  26. // | Local headers:                                           |
  27. // ------------------------------------------------------------
  28.  
  29. #include "32bit.HPP"
  30. #include "TGA32.HPP"
  31. #include "OutPort.HPP"
  32.  
  33. // ------------------------------------------------------------
  34. // | Globals/constants:                                       |
  35. // ------------------------------------------------------------
  36.  
  37. #pragma inline
  38.  
  39. // ------------------------------------------------------------
  40. // | Local structs/classes                                    |
  41. // ------------------------------------------------------------
  42.  
  43. // A view port struct:
  44. struct ViewPort {
  45. // The distance between the viewer and the screen:
  46. float Distance;
  47. // The buffer containing the image to be displayed:
  48. unsigned char *Buffer;
  49. // The background color:
  50. unsigned char BackColor;
  51. // The screen width and height:
  52. int Width, Height;
  53. // The center of the view port:
  54. int XCenter, YCenter;
  55. // The clipping coordinates:
  56. int Left, Right, Top, Bottom;
  57. };
  58.  
  59. // A Planet class:
  60. class Planet {
  61. protected:
  62. float X, Y, Z, Velocity;
  63. int Sx, Sy, OldSx, OldSy;
  64. unsigned char Color;
  65. ViewPort *LastScreen;
  66. // Protected project function:
  67. void Project ( ViewPort &Screen );
  68. public:
  69. // No argument constructor:
  70. Planet () { }
  71. // Three argument constructor:
  72. Planet ( float Nx, float Ny, float Nz )
  73.    {
  74.    Position ( Nx, Ny, Nz );
  75.    }
  76. // Rotatation functions:
  77. void RotateX ( float Angle );
  78. void RotateY ( float Angle );
  79. void RotateZ ( float Angle );
  80. // Translation functions:
  81. void Translate ( float Xt, float Yt, float Zt );
  82. // Display function:
  83. void Display ( ViewPort &Screen );
  84. // Position functions:
  85. float GetX () { return X; }
  86. float GetY () { return Y; }
  87. float GetZ () { return Z; }
  88. // Erase function:
  89. void Erase ();
  90. // Position function:
  91. void Position ( float Nx, float Ny, float Nz )
  92.    {
  93.    X = Nx; Y = Ny; Z = Nz;
  94.    }
  95. // Color function:
  96. void SetColor ( unsigned char NewColor )
  97.    {
  98.    Color = NewColor;
  99.    }
  100. };
  101.  
  102. void Planet::Project ( ViewPort &Screen )
  103.    {
  104.    // Project the planets (X, Y, Z) coordinates onto
  105.    // the 2-dimensional viewport by dividing the world (X, Y)
  106.    // by the world Z - multiplying by viewing distance:
  107.    assert ( Z > 0 );
  108.    Sx = X * Screen.Distance / Z + Screen.XCenter;
  109.    Sy = Y * ( -Screen.Distance ) / Z + Screen.YCenter;
  110.    }
  111.    
  112. void Planet::RotateX ( float Angle )
  113.    {
  114.    // Function rotates planet around the X axis by Angle
  115.    float OldX = X, OldY = Y, OldZ = Z;
  116.    X = OldX;
  117.    Y = OldY * cos ( Angle ) - OldZ * sin ( Angle );
  118.    Z = OldY * sin ( Angle ) + OldZ * cos ( Angle );
  119.    }
  120.    
  121. void Planet::RotateY ( float Angle )
  122.    {
  123.    // Function rotates planet around Y axis by Angle
  124.    float OldX = X, OldY = Y, OldZ = Z;
  125.    X = OldZ * sin ( Angle ) + OldX * cos ( Angle );
  126.    Y = OldY;
  127.    Z = OldZ * cos ( Angle ) - OldX * sin ( Angle );
  128.    }
  129.    
  130. void Planet::RotateZ ( float Angle )
  131.    {
  132.    // Function rotates planet around Z axis by Angle
  133.    float OldX = X, OldY = Y, OldZ = Z;
  134.    X = OldX * cos ( Angle ) - OldY * sin ( Angle );
  135.    Y = OldX * sin ( Angle ) + OldY * cos ( Angle );
  136.    Z = OldZ;
  137.    }
  138.    
  139. void Planet::Translate ( float Xt, float Yt, float Zt )
  140.    {
  141.    // Translate planet by (Xt, Yt, Zt)
  142.    X += Xt; Y += Yt; Z += Zt;
  143.    }
  144.    
  145. void Planet::Display ( ViewPort &Screen )
  146.    {
  147.    // Project 3-dimensional coordinates:
  148.    Project ( Screen );
  149.    // Determine if point is on view port:
  150.    if ( ( Sx >= Screen.Left) && ( Sx <= Screen.Right ) )
  151.       if ( ( Sy >= Screen.Top) && (Sy <= Screen.Bottom ) )
  152.      {
  153.      // If so, display planet:
  154.      Screen.Buffer [ Sy * Screen.Width + Sx ] = Color;
  155.      }
  156.    // Record these points:
  157.    OldSx = Sx; OldSy = Sy;      
  158.    LastScreen = &Screen;
  159.    }
  160.    
  161. void Planet::Erase ()
  162.    {
  163.    // Function erases planet - remembers last ViewPort
  164.    int Width = LastScreen -> Width;
  165.    unsigned char OldColor = LastScreen -> BackColor;
  166.    LastScreen -> Buffer [ OldSy * Width + Sx ] = OldColor;
  167.    }
  168.  
  169. // A timer class   
  170. class Timer {
  171. protected:
  172. unsigned long StartTime, CurrentTime, FunctionTime, Lapse;
  173. int UpdateFlag, AttachFlag;
  174. void (*CallFunction) ();
  175. public:
  176. Timer ()
  177. {
  178. AttachFlag = 0;
  179. UpdateFlag = 0;
  180. StartTime = 0;
  181. }
  182. void Start ()
  183.    {
  184.    StartTime = clock ();
  185.    UpdateFlag = 1;
  186.    }
  187. void Reset ()
  188.    {
  189.    StartTime = clock ();
  190.    UpdateFlag = 1;
  191.    }
  192. unsigned long Time ()
  193.    {
  194.    if ( UpdateFlag )
  195.       {
  196.       CurrentTime = clock();
  197.       return (CurrentTime - StartTime);
  198.       }
  199.    return 0;   
  200.    }
  201. void Update ();
  202. void Attach(void (*NewFunction)(), long Delay );
  203. void operator ++ () { Update (); }
  204. void operator ++ (int) { Update (); }
  205. };
  206.  
  207. void Timer::Update ()
  208.    {
  209.    CurrentTime = clock();
  210.    if (AttachFlag)
  211.       {
  212.       if (CurrentTime >= FunctionTime)
  213.      {
  214.      FunctionTime = CurrentTime + Lapse;
  215.      CallFunction ();
  216.      }
  217.       }   
  218.    }
  219.    
  220. // Function that will attach a function to specified time
  221. // intervals.
  222. void Timer::Attach(void (*NewFunction)(), long Delay )
  223.    {
  224.    Timer::CallFunction = NewFunction;
  225.    Lapse = Delay;
  226.    CurrentTime = clock();
  227.    FunctionTime = CurrentTime + Delay;
  228.    AttachFlag = 1;
  229.    }   
  230.    
  231. // ------------------------------------------------------------
  232. // | Function section:                                        |
  233. // ------------------------------------------------------------
  234.  
  235. // Function designed to initialize the two view ports
  236. void InitializeViews ( ViewPort &View1, ViewPort &View2 )
  237.    {
  238.    // Initialize view 1:
  239.    View1.Distance = 120;
  240.    View1.BackColor = 0;
  241.    View1.Width = 320;
  242.    View1.Height = 200;
  243.    View1.XCenter = 100;
  244.    View1.YCenter = 100;
  245.    View1.Left = 50;
  246.    View1.Right = 150;
  247.    View1.Top = 50;
  248.    View1.Bottom = 150;
  249.  
  250.    // Initialize view 2:
  251.    View2.Distance = 120;
  252.    View2.BackColor = 0;
  253.    View2.Width = 320;
  254.    View2.Height = 200;
  255.    View2.XCenter = 220;
  256.    View2.YCenter = 100;
  257.    View2.Left = 170;
  258.    View2.Right = 270;
  259.    View2.Top = 50;
  260.    View2.Bottom = 150;
  261.    }
  262.  
  263. // Function designed to blit a view port to a 320x200 screen:
  264. void BlitView ( ViewPort &ViewScreen, 
  265.          unsigned char *ScreenPtr )
  266.    {
  267.    int X1 = ViewScreen.Left, X2 = ViewScreen.Right;
  268.    int Y1 = ViewScreen.Top, Y2 = ViewScreen.Bottom;
  269.    unsigned char *BufferPtr = ViewScreen.Buffer;
  270.    unsigned char *ScanBuffer, *ScanScreen;
  271.    ScreenPtr += Y1 * 320 + X1;
  272.    BufferPtr += Y1 * ViewScreen.Width + X1;
  273.    for ( int Y = Y1; Y < Y2; Y++ )
  274.        {
  275.        ScanBuffer = BufferPtr;
  276.        ScanScreen = ScreenPtr;
  277.        // Blit scan-line - buffer width must be evenly
  278.        // divisible by 4:
  279.        int Length = (X2 - X1) >> 2;
  280.        for ( register int X = 0; X < Length; X++ )
  281.             {
  282.             *ScanScreen++ = *ScanBuffer++;
  283.             *ScanScreen++ = *ScanBuffer++;
  284.             *ScanScreen++ = *ScanBuffer++;
  285.             *ScanScreen++ = *ScanBuffer++;
  286.             }
  287.        ScreenPtr += 320;
  288.        BufferPtr += ViewScreen.Width;
  289.        }
  290.    }
  291.  
  292. void SetPalReg ( long Index, char Red, char Green, char Blue )
  293.    {
  294.    REGS Regs;
  295.    Regs.w.ax  = 0x1010;
  296.    Regs.x.ebx = Index;
  297.    Regs.h.ch  = Red;
  298.    Regs.h.cl  = Green;
  299.    Regs.h.dh  = Blue;
  300.    int386 ( 0x10, &Regs, &Regs );
  301.    }
  302.  
  303. // A function designed to set the palette:
  304. void SetPalette(unsigned char *Palette)
  305.    {
  306.    int N = 0; N; Palette;
  307.    for (short unsigned int Index = 0; Index < 256; Index++)
  308.        {
  309.        SetPalReg ( Index, ( short unsigned int ) Palette [ N++ ], 
  310.                           ( short unsigned int ) Palette [ N++ ], 
  311.                           ( short unsigned int ) Palette [ N++ ] );
  312.        }
  313.    }   
  314.  
  315. // Changes the speed of the internal clock
  316. void ChangeClock ( unsigned short int Value )
  317.    {
  318.    unsigned char LowByte =  ( unsigned char ) 
  319.                  ( Value & 0x00FF );
  320.    unsigned char HighByte = ( unsigned char )
  321.                  ( ( Value >> 8 ) & 0x00FF );
  322.    // Send control word to 8253's control register:
  323.    outportbr ( 0x43, 0x3C );
  324.    // Set the new counter time:
  325.    outportbr ( 0x40, LowByte );
  326.    outportbr ( 0x40, HighByte );
  327.    }   
  328.    
  329. // Program entry:
  330. void main ()
  331.    {
  332.    // Create a pointer to video memory:
  333.    unsigned char *ScreenPtr = VideoAddress ();
  334.    // Create a video buffer:
  335.    unsigned char *ScreenBuffer = new unsigned char [64000];
  336.    float TScale, ElapsedTime = 0; Timer T;
  337.    if ( ScreenBuffer == NULL )
  338.       {
  339.       cout << "\nNot enough memory to run application\n";
  340.       return;
  341.       }
  342.    TGAImage BackGround;
  343.    if ( BackGround.Load ( "Orbitbck.TGA" ) == 0 )
  344.       {
  345.       cout << "\nError loading OrbitBCK.TGA\n";
  346.       delete [] ScreenBuffer;
  347.       return;
  348.       }
  349.    int Input = 0;
  350.    ViewPort View1, View2;
  351.    InitializeViews ( View1, View2 );
  352.    View1.Buffer = ScreenBuffer;
  353.    View2.Buffer = ScreenBuffer;
  354.    Planet Earth (0, -1, 10 ), Moon (-3, -1, 10 );
  355.    Planet Jupiter (0, 0, 10 ), JMoon ( -3, 0, 10 );
  356.    Earth.SetColor ( BLUE + 100 );
  357.    Moon.SetColor ( LIGHTGRAY + 100 );
  358.    Jupiter.SetColor ( RED + 100 );
  359.    JMoon.SetColor ( DARKGRAY + 100 );
  360.    
  361.    // Set the video mode to 13h:
  362.    SetVideo ( 0x13 );
  363.    
  364.    // Set the palette:
  365.    SetPalette ( BackGround.Palette );
  366.    
  367.    // Initialize inertia values:
  368.    float MoonVSign = 1;
  369.    
  370.    // Set the system clock to 119.2 ticks a second:
  371.    ChangeClock ( 10000 );
  372.    
  373.    // Start the timer:
  374.    T.Start ();
  375.    
  376.    // Loop until escape key pressed:
  377.    while ( Input != 27 )
  378.          {
  379.          TScale = 0.05 * ElapsedTime;
  380.      
  381.          // Check for keyboard input:
  382.          if ( kbhit() )
  383.          Input = getch ();
  384.      
  385.          // Blit background to screen:
  386.          memmove ( ScreenBuffer, BackGround.Image, 64000 );   
  387.      
  388.          // Display earth and moon:
  389.          Earth.Display ( View1 );
  390.          Moon.Display ( View1 );
  391.      
  392.          // Translate moon to origin:
  393.          Moon.Translate ( 0, 1, -10 );
  394.      
  395.          // Rotate moon:
  396.          Moon.RotateY ( 0.01 * TScale );
  397.      
  398.          // Translate moon:
  399.          Moon.Translate ( 0, MoonVSign, 0 );
  400.  
  401.          if ( Moon.GetY() < -0.25 )
  402.             {
  403.             MoonVSign = ( 0.01 * TScale );
  404.             }
  405.         
  406.          if ( Moon.GetY() >  0.25 )
  407.             {
  408.             MoonVSign = -( 0.01 * TScale );
  409.             }
  410.         
  411.          // Translate moon to original position:
  412.          Moon.Translate ( 0, -1, 10 );
  413.      
  414.          // Display Jupiter and it's moon:
  415.          Jupiter.Display ( View2 );
  416.          JMoon.Display ( View2 );
  417.      
  418.          // Rotate moon:
  419.          JMoon.RotateZ ( 0.01 * TScale );
  420.  
  421.          // Blit the various viewports:
  422.          BlitView ( View1, ScreenBuffer );
  423.          BlitView ( View2, ScreenBuffer );
  424.  
  425.          // Copy the screen buffer into the video ram:
  426.          memmove ( ScreenPtr, ScreenBuffer, 64000 );
  427.      
  428.          // Record elapsed time and reset the timer:
  429.          ElapsedTime = T.Time ();
  430.          T.Reset ();
  431.          }
  432.    // Set the video mode to 03h:
  433.    SetVideo ( 0x03 );
  434.    
  435.    // Unlock memory:
  436.    delete [] ScreenBuffer;
  437.    
  438.    // Reset the speed of the system's clock:
  439.    ChangeClock ( 0xFFFF );
  440.    }
  441.