home *** CD-ROM | disk | FTP | other *** search
- //
- // File Name: Starf.CPP
- //
- // Description: 3-D starfield simulation
- //
- // Author: John A. De Goes
- //
- // Project: Cutting Edge 3D Game Programming
- //
-
- // -------------------------------------------------------------
- // | Global include files: |
- // -------------------------------------------------------------
-
- #include <Mem.h>
- #include <Dos.h>
- #include <Math.h>
- #include <Time.h>
- #include <Ctype.h>
- #include <Conio.h>
- #include <Stdio.h>
- #include <Stdlib.h>
- #include <String.h>
- #include <Iostream.h>
- #include <Graphics.h>
-
- // -------------------------------------------------------------
- // | Local include files: |
- // -------------------------------------------------------------
-
- #include "Starf.hpp"
- #include "OutPort.HPP"
-
- // -------------------------------------------------------------
- // | Global variables, constants: |
- // -------------------------------------------------------------
-
- // Scaling values for perspective projection:
- float Hscale = 120;
- float Vscale = -120;
-
- // The X, Y center of the screen:
- int XCENTER = 160; // The X center of the screen
- int YCENTER = 100; // The Y center of the screen
-
- // The clipping rectangle:
- int XMIN = 0, XMAX = 319, YMIN = 0, YMAX = 199;
-
- // The real-mode to protected-mode converter:
- unsigned int BaseDs = 0u;
-
- // The Z step value of the viewer:
- float ZStep;
-
- // Distance traveled in one second:
- float const DISTANCEPERSECOND = 5;
-
- // The Z value of the viewer:
- float ViewZ = 0;
-
- // View matrix and stars:
- Star *Cluster; Matrix3D ViewM;
-
- // Star count:
- unsigned int MAXSTARS = 1000;
-
- // The clock speed:
- const short unsigned int CLOCKSPEED = 10000;
-
- // Clock herz per second:
- const unsigned int HZ = 1193180 / CLOCKSPEED; // 119.3 cycles per
- // second
- // Trig tables:
- float CosTable[NUMBEROFDEGREES];
- float SinTable[NUMBEROFDEGREES];
-
- // -------------------------------------------------------------
- // | Local classes/structs: |
- // -------------------------------------------------------------
-
- void Star::Project()
- {
- // If star is far away, adjust
- // "Visible" flag accordingly:
- if (Point3D.Wz > 200)
- Visible = 0;
- else if (Point3D.Wz < 1.0F)
- {
- Visible = 0;
- // Un-comment the following lines for an infinite
- // starfield:
- // Initialize(random(300)-150, random(300)-150,
- // (random(4000)+100));
- }
- else {
- // Else star is probably visible - project:
- Visible = 1;
- float X = Point3D.Wx;
- float Y = Point3D.Wy;
- float Z = Point3D.Wz;
- float OneOverZ = 120.0F / Z;
- Point2D.X = X * OneOverZ + XCENTER;
- Point2D.Y = Y * OneOverZ + YCENTER;
- }
- }
-
- void Star::DrawPoint(unsigned char *Buffer)
- {
- // Create temporary screen points:
- int Sx = Point2D.X;
- int Sy = Point2D.Y;
- // Make sure point is in clipping boundary:
- if ((Sx >= XMIN) && (Sx <= XMAX) &&
- (Sy >= YMIN) && (Sy <= YMAX))
- {
- // Find memory location:
- short unsigned int Index = (short int)(Sy * 320 + Sx);
- // Shade according to distance:
- Buffer[Index] = Point3D.Wz / 4;
- }
- }
-
- // Initializes the star position
- void inline Star::Initialize(float Nx, float Ny, float Nz)
- {
- Point3D.Wx = Nx;
- Point3D.Wy = Ny;
- Point3D.Wz = Nz;
- }
-
- // Display the star on the linear buffer "Buffer"
- void Star::Show(unsigned char *Buffer)
- {
- // Project point:
- Project();
- // If star is still visible...
- if (Visible == 1)
- {
- // ...draw it:
- DrawPoint(Buffer);
- }
- }
-
- // A generic timer class:
- class Timer {
- protected:
- unsigned long StartTime, CurrentTime, FunctionTime, Lapse;
- int UpdateFlag, AttachFlag;
- void (*CallFunction) ();
- public:
- Timer ()
- {
- AttachFlag = 0;
- UpdateFlag = 0;
- StartTime = 0;
- }
- // A member to start the clock:
- void Start ()
- {
- StartTime = clock ();
- UpdateFlag = 1;
- }
- // A member to reset the clock:
- void Reset ()
- {
- StartTime = clock ();
- UpdateFlag = 1;
- }
- // A member to get elapsed time:
- unsigned long Time ()
- {
- if ( UpdateFlag )
- {
- CurrentTime = clock();
- return (CurrentTime - StartTime);
- }
- return 0;
- }
- void Update ();
- void Attach(void (*NewFunction)(), long Delay );
- void operator ++ () { Update (); }
- void operator ++ (int) { Update (); }
- };
-
- void Timer::Update ()
- {
- CurrentTime = clock();
- if (AttachFlag)
- {
- if (CurrentTime >= FunctionTime)
- {
- FunctionTime = CurrentTime + Lapse;
- CallFunction ();
- }
- }
- }
-
- // Function that will attach a function to specified time
- // intervals.
- void Timer::Attach(void (*NewFunction)(), long Delay )
- {
- Timer::CallFunction = NewFunction;
- Lapse = Delay;
- CurrentTime = clock();
- FunctionTime = CurrentTime + Delay;
- AttachFlag = 1;
- }
-
- // -------------------------------------------------------------
- // | Function section: |
- // -------------------------------------------------------------
-
- // Initiate math function - call to initialize trig tables
- void InitMath()
- {
- long double Unit = (long double)6.28 /
- (long double)NUMBEROFDEGREES;
- for (unsigned int i=0; i<NUMBEROFDEGREES; i++)
- {
- long double Degree = (long double)i;
- CosTable[i] = cos(Unit * Degree);
- SinTable[i] = sin(Unit * Degree);
- }
- }
-
- // Abort funtion
- void Abort(char *String, int N = 1)
- {
- cout << String;
- exit(N);
- }
-
- void SetPalReg ( long Index, char Red, char Green, char Blue )
- {
- REGS Regs;
- Regs.w.ax = 0x1010;
- Regs.x.ebx = Index;
- Regs.h.ch = Red;
- Regs.h.cl = Green;
- Regs.h.dh = Blue;
- int386 ( 0x10, &Regs, &Regs );
- }
-
-
- // Sets the palette to shades of gray
- void SetPalette()
- {
- short unsigned int Color1, Color2, Color3;
- for (short unsigned int Index = 0; Index < 256; Index++)
- {
- // Update three colors:
- Color1 = ( unsigned short ) ( ( 256 >> 2 ) - Index );
- Color2 = ( unsigned short ) ( ( 256 >> 2 ) - Index );
- Color3 = ( unsigned short ) ( ( 256 >> 2 ) - Index );
- SetPalReg ( Index, Color1, Color2, Color3 );
- }
- }
-
- // Changes the speed of the internal clock
- void ChangeClock ( unsigned short int Value )
- {
- unsigned char LowByte = ( unsigned char )
- ( Value & 0x00FF );
- unsigned char HighByte = ( unsigned char )
- ( ( Value >> 8 ) & 0x00FF );
- // Send control word to 8253's control register:
- outportbr ( 0x43, 0x3C );
- // Set the new counter time:
- outportbr ( 0x40, LowByte );
- outportbr ( 0x40, HighByte );
- }
-
- // Initializes real-mode addresses
- int InitDPMI(void)
- {
- REGS Register;
- // Do not proceed if BaseDs has already been initialized
- if (BaseDs == 0)
- {
- // Get the base linear address for DS.
- Register.w.bx = _DS;
- Register.w.ax = 0x0006;
- int386(0x31, &Register, &Register);
- // If we encounter an error, return zero
- if (Register.x.cflag)
- return 0;
- // Multiply by 65,536 and mask out un-wanted bits
- BaseDs = ((unsigned int)(Register.w.cx) << 16) | Register.w.dx;
-
- Register.w.bx = _DS;
- Register.w.ax = 0x0008;
- Register.w.cx = Register.w.dx = 0xFFFF;
- int386(0x31, &Register, &Register);
- return !Register.x.cflag;
- }
- else
- return 1;
- }
-
- // Call this one to get a real-mode address
- unsigned int GetAddress(unsigned int RMLocation)
- {
- if ((BaseDs == 0) && (InitDPMI() == 0))
- return 0;
- return (RMLocation - BaseDs);
- }
-
- // Call this one to get a real-mode address
- // Don't call this one without calling InitDPMI
- unsigned int ConvertAddress(unsigned int Address)
- {
- return Address - BaseDs;
- }
-
- // Sets video mode - performs no error checking (e.g wrong
- // monitor.)
- void SetMode(short int mode)
- {
- REGS regs;
- regs.w.ax = mode;
- regs.h.ah = 0;
- int386(0x10, ®s, ®s);
- }
-
-
- // Main function:
- void main(void)
- {
- // Pointer to video memory:
- unsigned char *Screen = (unsigned char *)GetAddress(0xA0000UL);
- // Screen buffer:
- unsigned char *Buffer;
- // Misc. variables:
- int Input = 1, Xr = 0, Yr = 0, Zr = 0;
- // Allociate memory:
- Buffer = new unsigned char[64000];
- Cluster = new Star [ MAXSTARS ];
- // Timer and ElapsedTime variables:
- Timer T; float ElapsedTime = 100;
- // Abort if not enough memory:
- if ((Buffer == NULL) || (Cluster == NULL))
- {
- Abort("\nNot enough memory to run application\n");
- }
- // Set video mode and palette:
- SetMode(0x13);
- SetPalette();
- // Initiate trig tables:
- InitMath();
- // Change the system clock to a higher resolution:
- ChangeClock ( ( short ) CLOCKSPEED );
- // Start the timer:
- T.Start ();
- // Loop until esc key pressed:
- while (Input != 27)
- {
- // Calculate step based on speed of computer.
- // Uses following algorithm:
- //
- // (1) convert DISTANCEPERSECOND to
- // a distance per herz value.
- // (2) multiply this value by the time
- // it takes to draw each frame
-
- ZStep = ( float ) DISTANCEPERSECOND /
- ( float ) HZ * ( float ) ElapsedTime;
- // Handle keyboard input:
- if (kbhit())
- {
- Input = getch();
- switch (Input)
- {
- case ('X'):
- ++Xr;
- break;
- case ('x'):
- --Xr;
- break;
- case ('Y'):
- ++Yr;
- break;
- case ('y'):
- --Yr;
- break;
- case ('Z'):
- ++Zr;
- break;
- case ('z'):
- --Zr;
- break;
- case ('f'):
- ViewZ = ZStep;
- break;
- case ('b'):
- ViewZ = -ZStep;
- break;
- case ('s'):
- ViewZ = 0.0f;
- break;
- case ('v'):
- {
- gotoxy(15, 12);
- cout << "Version 0.1a";
- getch();
- break;
- }
- default:
- break;
- }
- }
- // Clear buffer:
- setmem(Buffer, 64000, 0);
- // Initialize viewing matrix:
- ViewM.Initialize();
- // Perform transformations:
- ViewM.Rotate (-Xr, -Yr, -Zr);
- ViewM.Translate ( 0, 0, -ViewZ );
- // Loop through list of stars:
- for (unsigned int Index=0; Index<MAXSTARS; Index++)
- {
- // Transform and draw stars:
- Cluster[Index].Transform(ViewM);
- Cluster[Index].Show(Buffer);
- }
- // Move data into viewport:
- memmove(Screen, Buffer, 64000);
-
- // Calculate time it took to draw frame
- // and reset the timer:
- ElapsedTime = ( float ) T.Time ();
- T.Reset ();
- }
- // Perform a skewing demo:
- while (!kbhit())
- {
- // Clear buffer:
- setmem(Buffer, 64000, 0);
- // Initialize viewing matrix:
- ViewM.Initialize();
- // Perform rotations and translations:
- ViewM.Rotate(0, 0, 10);
- ViewM.Shear(-0.1, -0.1);
- // Loop through list of stars:
- for (unsigned int Index=0; Index<MAXSTARS; Index++)
- {
- // Transform and draw stars:
- Cluster[Index].Transform(ViewM);
- Cluster[Index].Show(Buffer);
- }
- // Move data into viewport:
- memmove(Screen, Buffer, 64000);
- }
- getch();
- // Unlock memory:
- delete [] Buffer;
- delete [] Cluster;
- // Set mode to text mode:
- SetMode(0x03);
- // Restore the system clocks original setting:
- ChangeClock ( 0xFFFF );
- }
-