home *** CD-ROM | disk | FTP | other *** search
/ io Programmo 23 / IOPROG_23.ISO / SOFT / RAYCAST.ZIP / VOXGEN.CPP < prev    next >
Encoding:
C/C++ Source or Header  |  1995-10-01  |  15.3 KB  |  565 lines

  1. #include "types.h"
  2. #include "fixed.h"
  3. #include "utils.h"
  4. #include "screen.h"
  5. #include "palobj.h"
  6. #include <stdlib>
  7. #include <conio.h>
  8. #include <stddef.h>
  9. #include <fcntl.h>
  10. #include <fstream.h>
  11. #include <io.h>
  12. #include <stdio.h>
  13.  
  14. #define VOX_WIDTH 256
  15. #define VOX_HEIGHT 256
  16. #define VOX_LEVEL 8
  17.  
  18. #define MAX_SAFETY (1000000)
  19.  
  20. #define COLOR_INCR 16
  21. #define GREEN_COL_OFFSET (0*COLOR_INCR)
  22. #define BROWN_COL_OFFSET (0*COLOR_INCR)
  23. #define WHITE_COL_OFFSET (0*COLOR_INCR)
  24. #define BLUE_COL_OFFSET (12*COLOR_INCR)
  25.  
  26. #define MID_LIGHT 16
  27. #define MAX_LIGHT 31
  28. long LIGHT_SCALER;
  29. #define LIGHT_INCR 1
  30.  
  31. #define MAX_RIVERS 20
  32.  
  33. #define WATER_LINE 72
  34. #define TREE_LINE 160
  35. #define SNOW_LINE 208
  36.  
  37. MYFIXED BASE_NOISE;
  38. MYFIXED NOISE_SCALE;
  39. #define MAX_HEIGHT (convtoMYFIXED(256))
  40. #define MAX_REAL_HEIGHT 255
  41.  
  42. #define MAX_RAND 32767
  43.  
  44. #define MAX_DIRS 4
  45. #define DIR_RIGHT 0
  46. #define DIR_UP 1
  47. #define DIR_LEFT 2
  48. #define DIR_DOWN 3
  49.  
  50. #define X_COL TRUE
  51. #define Y_COL FALSE
  52.  
  53. #define ALT_PAL_F_NAME "whites.pal"
  54. #define COL_PAL_F_NAME "standard.pal"
  55.  
  56. #define real_alts image[0]
  57. #define colors image[1]
  58. #define alt_palette palette[0]
  59. #define col_palette palette[1]
  60.  
  61. long smooth_scaler;
  62.  
  63. typedef MYFIXED T_ALT;
  64. typedef MYFIXED * PT_ALT;
  65.  
  66. void Make_Vox_Line(
  67.    T_ALT base_top,
  68.    T_ALT base_bottom,
  69.    T_ALT noise,
  70.    short lev_count,
  71.    PT_ALT elev_buff);
  72.  
  73. inline long random(long range)
  74. {
  75. return (fixedmd((LONG)rand(), range, MAX_RAND));
  76. }
  77.  
  78. class Vox_Gobject : public palobj {
  79.    protected:
  80.       short dimensions;
  81.       PT_ALT * altitudes;
  82.       long Loc(short x, short y)
  83.       {
  84.       return ((y&(height-1))*width+(x&(width-1)));
  85.       };
  86.       void Make_Vox_Middle(
  87.          T_ALT noise,
  88.          short lev_count);
  89.       void Convert_Altitudes();
  90.       void Generate_Color_Map();
  91.       void Smooth_Map();
  92.       void Clear_Alts() {
  93.          for (short cur_row=0; cur_row<width; cur_row++)
  94.             delete altitudes[cur_row];
  95.          delete altitudes;
  96.       };
  97.       BOOL Progress_River(short cur_x, short cur_y, short dir_start);
  98.       void Make_Water(short cur_x, short cur_y);
  99.       void Make_Rivers();
  100.       short Next_Direction(short cur_direction);
  101.    public:
  102.       Vox_Gobject() : palobj(2)
  103.       {
  104.       };
  105.       void Reset() {
  106.          Clear_Alts();
  107.          delete real_alts;
  108.          delete colors;
  109.          delete alt_palette;
  110.          delete col_palette;
  111.       };
  112.       void Make_Vox_Map(short level_count, BOOL external_option);
  113.       ~Vox_Gobject()
  114.       {
  115.          Clear_Alts();
  116.          palobj::~palobj();
  117.       };
  118. };
  119.  
  120. void main(LONG argc, PCHAR argv[])
  121. {
  122.    if (argc<2)
  123.      return;
  124.  
  125.    cout << "Enter Base Noise (ex. 512)\n";
  126.    cin >> BASE_NOISE;
  127.    BASE_NOISE=convtoMYFIXED(BASE_NOISE);
  128.    cout << "Enter Noise Scaler (ex. 8192)\n";
  129.    cin >> NOISE_SCALE;
  130.    cout << "Enter Shadow Scaler (ex. 4096)\n";
  131.    cin >> LIGHT_SCALER;
  132.    cout << "Enter Smoothing effect (ex. 2)\n";
  133.    cin >> smooth_scaler;
  134.    char ch;
  135.    srand(strtoint(argv[1]));
  136.    Vox_Gobject bob;
  137.    if (!strnicmp(argv[argc-1], "EXTALT", 8)) {
  138.       bob.Make_Vox_Map(VOX_LEVEL, TRUE);
  139.    } else bob.Make_Vox_Map(VOX_LEVEL, FALSE);
  140.    setgmode(0x13);
  141.    bob.drawpalette(setpalette);
  142.    bob.show(screen,SCREEN_WIDTH,0,0);
  143.    ch=getch();
  144.    bob.drawpalette(setpalette,1);
  145.    bob.show(screen,SCREEN_WIDTH,0,0,1);
  146.    ch=getch();
  147.    if (argc>2) {
  148.       bob.assignoutfile(argv[2]);
  149.       bob.Write(0);
  150.    } /* endif */
  151.    if (argc>3) {
  152.       bob.assignoutfile(argv[3]);
  153.       bob.Write(1);
  154.    } /* endif */
  155.    setgmode(0x3);
  156. }
  157.  
  158. void Make_Vox_Line(
  159.    T_ALT base_top,
  160.    T_ALT base_bottom,
  161.    T_ALT noise,
  162.    short level_count,
  163.    PT_ALT elev_buff)
  164. {
  165.  
  166.    // is line already small enough to fill w/ endpoints
  167.    if (level_count==0) {
  168.       elev_buff[0] = base_top;
  169.       elev_buff[1] = base_bottom;
  170.       return;
  171.    } /* endif */
  172.  
  173.    // Nope, so get a middle altitude
  174.    MYFIXED y_mid=(base_top+base_bottom)/2;
  175.    y_mid+=(random(noise)-(noise/2));
  176.  
  177.    // Are there few enough points to fill w/ endpoints and middle?
  178.    if (level_count==1) {
  179.       elev_buff[0]=base_top;
  180.       elev_buff[1]=y_mid;
  181.       elev_buff[2]=base_bottom;
  182.       return;
  183.    } /* endif */
  184.  
  185.    // Nope, so we'll just have to divide the line into and process each half
  186.  
  187.    // Get new values for next level of recursion
  188.    short point_count=(1<<level_count)+1;
  189.    short point_middle=point_count/2;
  190.    T_ALT new_noise=fixedmult(noise, NOISE_SCALE);
  191.    short new_level_count=level_count-1;
  192.  
  193.    // Process top half
  194.    Make_Vox_Line(
  195.       base_top,
  196.       y_mid,
  197.       new_noise,
  198.       new_level_count,
  199.       elev_buff);
  200.  
  201.    // Process bottom half
  202.    Make_Vox_Line(
  203.       y_mid,
  204.       base_bottom,
  205.       new_noise,
  206.       new_level_count,
  207.       elev_buff+point_middle);
  208.  
  209. return;
  210. }
  211.  
  212. void Vox_Gobject::Make_Vox_Map(short lev_count, BOOL external_option)
  213. {
  214. // dimensions must be the 2^lev_count +1
  215. // don't ask why
  216.  
  217. dimensions=(1<<lev_count)+1;
  218. width=dimensions-1;
  219. height=dimensions-1;
  220. image_size=width*height;
  221.  
  222. //Allocate Initial Altitude Tables
  223.  
  224. if ((altitudes=new PT_ALT [dimensions])==NULL) {
  225.    return;
  226. } /* endif */
  227.  
  228. for (short cur_column=0; cur_column<dimensions; cur_column++) {
  229.    if ((altitudes[cur_column]=new T_ALT [dimensions])==NULL) {
  230.       return;
  231.    } /* endif */
  232. } /* endfor */
  233.  
  234. if (!external_option)
  235. {
  236.  
  237. // Init random values on four corners of map
  238.  
  239. T_ALT tl_corner, tr_corner, bl_corner, br_corner;
  240.  
  241. tl_corner=(MAX_HEIGHT/2) /* + (random(BASE_NOISE) - (BASE_NOISE/2)) */ ;
  242. tr_corner=(MAX_HEIGHT/2) /* + (random(BASE_NOISE) - (BASE_NOISE/2)) */ ;
  243. bl_corner=(MAX_HEIGHT/2) /* + (random(BASE_NOISE) - (BASE_NOISE/2)) */ ;
  244. br_corner=(MAX_HEIGHT/2) /* + (random(BASE_NOISE) - (BASE_NOISE/2)) */ ;
  245.  
  246. // Generate edges
  247.  
  248. // top
  249. Make_Vox_Line(
  250.    tl_corner,
  251.    bl_corner,
  252.    fixedmult(BASE_NOISE,NOISE_SCALE),
  253.    lev_count,
  254.    &(altitudes[0][0])
  255.    );
  256.  
  257. // right
  258. /*
  259. Make_Vox_Line(
  260.    tr_corner,
  261.    br_corner,
  262.    fixedmult(BASE_NOISE,NOISE_SCALE),
  263.    lev_count,
  264.    &(altitudes[dimensions-1][0])
  265.    );
  266. */
  267. memcpy(&(altitudes[dimensions-1][0]), &(altitudes[0][0]), sizeof(T_ALT)*dimensions);
  268.  
  269. PT_ALT temp_alt_buf=new T_ALT [dimensions];
  270. short cur_element;
  271.  
  272. // top
  273. Make_Vox_Line(      
  274.    tl_corner,
  275.    tr_corner,
  276.    fixedmult(BASE_NOISE,NOISE_SCALE),
  277.    lev_count,
  278.    temp_alt_buf);
  279.  
  280. for (cur_element=0; cur_element<dimensions; cur_element++) {
  281.    altitudes[cur_element][0]=temp_alt_buf[cur_element];
  282. } /* endfor */
  283.  
  284. // bottom
  285. /*
  286. Make_Vox_Line(
  287.    bl_corner,
  288.    br_corner,
  289.    fixedmult(BASE_NOISE,NOISE_SCALE),
  290.    lev_count,
  291.    temp_alt_buf);
  292. */
  293.  
  294. for (cur_element=0; cur_element<dimensions; cur_element++) {
  295.    altitudes[cur_element][dimensions-1]=temp_alt_buf[cur_element];
  296. } /* endfor */
  297.  
  298. delete temp_alt_buf;
  299.  
  300. // Now Generate 2D map
  301.  
  302. Make_Vox_Middle(
  303.    fixedmult(BASE_NOISE,NOISE_SCALE),
  304.    lev_count);
  305.  
  306. } else {
  307. FILE * fp;
  308. fp=fopen("terr.dat", "r+b");
  309. for (short cur_x=0; cur_x<width; cur_x++) {
  310.    fread(altitudes[cur_x], height, sizeof(T_ALT), fp);
  311. } /* endfor */
  312. }
  313.  
  314. // convert to bitmapable level altitudes
  315.  
  316. Convert_Altitudes();
  317.  
  318. // get rid of jaggedy look!
  319.  
  320. if (!external_option)
  321.    Smooth_Map();
  322.  
  323. // Generate colors based on altitudes
  324.  
  325. Generate_Color_Map();
  326.  
  327. // Draw some rivers, for viewing enjoyment
  328.  
  329. //Make_Rivers();
  330. }
  331.  
  332. void Vox_Gobject::Smooth_Map() {
  333.    PUCHAR temp_altitudes;
  334.    temp_altitudes=new UCHAR [width * height];
  335.    for (short cur_x=0; cur_x<width; cur_x++) {
  336.       for (short cur_y=0; cur_y<height; cur_y++) {
  337.          long sum=0;
  338.          for (short u=-smooth_scaler; u<=smooth_scaler; u++) {
  339.             for (short v=-smooth_scaler; v<=smooth_scaler; v++) {
  340.                sum+=real_alts[Loc((cur_x+u+width)&(width-1),(cur_y+v+height)&(height-1))];
  341.             }
  342.          }
  343.          temp_altitudes[Loc(cur_x, cur_y)]=(UCHAR)(sum/ ((2*smooth_scaler+1) *(2*smooth_scaler+1)));
  344.       } /* endfor */
  345.    } /* endfor */
  346.  
  347.    for (cur_x=0; cur_x<width; cur_x++) {
  348.       for (short cur_y=0; cur_y<height; cur_y++) {
  349.          real_alts[Loc(cur_x, cur_y)]=temp_altitudes[Loc(cur_x, cur_y)];
  350.          altitudes[cur_x][cur_y]=convtoMYFIXED(temp_altitudes[Loc(cur_x, cur_y)]);
  351.       }
  352.    }
  353.    delete temp_altitudes;
  354. }
  355.  
  356. void Vox_Gobject::Make_Vox_Middle(
  357.    T_ALT noise,
  358.    short lev_count)
  359. {
  360.    short base_stepper, half_stepper;
  361.    T_ALT cur_noise;
  362.    short cur_x, cur_y;
  363.    short cur_level;
  364.    short point_count;
  365.  
  366.    cur_noise=noise;
  367.    point_count=dimensions-1;
  368.    half_stepper=point_count;
  369.  
  370.    // Generate middle points for each level
  371.    for (cur_level=0; cur_level<lev_count; cur_level++) {
  372.       base_stepper=half_stepper;
  373.       half_stepper/=2;
  374.  
  375.       // Get mid points between levels corners
  376.       for (cur_x=half_stepper; cur_x < point_count; cur_x += base_stepper) {
  377.          for (cur_y=half_stepper; cur_y < point_count; cur_y += base_stepper) {
  378.             altitudes[cur_x][cur_y] = (altitudes[cur_x - half_stepper][cur_y - half_stepper] +
  379.                                                  altitudes[cur_x - half_stepper][cur_y + half_stepper] +
  380.                                                  altitudes[cur_x + half_stepper][cur_y - half_stepper] +
  381.                                                  altitudes[cur_x + half_stepper][cur_y + half_stepper]) / 4;
  382.             altitudes[cur_x][cur_y] += (random(cur_noise) - (cur_noise/2));
  383.          } /* endfor */
  384.       } /* endfor */
  385.  
  386.       // Get mid points on edges between corners
  387.       if (cur_level > 0) {
  388.  
  389.          // do mid points on x edges then the ones on y edges
  390.  
  391.          for (cur_x = half_stepper; cur_x < point_count; cur_x += base_stepper) {
  392.             for (cur_y = base_stepper; cur_y < point_count; cur_y += base_stepper) {
  393.                altitudes[cur_x][cur_y] = (altitudes[cur_x][cur_y - half_stepper] +
  394.                                                    altitudes[cur_x][cur_y + half_stepper] +
  395.                                                    altitudes[cur_x - half_stepper][cur_y] +
  396.                                                    altitudes[cur_x + half_stepper][cur_y]) / 4;
  397.                altitudes[cur_x][cur_y] += (random(cur_noise) - (cur_noise/2));
  398.             } /* endfor */
  399.          } /* endfor */
  400.  
  401.          for (cur_x = base_stepper; cur_x < point_count; cur_x += base_stepper) {
  402.             for (cur_y = half_stepper; cur_y < point_count; cur_y += base_stepper) {
  403.                altitudes[cur_x][cur_y] = (altitudes[cur_x][cur_y - half_stepper] +
  404.                                                    altitudes[cur_x][cur_y + half_stepper] +
  405.                                                    altitudes[cur_x - half_stepper][cur_y] +
  406.                                                    altitudes[cur_x + half_stepper][cur_y]) / 4;
  407.                altitudes[cur_x][cur_y] += (random(cur_noise) - (cur_noise/2));
  408.             } /* endfor */
  409.          } /* endfor */
  410.  
  411.       } /* endif */
  412.  
  413.       // Now change noise for next round through
  414.       cur_noise=fixedmult(cur_noise, NOISE_SCALE);
  415.    } /* endfor */
  416.  
  417. }
  418.  
  419. void Vox_Gobject::Convert_Altitudes()
  420. {
  421.    if ((real_alts= new UCHAR [image_size])==NULL) {
  422.       return;
  423.    } /* endif */
  424.  
  425.    // load up palette
  426.    if ((alt_palette= new UCHAR [PALETTE_SIZE])==NULL) {
  427.       return;
  428.    } /* endif */
  429.    fstream fp(ALT_PAL_F_NAME, ios::in | ios::out | ios::binary);
  430.    fp.read(alt_palette, PALETTE_SIZE);
  431.    fp.close();
  432.  
  433.    for (short cur_x=0; cur_x<width; cur_x++)
  434.       for (short cur_y=0; cur_y<height; cur_y++) {
  435.          if (altitudes[cur_x][cur_y]<0)
  436.             real_alts[Loc(cur_x, cur_y)]=0;
  437.          else if (altitudes[cur_x][cur_y]>=MAX_HEIGHT)
  438.             real_alts[Loc(cur_x, cur_y)]=MAX_REAL_HEIGHT;
  439.          else real_alts[Loc(cur_x, cur_y)]=(UCHAR)(convtoLONG(altitudes[cur_x][cur_y]));
  440.       }
  441.  
  442. }
  443.  
  444. void Vox_Gobject::Generate_Color_Map()
  445. {
  446.    if ((colors= new UCHAR [image_size])==NULL) {
  447.       return;
  448.    } /* endif */
  449.  
  450.    // load up palette
  451.    if ((col_palette= new UCHAR [PALETTE_SIZE])==NULL) {
  452.       return;
  453.    } /* endif */
  454.    fstream fp(COL_PAL_F_NAME, ios::in | ios::out | ios::binary);
  455.    fp.read(col_palette, PALETTE_SIZE);
  456.    fp.close();
  457.  
  458.    T_ALT alt_difference;
  459.    SHORT light;
  460.    UCHAR cur_alt;
  461.    for (short cur_x=0; cur_x<width; cur_x++) {
  462.       for (short cur_y=0; cur_y<height; cur_y++) {
  463.  
  464.          // find shadow on light
  465.          alt_difference=0;
  466.          alt_difference+=(altitudes[(cur_x+1) % width][cur_y]-altitudes[cur_x][cur_y]);
  467.          alt_difference+=(altitudes[cur_x][cur_y]-altitudes[(cur_x-1+width)%width][cur_y]);
  468.  
  469.          light=(alt_difference / LIGHT_SCALER)+MID_LIGHT;
  470.          if (light<0)
  471.             light=0;
  472.          if (light>MAX_LIGHT)
  473.             light=MAX_LIGHT;
  474.  
  475.          light*=LIGHT_INCR;
  476.  
  477.          cur_alt=real_alts[Loc(cur_x, cur_y)];
  478.  
  479.          // Decide upon terrain color
  480.          if (cur_alt < WATER_LINE) {
  481.             colors[Loc(cur_x, cur_y)]=light+GREEN_COL_OFFSET;
  482.          } else if (cur_alt < TREE_LINE)
  483.             colors[Loc(cur_x, cur_y)]=light+GREEN_COL_OFFSET;
  484.          else if (cur_alt < SNOW_LINE)
  485.             colors[Loc(cur_x, cur_y)]=light+BROWN_COL_OFFSET;
  486.          else colors[Loc(cur_x, cur_y)]=light+WHITE_COL_OFFSET;
  487.       } /* endfor */
  488.    } /* endfor */
  489. }
  490.  
  491. BOOL marked_spots[VOX_WIDTH * VOX_HEIGHT];
  492.  
  493. void Vox_Gobject::Make_Rivers() {
  494.    short num_rivers;
  495.    short w,h,cur_river;
  496.    for (w=0; w<width; w++) {
  497.       for (h=0; h<height; h++) {
  498.          marked_spots[Loc(w,h)]=FALSE;
  499.       } /* endfor */
  500.    } /* endfor */
  501.    num_rivers=random(MAX_RIVERS);
  502.    for (cur_river=0; cur_river<num_rivers; cur_river++) {
  503.       Progress_River(random(VOX_WIDTH), random(VOX_HEIGHT), random(MAX_DIRS));
  504.    }
  505. }
  506.  
  507. void Vox_Gobject::Make_Water(short cur_x, short cur_y) {
  508.          colors[Loc(cur_x, cur_y)]=(UCHAR)((short)(colors[Loc(cur_x, cur_y)]-GREEN_COL_OFFSET)/2
  509.                 +BLUE_COL_OFFSET);
  510. }
  511.  
  512. short Vox_Gobject::Next_Direction(short cur_direction) {
  513.    return ((cur_direction+1)%MAX_DIRS);
  514. }
  515.  
  516. BOOL Vox_Gobject::Progress_River(short cur_x, short cur_y, short start_dir) {
  517.    short this_alt;
  518.    short direction, dir_count;
  519.    BOOL found;
  520.  
  521.    direction=Next_Direction(start_dir);
  522.    if (!marked_spots[Loc(cur_x, cur_y)]) {
  523.       marked_spots[Loc(cur_x, cur_y)]=TRUE;
  524.       Make_Water(cur_x, cur_y);
  525.       this_alt=real_alts[Loc(cur_x, cur_y)]+2;
  526.       dir_count=0;
  527.       found=FALSE;
  528.       while ((!found)&&(dir_count<MAX_DIRS)) {
  529.       switch (direction) {
  530.          case DIR_RIGHT:
  531.             if (this_alt>=real_alts[Loc(cur_x+1, cur_y)]) {
  532.                found=Progress_River(cur_x+1, cur_y, direction);
  533.             }
  534.          break;
  535.       case DIR_UP:
  536.             if (this_alt>=real_alts[Loc(cur_x, cur_y+1)]) {
  537.                found=Progress_River(cur_x, cur_y+1, direction);
  538.             }
  539.          break;
  540.       case DIR_LEFT:
  541.             if (this_alt>=real_alts[Loc(cur_x-1, cur_y)]) {
  542.                found=Progress_River(cur_x-1, cur_y, direction);
  543.             }
  544.          break;
  545.       case DIR_DOWN:
  546.             if (this_alt>=real_alts[Loc(cur_x, cur_y-1)]) {
  547.                found=Progress_River(cur_x, cur_y-1, direction);
  548.             } /* endif */
  549.          break;
  550.       default:
  551.         break;
  552.       } /* endswitch */
  553.       dir_count++;
  554.       direction=Next_Direction(direction);
  555.       } /* endwhile */
  556.       return TRUE;
  557.    } else {
  558.       return FALSE;
  559.    } /* endif */
  560. }
  561.  
  562.  
  563.  
  564.  
  565.