home
***
CD-ROM
|
disk
|
FTP
|
other
***
search
/
Cutting-Edge 3D Game Programming with C++
/
CE3DC++.ISO
/
BOOK
/
CHAP03
/
ORBITSIM.CPP
< prev
next >
Wrap
C/C++ Source or Header
|
1996-04-19
|
12KB
|
441 lines
//
// File name: OrbitSim.CPP
//
// Description: A simple orbit model illustrating 3-dimensional
// transformations
//
// Author: John De Goes
//
// Project: Cutting Edge 3D Game Programming
//
// ------------------------------------------------------------
// | Global headers: |
// ------------------------------------------------------------
#include <Dos.H>
#include <Time.H>
#include <Math.H>
#include <Stdio.H>
#include <Assert.H>
#include <Conio.H>
#include <Stdlib.H>
#include <Iostream.H>
// ------------------------------------------------------------
// | Local headers: |
// ------------------------------------------------------------
#include "32bit.HPP"
#include "TGA32.HPP"
#include "OutPort.HPP"
// ------------------------------------------------------------
// | Globals/constants: |
// ------------------------------------------------------------
#pragma inline
// ------------------------------------------------------------
// | Local structs/classes |
// ------------------------------------------------------------
// A view port struct:
struct ViewPort {
// The distance between the viewer and the screen:
float Distance;
// The buffer containing the image to be displayed:
unsigned char *Buffer;
// The background color:
unsigned char BackColor;
// The screen width and height:
int Width, Height;
// The center of the view port:
int XCenter, YCenter;
// The clipping coordinates:
int Left, Right, Top, Bottom;
};
// A Planet class:
class Planet {
protected:
float X, Y, Z, Velocity;
int Sx, Sy, OldSx, OldSy;
unsigned char Color;
ViewPort *LastScreen;
// Protected project function:
void Project ( ViewPort &Screen );
public:
// No argument constructor:
Planet () { }
// Three argument constructor:
Planet ( float Nx, float Ny, float Nz )
{
Position ( Nx, Ny, Nz );
}
// Rotatation functions:
void RotateX ( float Angle );
void RotateY ( float Angle );
void RotateZ ( float Angle );
// Translation functions:
void Translate ( float Xt, float Yt, float Zt );
// Display function:
void Display ( ViewPort &Screen );
// Position functions:
float GetX () { return X; }
float GetY () { return Y; }
float GetZ () { return Z; }
// Erase function:
void Erase ();
// Position function:
void Position ( float Nx, float Ny, float Nz )
{
X = Nx; Y = Ny; Z = Nz;
}
// Color function:
void SetColor ( unsigned char NewColor )
{
Color = NewColor;
}
};
void Planet::Project ( ViewPort &Screen )
{
// Project the planets (X, Y, Z) coordinates onto
// the 2-dimensional viewport by dividing the world (X, Y)
// by the world Z - multiplying by viewing distance:
assert ( Z > 0 );
Sx = X * Screen.Distance / Z + Screen.XCenter;
Sy = Y * ( -Screen.Distance ) / Z + Screen.YCenter;
}
void Planet::RotateX ( float Angle )
{
// Function rotates planet around the X axis by Angle
float OldX = X, OldY = Y, OldZ = Z;
X = OldX;
Y = OldY * cos ( Angle ) - OldZ * sin ( Angle );
Z = OldY * sin ( Angle ) + OldZ * cos ( Angle );
}
void Planet::RotateY ( float Angle )
{
// Function rotates planet around Y axis by Angle
float OldX = X, OldY = Y, OldZ = Z;
X = OldZ * sin ( Angle ) + OldX * cos ( Angle );
Y = OldY;
Z = OldZ * cos ( Angle ) - OldX * sin ( Angle );
}
void Planet::RotateZ ( float Angle )
{
// Function rotates planet around Z axis by Angle
float OldX = X, OldY = Y, OldZ = Z;
X = OldX * cos ( Angle ) - OldY * sin ( Angle );
Y = OldX * sin ( Angle ) + OldY * cos ( Angle );
Z = OldZ;
}
void Planet::Translate ( float Xt, float Yt, float Zt )
{
// Translate planet by (Xt, Yt, Zt)
X += Xt; Y += Yt; Z += Zt;
}
void Planet::Display ( ViewPort &Screen )
{
// Project 3-dimensional coordinates:
Project ( Screen );
// Determine if point is on view port:
if ( ( Sx >= Screen.Left) && ( Sx <= Screen.Right ) )
if ( ( Sy >= Screen.Top) && (Sy <= Screen.Bottom ) )
{
// If so, display planet:
Screen.Buffer [ Sy * Screen.Width + Sx ] = Color;
}
// Record these points:
OldSx = Sx; OldSy = Sy;
LastScreen = &Screen;
}
void Planet::Erase ()
{
// Function erases planet - remembers last ViewPort
int Width = LastScreen -> Width;
unsigned char OldColor = LastScreen -> BackColor;
LastScreen -> Buffer [ OldSy * Width + Sx ] = OldColor;
}
// A timer class
class Timer {
protected:
unsigned long StartTime, CurrentTime, FunctionTime, Lapse;
int UpdateFlag, AttachFlag;
void (*CallFunction) ();
public:
Timer ()
{
AttachFlag = 0;
UpdateFlag = 0;
StartTime = 0;
}
void Start ()
{
StartTime = clock ();
UpdateFlag = 1;
}
void Reset ()
{
StartTime = clock ();
UpdateFlag = 1;
}
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: |
// ------------------------------------------------------------
// Function designed to initialize the two view ports
void InitializeViews ( ViewPort &View1, ViewPort &View2 )
{
// Initialize view 1:
View1.Distance = 120;
View1.BackColor = 0;
View1.Width = 320;
View1.Height = 200;
View1.XCenter = 100;
View1.YCenter = 100;
View1.Left = 50;
View1.Right = 150;
View1.Top = 50;
View1.Bottom = 150;
// Initialize view 2:
View2.Distance = 120;
View2.BackColor = 0;
View2.Width = 320;
View2.Height = 200;
View2.XCenter = 220;
View2.YCenter = 100;
View2.Left = 170;
View2.Right = 270;
View2.Top = 50;
View2.Bottom = 150;
}
// Function designed to blit a view port to a 320x200 screen:
void BlitView ( ViewPort &ViewScreen,
unsigned char *ScreenPtr )
{
int X1 = ViewScreen.Left, X2 = ViewScreen.Right;
int Y1 = ViewScreen.Top, Y2 = ViewScreen.Bottom;
unsigned char *BufferPtr = ViewScreen.Buffer;
unsigned char *ScanBuffer, *ScanScreen;
ScreenPtr += Y1 * 320 + X1;
BufferPtr += Y1 * ViewScreen.Width + X1;
for ( int Y = Y1; Y < Y2; Y++ )
{
ScanBuffer = BufferPtr;
ScanScreen = ScreenPtr;
// Blit scan-line - buffer width must be evenly
// divisible by 4:
int Length = (X2 - X1) >> 2;
for ( register int X = 0; X < Length; X++ )
{
*ScanScreen++ = *ScanBuffer++;
*ScanScreen++ = *ScanBuffer++;
*ScanScreen++ = *ScanBuffer++;
*ScanScreen++ = *ScanBuffer++;
}
ScreenPtr += 320;
BufferPtr += ViewScreen.Width;
}
}
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 );
}
// A function designed to set the palette:
void SetPalette(unsigned char *Palette)
{
int N = 0; N; Palette;
for (short unsigned int Index = 0; Index < 256; Index++)
{
SetPalReg ( Index, ( short unsigned int ) Palette [ N++ ],
( short unsigned int ) Palette [ N++ ],
( short unsigned int ) Palette [ N++ ] );
}
}
// 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 );
}
// Program entry:
void main ()
{
// Create a pointer to video memory:
unsigned char *ScreenPtr = VideoAddress ();
// Create a video buffer:
unsigned char *ScreenBuffer = new unsigned char [64000];
float TScale, ElapsedTime = 0; Timer T;
if ( ScreenBuffer == NULL )
{
cout << "\nNot enough memory to run application\n";
return;
}
TGAImage BackGround;
if ( BackGround.Load ( "Orbitbck.TGA" ) == 0 )
{
cout << "\nError loading OrbitBCK.TGA\n";
delete [] ScreenBuffer;
return;
}
int Input = 0;
ViewPort View1, View2;
InitializeViews ( View1, View2 );
View1.Buffer = ScreenBuffer;
View2.Buffer = ScreenBuffer;
Planet Earth (0, -1, 10 ), Moon (-3, -1, 10 );
Planet Jupiter (0, 0, 10 ), JMoon ( -3, 0, 10 );
Earth.SetColor ( BLUE + 100 );
Moon.SetColor ( LIGHTGRAY + 100 );
Jupiter.SetColor ( RED + 100 );
JMoon.SetColor ( DARKGRAY + 100 );
// Set the video mode to 13h:
SetVideo ( 0x13 );
// Set the palette:
SetPalette ( BackGround.Palette );
// Initialize inertia values:
float MoonVSign = 1;
// Set the system clock to 119.2 ticks a second:
ChangeClock ( 10000 );
// Start the timer:
T.Start ();
// Loop until escape key pressed:
while ( Input != 27 )
{
TScale = 0.05 * ElapsedTime;
// Check for keyboard input:
if ( kbhit() )
Input = getch ();
// Blit background to screen:
memmove ( ScreenBuffer, BackGround.Image, 64000 );
// Display earth and moon:
Earth.Display ( View1 );
Moon.Display ( View1 );
// Translate moon to origin:
Moon.Translate ( 0, 1, -10 );
// Rotate moon:
Moon.RotateY ( 0.01 * TScale );
// Translate moon:
Moon.Translate ( 0, MoonVSign, 0 );
if ( Moon.GetY() < -0.25 )
{
MoonVSign = ( 0.01 * TScale );
}
if ( Moon.GetY() > 0.25 )
{
MoonVSign = -( 0.01 * TScale );
}
// Translate moon to original position:
Moon.Translate ( 0, -1, 10 );
// Display Jupiter and it's moon:
Jupiter.Display ( View2 );
JMoon.Display ( View2 );
// Rotate moon:
JMoon.RotateZ ( 0.01 * TScale );
// Blit the various viewports:
BlitView ( View1, ScreenBuffer );
BlitView ( View2, ScreenBuffer );
// Copy the screen buffer into the video ram:
memmove ( ScreenPtr, ScreenBuffer, 64000 );
// Record elapsed time and reset the timer:
ElapsedTime = T.Time ();
T.Reset ();
}
// Set the video mode to 03h:
SetVideo ( 0x03 );
// Unlock memory:
delete [] ScreenBuffer;
// Reset the speed of the system's clock:
ChangeClock ( 0xFFFF );
}