www.pudn.com > VOXEM.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