www.pudn.com > VOXEL.ZIP > VOXEL.C


// voxel demo 
// 
// 95-03-Sep. 
// jeff bilger 
// eusjeb@exu.ericsson.se 
// (Send me email if you have any comments) 
// 
// ********************* 
// * Overview          * 
// ********************* 
// This program will  
//      generate a voxel terrain map and place this data in a 2d array 
//      rotate the terrain map data about x,y,z 
//      sort the voxel terrain map data by z (small values) 
//      finally display the voxel map to the crt. 
//      A virtual window can be defined, see the #define section 
// 
// ********************* 
// * History           * 
// ********************* 
// uses quick sort 
// added a period, and a granularity input,  
// the gen_map fnct uses these vars to compute the voxel map 
//   - added rotations about all 3 axes. 
//   - removed temp[][] array. No need to copy WIDTH*HEIGHT*3 words 
//     per display anymore.  
//   - added angle incr settings 
//   - color is indep. of height once transformations occur.  
//     the color is only dependent on the *original* heght now 
//   - added logic to clip at the crt window 
//   - optimized for speed (rotate/display)  
// 
// 
// 
 
#include  
#include  
#include  
#include  
#include  
#include "..\library\grafix.h" 
 
 
/**********************/ 
/* Function Prototypes*/ 
/**********************************************************************/ 
void main(); 
void init(); 
void build_palette(); 
void display_(); 
void draw_voxel(int,int,int,int); 
void gen_map(); 
void rotate(double); 
void _qsort(int,int); 
void swap(int,int); 
 
 
/*********/ 
/*Defines*/ 
/**********************************************************************/ 
 
#define DEPTH 20                  // depth of the terrain map (z) 
#define WIDTH 40                  // width of the terrain map (x) 
#define X_ORIGIN 100              // x,y origin of the screen 
#define Y_ORIGIN 100 
#define MAX_HEIGHT 50.0           // max height of the terrain 
#define INITIAL_HEIGHT 5          // initial height of the terrain 
#define PI      3.1415 
#define NO  0  
#define YES 1 
#define XW_MIN 10                // coords that define the 'virtual' 
#define XW_MAX 300               // window on the crt 
#define YW_MIN 5 
#define YW_MAX 190 
 
 
/***************/ 
/* Structures  */ 
/********************************************************************/ 
 
struct pts                        // structure for terrain map data 
{ 
 float x,y,z,color; 
}; 
typedef struct pts TERRAIN_POINTS; 
 
struct pts_int                    // structure for display map data 
{ 
int x,y,z,color; 
}; 
typedef struct pts_int DISPLAY_POINTS; 
 
 
TERRAIN_POINTS map[DEPTH][WIDTH];        // holds original terrain coords 
DISPLAY_POINTS display[DEPTH*WIDTH];     // holds  coords to display on the 
                                         // crt after transformations and  
                                         // sorting 
 
 
 
/***********/ 
/* Globals */ 
/*****************************************************************/ 
 
char far      *SCR;             // ptrs to video memory 
char          *BACK;            // and our double buffer 
unsigned char PAL[256*3];       // 256 colors (rgb) for the palette  
float         PERIOD,           // user defined period   
              COS_10,           // for roataions  
              SIN_10; 
int           GRANULARITY,      // user defined size of voxel 
              THETA_INCR;       // user defined angle increment for rotations 
char          CLIPPING = NO;    // clipping flag 
 
 
 
 
/**************/ 
/* Main()     */ 
/********************************************************************/ 
 
void main() 
{                                
double theta;                   // holds current angle 
int i=0;                        // counter  
 
 
/***************************/ 
/* Get user defined params.*/ 
/***************************/ 
printf("-Voxel landscape demo by Jeff Bilger (eusjeb@exu.ericsson.se)-\n"); 
printf("Enter the period: (90,180,360 etc) (530 is a good value):"); 
scanf("%f",&PERIOD); 
printf("Enter the length of the voxel sides: (1,2,3 etc) (2 is a good value):"); 
scanf("%d",&GRANULARITY); 
printf("Enter the degree increment per rotation: (8 is a good value):"); 
scanf("%d",&THETA_INCR); 
 
 
 
/*******************************/ 
/* Do some initialization stuff*/ 
/*******************************/ 
init(); 
 
 
/****************/ 
/* Main routine */ 
/****************/ 
while (!kbhit())                   // loop until user hits a key 
{ 
 for(i=1;i<360;i+=THETA_INCR)      // For each iteration...  
 { 
  theta = (double)i * PI / 180.0;  // convert current angle to radians 
 
  rotate(theta);                   // rotate map and save to 1d display array 
  _qsort(0,DEPTH*WIDTH-1);         // sort it 
  display_();                      // save it to double buffer 
  G_WaitRetrace(); 
  G_memcpy_word(SCR,BACK,320*200/2); // display it to the crt 
  G_Set_screen_color(0,BACK);      // erase the double buffer and repeat.. 
 } 
 
theta = 0.0;                       // if a full 360 degree revolution has  
                                   // finished, reset the angle and repeat... 
} 
G_Text_mode();                     // Go back to text mode 
 
}                                  // end of main() 
 
/*******************************************************************/ 
/*******************************************************************/ 
 
 
 
 
 
/************************/ 
/* Procedures/Functions */ 
/*******************************************************************/ 
 
