Ever wonder if you could create a starfield simulation like that of the screensaver of windows? Here's the program I wrote last 7 years ago. It's a Dos-based application so don't run it in Visual C++. I used Turbo C++ for Dos. If you want to run this, you can simply copy-paste the source code and you have to edit the comments since it's not really formatted here properly on this site. So don't blame me if you found a lot of errors.. Anyway, if you have question about this program, just post a comment here on this blog. Take note, the code presented here is quite advanced, so you may find some cryptic syntax around.. Don't be scared though, there are a lot of things you can learn from the code itself. So go ahead, and reverse-engineer it if you like.
By the way, you can press the arrow keys once it's already running and to exit the program, simply press Esc.
#include <stdio.h>
#include <conio.h>
#include <stdlib.h>
#include <dos.h>
const Maxstars = 1056; //Determine the number of stars
const RIGHTARROW = 77; // {Right Coursr Key}
const LEFTARROW = 75; // {Left Coursr Key}
const UPARROW = 72; // {Up Coursr Key}
const DOWNARROW = 80; // {Down Coursr Key}
const ESCAPE = 1;
typedef unsigned char byte;
byte keystruck[128];
void interrupt (* oldInt9)(...); //oldInt9 is a pointer to an interrupt handlr
typedef unsigned char byte;
typedef struct star_id
{
int x ;
int y ;
int z ;
int speed ;
int color ;
} star_ID;
star_ID star[Maxstars] ;
int loop, Zoff ;
int Screen_X[Maxstars], Screen_Y[Maxstars] ;
int color, cntr ;
void interrupt newInt9(...)
{ //This is the new interrupt 9.
//It will determine if a key is being pressed or released;
byte key;
key = inp(0x60) % 128 ; //Get the byte at port 60h
//if the byte returned is < 128 then return TRUE else FALSE;
keystruck[key] = (inp(0x60) < 128);
asm pushf; //Push all flags
oldInt9(); //Call the old interrupt 9
//Move the Tail to HEAD to Empty the keyboard buffer
pokeb(0x40,0x1A,peekb(0x40,0x1C));
}
void WaitRetrace()
{
// { This waits for a vertical retrace to reduce snow on the screen }
byte signal;
signal = inp(0x3DA); //Get the status byte of the CRT
signal &= 8;
while(signal > 0) //Loop while signal is high
{
signal = inp(0x3DA);
signal &= 8;
}
signal = inp(0x3DA); //Get the status byte of the CRT
signal &= 8;
while(signal == 0) //Loop while signal is low
{
signal = inp(0x3DA);
signal &= 8;
}
}
void init()
{
oldInt9 = getvect(0x9);
setvect(0x9,newInt9);
}
void restore()
{
setvect(0x9,oldInt9);
}
void pal(byte color, byte R, byte G, byte B)
{ //Set the background(0) palette;
asm{
mov al, color
mov dx, 0x3c8
out dx, al
inc dx
mov al, R
out dx, al
mov al, G
out dx, al
mov al, B
out dx, al
}
}
void Putpixel (int X,int Y, byte Col)
/*{ This putpixel was originally written by Denthor of ASPHIXIA,
modified by me for maximum optimisation. This is faster than
the BGI's Putpixel}
This puts a pixel on the screen by writing directly to memory. }
Optimized by J.V.A. */
{
asm {
mov ax, 0xa000 // Load the memory segment address
mov es,ax // to es { 8 }
mov bx,X // Store X to bx { 8 }
mov dx,Y // Store Y to dx { 8 }
mov di,bx // Copy X to di { 2 }
mov bx, dx // Copy Y to bx { 2 }
shl dx, 8 // Multiply Y by 256 { 8 }
shl bx, 6 // Multiply temp.Y by 64 { 8 }
add dx, bx // Add both product to get Y*320 { 3 }
add di, dx // Final location(X+Y) { 3 }
mov al,Col // Store the color { 8 }
mov es:[di],al // Put the color on this address { 10 }
}
}
void dPutPixel(int x, int y, byte drawcolor) {
/*
_AH = 0x0C;
_AL = drawcolor;
_CX = x;
_DX = y;
_BX = 0x01;
geninterrupt (0x10);*/
asm{
mov ax, y
mov bx, x
mov cx, 640
mul cx
add bx, ax
adc dx, 0
mov ax, 0xa000
mov es, ax
push bx
mov bx, 1
mov ax, 0x4f05
int 0x10
pop bx
mov al, drawcolor
mov es:[bx], al
}
}
void SetMCGA()
{
asm{
mov ax, 0x013
int 0x10
}
}
void GoTextMode()
{
asm{
mov ax,0x3
int 0x10
}
}
void InitStars(int I)
{
int temp ;
byte sign ;
star[I].x = random(160)+1; // {Set the initial x of the star}
star[I].y = random(100)+1; // {Set the initial y of the star}
star[I].z = 256; // {Set the z to default, the depth}
star[I].speed = random(5) + 3; // {This is to adjust the speed of a star}
star[I].color = 0;
sign = random(2);
switch (sign) { // {Make some random stuff}
case 1 : star[I].x = -star[I].x; break;
case 2 : star[I].x = star[I].x; break;
}
sign = random(2);
switch (sign) {
case 1 : star[I].y = -star[I].y; break;
case 2 : star[I].y = star[I].y; break;
}
}
void InitStarsD(int K)
{
int temp ;
int sign ;
star[K].x = random(160)+1; // {Set the x of the star}
star[K].y = random(100)+1; // {Set the y of the star}
star[K].z = random(256) + 1; // {Set the z to default}
star[K].speed = random(5) + 3;// {This is to adjust the speed of a star}
star[K].color = BLACK; //Starting color of star is black
sign = random(2);
switch (sign) { // {Make some random stuff}
case 1 : star[K].x = -star[K].x; break;
case 2 : star[K].x = star[K].x; break;
}
sign = random(2);
switch (sign) {
case 1 : star[K].y = -star[K].y; break;
case 2 : star[K].y = star[K].y; break;
}
}
int main()
{
long viewx, viewy;
init();
SetMCGA();
randomize();
//Set the drawing palette of the stars
for (loop = 0;loop <= 255; loop++)
pal(loop,loop % 63,loop % 63,loop % 63);
for (loop = 0;loop < Maxstars;loop++)
InitStarsD(loop); //{ Initialize all stars }
viewx = 160;
viewy = 100;
while (!keystruck[ESCAPE])
{
for (loop = 0; loop < Maxstars; loop++)//Process each stars
{
//Convert the 3D coordinates to 2D coordinates;
Screen_X[loop] = ((star[loop].x * 256 / star[loop].z ) + viewx);
Screen_Y [loop] = ((star[loop].y * 256 / star[loop].z ) + viewy);
//Check of Stars are beyond the screen area, if not then draw them
if ((Screen_X[loop] > 1) && (Screen_X[loop] < 319) && (Screen_Y[loop] > 1)
&& (Screen_Y[loop] < 199))
{
Putpixel(Screen_X[loop],Screen_Y[loop],star[loop].color % 256);
}
//If stars are beyond the view, create new one
if (star[loop].z <= 8)
InitStars(loop); // Create new star
//Move the stars towards the viewer.
star[loop].z = star[loop].z - star[loop].speed;
//Change the palette;
star[loop].color = star[loop].color + 1;
}
if (keystruck[LEFTARROW])
viewx -= 3;
if (keystruck[RIGHTARROW])
viewx += 3;
if (keystruck[UPARROW])
viewy -= 3;
if (keystruck[DOWNARROW])
viewy += 3;
delay(30);
//Erase the stars after drawing them
for (loop = 0;loop < Maxstars; loop++)
{
Putpixel(Screen_X[loop],Screen_Y[loop],BLACK);
}
}
restore();
GoTextMode();
return 0;
}
Sunday, July 29, 2007
Star Field Simulation Written in Turbo C
Posted by
NegOcc
at
9:12 PM
Subscribe to:
Post Comments (Atom)
1 comments:
Cool Blog bro!! Another nice Programming Tutorial! Keep it up!
Post a Comment