home *** CD-ROM | disk | FTP | other *** search
/ Amiga ACS 1998 #6 / amigaacscoverdisc1998-061998.iso / games / descent / source / main / terrain.c < prev    next >
C/C++ Source or Header  |  1998-06-08  |  13KB  |  535 lines

  1. /*
  2. THE COMPUTER CODE CONTAINED HEREIN IS THE SOLE PROPERTY OF PARALLAX
  3. SOFTWARE CORPORATION ("PARALLAX").  PARALLAX, IN DISTRIBUTING THE CODE TO
  4. END-USERS, AND SUBJECT TO ALL OF THE TERMS AND CONDITIONS HEREIN, GRANTS A
  5. ROYALTY-FREE, PERPETUAL LICENSE TO SUCH END-USERS FOR USE BY SUCH END-USERS
  6. IN USING, DISPLAYING,  AND CREATING DERIVATIVE WORKS THEREOF, SO LONG AS
  7. SUCH USE, DISPLAY OR CREATION IS FOR NON-COMMERCIAL, ROYALTY OR REVENUE
  8. FREE PURPOSES.  IN NO EVENT SHALL THE END-USER USE THE COMPUTER CODE
  9. CONTAINED HEREIN FOR REVENUE-BEARING PURPOSES.  THE END-USER UNDERSTANDS
  10. AND AGREES TO THE TERMS HEREIN AND ACCEPTS THE SAME BY USE OF THIS FILE.  
  11. COPYRIGHT 1993-1998 PARALLAX SOFTWARE CORPORATION.  ALL RIGHTS RESERVED.
  12. */
  13. /*
  14.  * $Source: f:/miner/source/main/rcs/terrain.c $
  15.  * $Revision: 2.0 $
  16.  * $Author: john $
  17.  * $Date: 1995/02/27 11:31:27 $
  18.  * 
  19.  * Code to render cool external-scene terrain
  20.  * 
  21.  * $Log: terrain.c $
  22.  * Revision 2.0  1995/02/27  11:31:27  john
  23.  * New version 2.0, which has no anonymous unions, builds with
  24.  * Watcom 10.0, and doesn't require parsing BITMAPS.TBL.
  25.  * 
  26.  * Revision 1.12  1994/12/03  00:18:00  matt
  27.  * Made endlevel sequence cut off early
  28.  * Made exit model and bit explosion always plot last (after all terrain)
  29.  * 
  30.  * Revision 1.11  1994/11/27  23:13:46  matt
  31.  * Made changes for new mprintf calling convention
  32.  * 
  33.  * Revision 1.10  1994/11/21  18:04:36  matt
  34.  * Fixed alloc/free problem with height array
  35.  * 
  36.  * Revision 1.9  1994/11/21  17:30:42  matt
  37.  * Properly free light array
  38.  * 
  39.  * Revision 1.8  1994/11/19  12:40:55  matt
  40.  * Added system to read endlevel data from file, and to make it work
  41.  * with any exit tunnel.
  42.  * 
  43.  * Revision 1.7  1994/11/16  11:49:44  matt
  44.  * Added code to rotate terrain to match mine
  45.  * 
  46.  * Revision 1.6  1994/11/02  16:22:59  matt
  47.  * Killed mprintf
  48.  * 
  49.  * Revision 1.5  1994/10/30  20:09:19  matt
  50.  * For endlevel: added big explosion at tunnel exit; made lights in tunnel 
  51.  * go out; made more explosions on walls.
  52.  * 
  53.  * Revision 1.4  1994/10/27  21:15:07  matt
  54.  * Added better error handling
  55.  * 
  56.  * Revision 1.3  1994/10/27  01:03:17  matt
  57.  * Made terrain renderer use aribtary point in height array as origin
  58.  * 
  59.  * Revision 1.2  1994/08/19  20:09:44  matt
  60.  * Added end-of-level cut scene with external scene
  61.  * 
  62.  * Revision 1.1  1994/08/17  20:20:49  matt
  63.  * Initial revision
  64.  * 
  65.  * 
  66.  */
  67.  
  68. #pragma off (unreferenced)
  69. static char rcsid[] = "$Id: terrain.c 2.0 1995/02/27 11:31:27 john Exp $";
  70. #pragma on (unreferenced)
  71.  
  72. #include <stdio.h>
  73. #include <stdlib.h>
  74. #include <string.h>
  75.  
  76. #include "3d.h"
  77. #include "error.h"
  78. #include "gr.h"
  79. #include "texmap.h"
  80. #include "iff.h"
  81. #include "mem.h"
  82. #include "mono.h"
  83.  
  84. #include "inferno.h"
  85. #include "textures.h"
  86. #include "object.h"
  87. #include "endlevel.h"
  88. #include "fireball.h"
  89.  
  90. #define GRID_MAX_SIZE    64
  91. #define GRID_SCALE    i2f(2*20)
  92. #define HEIGHT_SCALE    f1_0
  93.  
  94. int grid_w,grid_h;
  95.  
  96. g3s_uvl uvl_list1[] = { {0,0,0}, {f1_0,0,0},  {0,f1_0,0} };
  97. g3s_uvl uvl_list2[] = { {f1_0,0,0}, {f1_0,f1_0,0},  {0,f1_0,0} };
  98.  
  99. ubyte *height_array;
  100. ubyte *light_array;
  101.  
  102. #define HEIGHT(_i,_j) (height_array[(_i)*grid_w+(_j)])
  103. #define LIGHT(_i,_j) light_array[(_i)*grid_w+(_j)]
  104.  
  105. //!!#define HEIGHT(_i,_j)    height_array[(grid_h-1-j)*grid_w+(_i)]
  106. //!!#define LIGHT(_i,_j)        light_array[(grid_h-1-j)*grid_w+(_i)]
  107.  
  108. #define LIGHTVAL(_i,_j) (((fix) LIGHT(_i,_j))<<8)
  109.  
  110. g3s_point save_row[GRID_MAX_SIZE];
  111.  
  112. vms_vector start_point;
  113.  
  114. grs_bitmap *terrain_bm;
  115.  
  116. extern fix g3_get_surface_dotprod(g3s_point **list);
  117. #pragma aux g3_get_surface_dotprod "*" parm [esi] value [eax] modify exact [eax];
  118.  
  119. int terrain_outline=0;
  120.  
  121. void render_mine(int start_seg_num,fix eye_offset);
  122.  
  123. int org_i,org_j;
  124.  
  125. int mine_tiles_drawn;        //flags to tell if all 4 tiles under mine have drawn
  126.  
  127. draw_cell(int i,int j,g3s_point *p0,g3s_point *p1,g3s_point *p2,g3s_point *p3)
  128. {
  129.     g3s_point *pointlist[3];
  130.  
  131.     pointlist[0] = p0;
  132.     pointlist[1] = p1;
  133.     pointlist[2] = p3;
  134.     uvl_list1[0].l = LIGHTVAL(i,j);
  135.     uvl_list1[1].l = LIGHTVAL(i,j+1);
  136.     uvl_list1[2].l = LIGHTVAL(i+1,j);
  137.  
  138.     uvl_list1[0].u = (i)*f1_0/4; uvl_list1[0].v = (j)*f1_0/4;
  139.     uvl_list1[1].u = (i)*f1_0/4; uvl_list1[1].v = (j+1)*f1_0/4;
  140.     uvl_list1[2].u = (i+1)*f1_0/4;   uvl_list1[2].v = (j)*f1_0/4;
  141.  
  142.     g3_check_and_draw_tmap(3,pointlist,uvl_list1,terrain_bm,NULL,NULL);
  143.     if (terrain_outline) {
  144.         int lsave=Lighting_on;
  145.         Lighting_on=0;
  146.         gr_setcolor(BM_XRGB(31,0,0));
  147.         g3_draw_line(pointlist[0],pointlist[1]);
  148.         g3_draw_line(pointlist[2],pointlist[0]);
  149.         Lighting_on=lsave;
  150.     }
  151.  
  152.     pointlist[0] = p1;
  153.     pointlist[1] = p2;
  154.     uvl_list2[0].l = LIGHTVAL(i,j+1);
  155.     uvl_list2[1].l = LIGHTVAL(i+1,j+1);
  156.     uvl_list2[2].l = LIGHTVAL(i+1,j);
  157.  
  158.     uvl_list2[0].u = (i)*f1_0/4; uvl_list2[0].v = (j+1)*f1_0/4;
  159.     uvl_list2[1].u = (i+1)*f1_0/4;   uvl_list2[1].v = (j+1)*f1_0/4;
  160.     uvl_list2[2].u = (i+1)*f1_0/4;   uvl_list2[2].v = (j)*f1_0/4;
  161.  
  162.     g3_check_and_draw_tmap(3,pointlist,uvl_list2,terrain_bm,NULL,NULL);
  163.     if (terrain_outline) {
  164.         int lsave=Lighting_on;
  165.         Lighting_on=0;
  166.         gr_setcolor(BM_XRGB(31,0,0));
  167.         g3_draw_line(pointlist[0],pointlist[1]);
  168.         g3_draw_line(pointlist[1],pointlist[2]);
  169.         g3_draw_line(pointlist[2],pointlist[0]);
  170.         Lighting_on=lsave;
  171.     }
  172.  
  173.     if (i==org_i && j==org_j)
  174.         mine_tiles_drawn |= 1;
  175.     if (i==org_i-1 && j==org_j)
  176.         mine_tiles_drawn |= 2;
  177.     if (i==org_i && j==org_j-1)
  178.         mine_tiles_drawn |= 4;
  179.     if (i==org_i-1 && j==org_j-1)
  180.         mine_tiles_drawn |= 8;
  181.     
  182.     if (mine_tiles_drawn == 0xf) {
  183.         render_mine(exit_segnum,0);
  184.         //draw_exit_model();
  185.         mine_tiles_drawn=-1;
  186.         //if (ext_expl_playing)
  187.         //    draw_fireball(&external_explosion);
  188.     }
  189.  
  190. }
  191.  
  192. vms_vector y_cache[256];
  193. ubyte yc_flags[256];
  194.  
  195. extern vms_matrix surface_orient;
  196.  
  197. vms_vector *get_dy_vec(int h)
  198. {
  199.     vms_vector *dyp;
  200.  
  201.     dyp = &y_cache[h];
  202.  
  203.     if (!yc_flags[h]) {
  204.         vms_vector tv;
  205.  
  206.         //@@g3_rotate_delta_y(dyp,h*HEIGHT_SCALE);
  207.  
  208.         vm_vec_copy_scale(&tv,&surface_orient.uvec,h*HEIGHT_SCALE);
  209.         g3_rotate_delta_vec(dyp,&tv);
  210.  
  211.         yc_flags[h] = 1;
  212.     }
  213.  
  214.     return dyp;
  215.  
  216. }
  217.  
  218. int im=1;
  219.  
  220. void render_terrain(vms_vector *org_point,int org_2dx,int org_2dy)
  221. {
  222.     vms_vector delta_i,delta_j;        //delta_y;
  223.     g3s_point p,last_p,save_p_low,save_p_high;
  224.     g3s_point last_p2;
  225.     int i,j;
  226.     int low_i,high_i,low_j,high_j;
  227.     int viewer_i,viewer_j;
  228.     vms_vector tv;
  229.  
  230.     mine_tiles_drawn = 0;    //clear flags
  231.  
  232.     org_i = org_2dy;
  233.     org_j = org_2dx;
  234.  
  235.     low_i = 0;  high_i = grid_w-1;
  236.     low_j = 0;  high_j = grid_h-1;
  237.  
  238.     //@@start_point.x = org_point->x - GRID_SCALE*(org_i - low_i);
  239.     //@@start_point.z = org_point->z - GRID_SCALE*(org_j - low_j);
  240.     //@@start_point.y = org_point->y;
  241.  
  242.     memset(yc_flags,0,256);
  243.  
  244.     //Lighting_on = 0;
  245.     Interpolation_method = im;
  246.  
  247.     vm_vec_copy_scale(&tv,&surface_orient.rvec,GRID_SCALE);
  248.     g3_rotate_delta_vec(&delta_i,&tv);
  249.     vm_vec_copy_scale(&tv,&surface_orient.fvec,GRID_SCALE);
  250.     g3_rotate_delta_vec(&delta_j,&tv);
  251.  
  252.     vm_vec_scale_add(&start_point,org_point,&surface_orient.rvec,-(org_i - low_i)*GRID_SCALE);
  253.     vm_vec_scale_add2(&start_point,&surface_orient.fvec,-(org_j - low_j)*GRID_SCALE);
  254.  
  255.     vm_vec_sub(&tv,&Viewer->pos,&start_point);
  256.     viewer_i = vm_vec_dot(&tv,&surface_orient.rvec) / GRID_SCALE;
  257.     viewer_j = vm_vec_dot(&tv,&surface_orient.fvec) / GRID_SCALE;
  258.  
  259. //mprintf((0,"viewer_i,j = %d,%d\n",viewer_i,viewer_j));
  260.  
  261.     g3_rotate_point(&last_p,&start_point);
  262.     save_p_low = last_p;
  263.  
  264.     for (j=low_j;j<=high_j;j++) {
  265.         g3_add_delta_vec(&save_row[j],&last_p,get_dy_vec(HEIGHT(low_i,j)));
  266.         if (j==high_j)
  267.             save_p_high = last_p;
  268.         else
  269.             g3_add_delta_vec(&last_p,&last_p,&delta_j);
  270.     }
  271.  
  272.     for (i=low_i;i<viewer_i;i++) {
  273.  
  274.         g3_add_delta_vec(&save_p_low,&save_p_low,&delta_i);
  275.         last_p = save_p_low;
  276.         g3_add_delta_vec(&last_p2,&last_p,get_dy_vec(HEIGHT(i+1,low_j)));
  277.         
  278.         for (j=low_j;j<viewer_j;j++) {
  279.             g3s_point p2;
  280.  
  281.             g3_add_delta_vec(&p,&last_p,&delta_j);
  282.             g3_add_delta_vec(&p2,&p,get_dy_vec(HEIGHT(i+1,j+1)));
  283.  
  284.             draw_cell(i,j,&save_row[j],&save_row[j+1],&p2,&last_p2);
  285.  
  286.             last_p = p;
  287.             save_row[j] = last_p2;
  288.             last_p2 = p2;
  289.  
  290.         }
  291.  
  292.         vm_vec_negate(&delta_j);            //don't have a delta sub...
  293.  
  294.         g3_add_delta_vec(&save_p_high,&save_p_high,&delta_i);
  295.         last_p = save_p_high;
  296.         g3_add_delta_vec(&last_p2,&last_p,get_dy_vec(HEIGHT(i+1,high_j)));
  297.         
  298.         for (j=high_j-1;j>=viewer_j;j--) {
  299.             g3s_point p2;
  300.  
  301.             g3_add_delta_vec(&p,&last_p,&delta_j);
  302.             g3_add_delta_vec(&p2,&p,get_dy_vec(HEIGHT(i+1,j)));
  303.  
  304.             draw_cell(i,j,&save_row[j],&save_row[j+1],&last_p2,&p2);
  305.  
  306.             last_p = p;
  307.             save_row[j+1] = last_p2;
  308.             last_p2 = p2;
  309.  
  310.         }
  311.  
  312.         save_row[j+1] = last_p2;
  313.  
  314.         vm_vec_negate(&delta_j);        //restore sign of j
  315.  
  316.     }
  317.  
  318.     //now do i from other end
  319.  
  320.     vm_vec_negate(&delta_i);        //going the other way now...
  321.  
  322.     //@@start_point.x += (high_i-low_i)*GRID_SCALE;
  323.     vm_vec_scale_add2(&start_point,&surface_orient.rvec,(high_i-low_i)*GRID_SCALE);
  324.     g3_rotate_point(&last_p,&start_point);
  325.     save_p_low = last_p;
  326.  
  327.     for (j=low_j;j<=high_j;j++) {
  328.         g3_add_delta_vec(&save_row[j],&last_p,get_dy_vec(HEIGHT(high_i,j)));
  329.         if (j==high_j)
  330.             save_p_high = last_p;
  331.         else
  332.             g3_add_delta_vec(&last_p,&last_p,&delta_j);
  333.     }
  334.  
  335.     for (i=high_i-1;i>=viewer_i;i--) {
  336.  
  337.         g3_add_delta_vec(&save_p_low,&save_p_low,&delta_i);
  338.         last_p = save_p_low;
  339.         g3_add_delta_vec(&last_p2,&last_p,get_dy_vec(HEIGHT(i,low_j)));
  340.         
  341.         for (j=low_j;j<viewer_j;j++) {
  342.             g3s_point p2;
  343.  
  344.             g3_add_delta_vec(&p,&last_p,&delta_j);
  345.             g3_add_delta_vec(&p2,&p,get_dy_vec(HEIGHT(i,j+1)));
  346.  
  347.             draw_cell(i,j,&last_p2,&p2,&save_row[j+1],&save_row[j]);
  348.  
  349.             last_p = p;
  350.             save_row[j] = last_p2;
  351.             last_p2 = p2;
  352.  
  353.         }
  354.  
  355.         vm_vec_negate(&delta_j);            //don't have a delta sub...
  356.  
  357.         g3_add_delta_vec(&save_p_high,&save_p_high,&delta_i);
  358.         last_p = save_p_high;
  359.         g3_add_delta_vec(&last_p2,&last_p,get_dy_vec(HEIGHT(i,high_j)));
  360.         
  361.         for (j=high_j-1;j>=viewer_j;j--) {
  362.             g3s_point p2;
  363.  
  364.             g3_add_delta_vec(&p,&last_p,&delta_j);
  365.             g3_add_delta_vec(&p2,&p,get_dy_vec(HEIGHT(i,j)));
  366.  
  367.             draw_cell(i,j,&p2,&last_p2,&save_row[j+1],&save_row[j]);
  368.  
  369.             last_p = p;
  370.             save_row[j+1] = last_p2;
  371.             last_p2 = p2;
  372.  
  373.         }
  374.  
  375.         save_row[j+1] = last_p2;
  376.  
  377.         vm_vec_negate(&delta_j);        //restore sign of j
  378.  
  379.     }
  380.  
  381. }
  382.  
  383. free_height_array()
  384. {
  385.     free(height_array);
  386. }
  387.  
  388. void load_terrain(char *filename)
  389. {
  390.     grs_bitmap height_bitmap;
  391.     int iff_error;
  392.     int i,j;
  393.     ubyte h,min_h,max_h;
  394.  
  395.     iff_error = iff_read_bitmap(filename,&height_bitmap,BM_LINEAR,NULL);
  396.     if (iff_error != IFF_NO_ERROR) {
  397.         mprintf((1, "File %s - IFF error: %s",filename,iff_errormsg(iff_error)));
  398.         Error("File %s - IFF error: %s",filename,iff_errormsg(iff_error));
  399.     }
  400.  
  401.     if (height_array)
  402.         free(height_array);
  403.     else
  404.         atexit(free_height_array);        //first time
  405.  
  406.     grid_w = height_bitmap.bm_w;
  407.     grid_h = height_bitmap.bm_h;
  408.  
  409.     Assert(grid_w <= GRID_MAX_SIZE);
  410.     Assert(grid_h <= GRID_MAX_SIZE);
  411.  
  412.     height_array = height_bitmap.bm_data;
  413.  
  414.     max_h=0; min_h=255;
  415.     for (i=0;i<grid_w;i++)
  416.         for (j=0;j<grid_h;j++) {
  417.  
  418.             h = HEIGHT(i,j);
  419.  
  420.             if (h > max_h)
  421.                 max_h = h;
  422.  
  423.             if (h < min_h)
  424.                 min_h = h;
  425.         }
  426.  
  427.     for (i=0;i<grid_w;i++)
  428.         for (j=0;j<grid_h;j++)
  429.             HEIGHT(i,j) -= min_h;
  430.     
  431.  
  432. //    free(height_bitmap.bm_data);
  433.  
  434.     terrain_bm = terrain_bitmap;
  435.  
  436.     build_light_table();
  437. }
  438.  
  439.  
  440. get_pnt(vms_vector *p,int i,int j)
  441. {
  442.     p->x = GRID_SCALE*i;
  443.     p->z = GRID_SCALE*j;
  444.     p->y = HEIGHT(i,j)*HEIGHT_SCALE;
  445. }
  446.  
  447. vms_vector light = {0x2e14,0xe8f5,0x5eb8};
  448.  
  449. fix get_face_light(vms_vector *p0,vms_vector *p1,vms_vector *p2)
  450. {
  451.     vms_vector norm;
  452.  
  453.     vm_vec_normal(&norm,p0,p1,p2);
  454.  
  455.     return -vm_vec_dot(&norm,&light);
  456.  
  457. }
  458.  
  459.  
  460. fix get_avg_light(int i,int j)
  461. {
  462.     vms_vector pp,p[6];
  463.     fix sum;
  464.     int f;
  465.  
  466.     get_pnt(&pp,i,j);
  467.     get_pnt(&p[0],i-1,j);
  468.     get_pnt(&p[1],i,j-1);
  469.     get_pnt(&p[2],i+1,j-1);
  470.     get_pnt(&p[3],i+1,j);
  471.     get_pnt(&p[4],i,j+1);
  472.     get_pnt(&p[5],i-1,j+1);
  473.  
  474.     for (f=0,sum=0;f<6;f++)
  475.         sum += get_face_light(&pp,&p[f],&p[(f+1)%5]);
  476.  
  477.     return sum/6;
  478. }
  479.  
  480. free_light_table()
  481. {
  482.     if (light_array)
  483.         free(light_array);
  484.  
  485. }
  486.  
  487. build_light_table()
  488. {
  489.     int i,j;
  490.     fix l,l2,min_l=0x7fffffff,max_l=0;
  491.  
  492.  
  493.     if (light_array)
  494.         free(light_array);
  495.     else
  496.         atexit(free_light_table);        //first time
  497.  
  498.     //MALLOC(light_array,ubyte,grid_w*grid_h); //Won't comile -KRB
  499.     light_array = (ubyte *)malloc(grid_w*grid_h+(sizeof(ubyte))); //my hack -KRB
  500.     for (i=1;i<grid_w;i++)
  501.         for (j=1;j<grid_h;j++) {
  502.             l = get_avg_light(i,j);
  503.  
  504.             if (l > max_l)
  505.                 max_l = l;
  506.  
  507.             if (l < min_l)
  508.                 min_l = l;
  509.  
  510.             //printf("light %2d,%2d = %8x\n",i,j,l);
  511.         }
  512.  
  513.     for (i=1;i<grid_w;i++)
  514.         for (j=1;j<grid_h;j++) {
  515.  
  516.             l = get_avg_light(i,j);
  517.  
  518.             if (min_l == max_l) {
  519.                 LIGHT(i,j) = l>>8;
  520.                 continue;
  521.             }                
  522.  
  523.             l2 = fixdiv((l-min_l),(max_l-min_l));
  524.  
  525.             if (l2==f1_0)
  526.                 l2--;
  527.  
  528.             LIGHT(i,j) = l2>>8;
  529.  
  530.             //printf("light %2d,%2d = %4x\n",i,j,l2>>8);
  531.  
  532.         }
  533. }
  534.  
  535.