// [%]===========================[%] 
// [%]build palette              [%] 
// [%]===========================[%] 
// 
// This procedure will generate the palette that will be used 
// to display the voxel terrain. 
// 
// In video mode 13h, the PC can display 256 colors from the palette 
// The palette has 256 entries and each entry is defined by a RGB color  
// value. The RGB value is 18 bits long thus 6 bits are used   
// for the R component, 6 bits for the G comp. and 6 bits for the B comp.  
// Thus each component can have a max value of 64 (2^6 = 64) 
// 
// The palette will be built such that whites/light greens are in the 
// lower color entries and dark greens are in the higher entries 
void build_palette() 
{ 
int i; 
int r=63,g=63,b=63;          // for palette setting 
 
PAL[0]= 0;                  // 1st pal entry is the background, we cant that 
PAL[1]=0;                   // to be BLACK (rgb = 0,0,0) 
PAL[2]=0; 
 
 
for(i=3;i<52*3;i+=3)        // set next 52 color entries 
 { 
  PAL[i] = r; 
  PAL[i+1] = g; 
  PAL[i+2] = b; 
  if(i%9==0) { r--;g--;b--;} 
 } 
 
 
 g=63; 
for(;i<256*3;i+=3)         // set the rest of the color entries 
 { 
  PAL[i] = 0; 
  PAL[i+1] = g--; 
  PAL[i+2] = 0; 
 } 
 
} 
 
 
 
 
// [%]===========================[%] 
// [%]init                       [%] 
// [%]===========================[%] 
// 
// Just set up some stuff 
void init() 
{ 
SCR = (char far *) MK_FP(0xa000,0);       // setup addr to video memory 
BACK =(char *) malloc(64000);             // alloc memory for double buffer 
if(BACK == NULL) exit(0); 
 
 COS_10 = cos(10.0*PI/180.0);             // for use in rotations 
 SIN_10 = sin(10.0*PI/180.0); 
 
G_Int13_mode();             // enter video mode 13h 
build_palette();            // build the palette 
G_SetPal(PAL,0,256);        // assign the new palette 
gen_map();                  // build terrain map 
 
} 
 
 
 
 
 
// [%]===========================[%] 
// [%]display                    [%] 
// [%]===========================[%] 
//  
// This procedure will draw the voxel landscape. 
// The array 'display[]'  contains the *sorted* voxel landscape  
// data, it is sorted by z such that small z values occur first. Thus 
// we will draw from 'display[DEPTH * width  - 1] to [0]' or back to front 
void display_() 
{ 
 int i,x1,y1,x2;  
 
 for(i=DEPTH*WIDTH -1 ;i>=0;i--) 
 { 
     x1 = display[i].x-GRANULARITY;     // define the length of the voxel  
     y1 = display[i].y-GRANULARITY; 
     x2 = display[i].x+GRANULARITY; 
 
                                        // see if any clipping needs to be  
                                        // done 
     if (x1 < XW_MIN || x2 > XW_MAX || y1 < YW_MIN || y1+10 > YW_MAX) 
        CLIPPING = YES; 
     
   
  draw_voxel(x1,y1,x2, display[i].color); 
  
 } 
} 
 
 
 
// [%]===========================[%] 
// [%]draw_voxel                 [%] 
// [%]===========================[%] 
//  
// draw the voxel 
void draw_voxel(int x1,int y1, int x2, int c) 
{ 
  int x=x1; 
  int offset = y1*320;  
  int loop; 
 
  if ( !CLIPPING) 
  while(x++ <= x2) 
  { 
  *(BACK + (offset + x)) = c;           // all voxels will be 10 pixels 
  *(BACK + (offset + 320) + x) = c;     // high 
  *(BACK + (offset + 2*320) + x) = c; 
  *(BACK + (offset + 3*320) + x) = c; 
  *(BACK + (offset + 4*320) + x) = c; 
  *(BACK + (offset + 5*320) + x) = c; 
  *(BACK + (offset + 6*320) + x) = c; 
  *(BACK + (offset + 7*320) + x) = c; 
  *(BACK + (offset + 8*320) + x) = c; 
  *(BACK + (offset + 9*320) + x) = c; 
  } 
   
  else  // CLIPPING is needed 
  { 
   loop = y1+10;               // each voxel is usually 10 pixels high 
 
   if (x < XW_MIN) x=XW_MIN;               // case 1,  
   else if (x2 > XW_MAX)  x2=XW_MAX;       // if case 1 is True, case 2 
                                           // can *never* be true unless you  
                                           // defined GRANULARITY as some  
                                           // value that is larger than  
                                           // the width of your virtual window 
                                           // which would be stupid. 
 
   if (y1 < YW_MIN)                   // case 3 
     { 
       loop = (10 + y1);  
       y1 = YW_MIN; 
     } 
   else if ((y1 + 10) > YW_MAX)      // case 4 can never be true if case 3 
     loop = YW_MAX;                  // is true unless you define your  
                                     // virtual window height as less than 10  
                                     // (again, stupid..) 
    
    for( ; y1 display[r].z) 
      swap(l,r); 
      j=l;k=r; 
      do 
      { 
       do{ j++; }while(display[j].z < display[l].z); 
       do{ k--; }while(display[k].z > display[l].z); 
       if  (j