]> icculus.org git repositories - btb/d2x.git/blob - main/terrain.c
reverting some networking stuff for now
[btb/d2x.git] / main / terrain.c
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-1999 PARALLAX SOFTWARE CORPORATION.  ALL RIGHTS RESERVED.
12 */
13
14 /*
15  * $Source: /cvs/cvsroot/d2x/main/terrain.c,v $
16  * $Revision: 1.1 $
17  * $Author: bradleyb $
18  * $Date: 2001-11-08 10:21:36 $
19  *
20  * FIXME: put description here
21  *
22  * $Log: not supported by cvs2svn $
23  *
24  */
25
26 #ifdef HAVE_CONFIG_H
27 #include <conf.h>
28 #endif
29
30 #include <stdio.h>
31 #include <stdlib.h>
32 #include <string.h>
33
34 #include "3d.h"
35 #include "error.h"
36 #include "gr.h"
37 #include "texmap.h"
38 #include "iff.h"
39 #include "u_mem.h"
40 #include "mono.h"
41
42 #include "inferno.h"
43 #include "textures.h"
44 #include "object.h"
45 #include "endlevel.h"
46 #include "fireball.h"
47
48 #define GRID_MAX_SIZE   64
49 #define GRID_SCALE      i2f(2*20)
50 #define HEIGHT_SCALE    f1_0
51
52 int grid_w,grid_h;
53
54 g3s_uvl uvl_list1[] = { {0,0,0}, {f1_0,0,0},  {0,f1_0,0} };
55 g3s_uvl uvl_list2[] = { {f1_0,0,0}, {f1_0,f1_0,0},  {0,f1_0,0} };
56
57 ubyte *height_array;
58 ubyte *light_array;
59
60 #define HEIGHT(_i,_j) (height_array[(_i)*grid_w+(_j)])
61 #define LIGHT(_i,_j) light_array[(_i)*grid_w+(_j)]
62
63 //!!#define HEIGHT(_i,_j)       height_array[(grid_h-1-j)*grid_w+(_i)]
64 //!!#define LIGHT(_i,_j)                light_array[(grid_h-1-j)*grid_w+(_i)]
65
66 #define LIGHTVAL(_i,_j) (((fix) LIGHT(_i,_j))<<8)
67
68 g3s_point save_row[GRID_MAX_SIZE];
69
70 vms_vector start_point;
71
72 grs_bitmap *terrain_bm;
73
74 int terrain_outline=0;
75
76 void render_mine(int start_seg_num,fix eye_offset);
77
78 int org_i,org_j;
79
80 int mine_tiles_drawn;           //flags to tell if all 4 tiles under mine have drawn
81
82
83 //      LINT: adding function prototypes
84 void build_light_table(void);
85 void free_light_table(void);
86
87
88 // ------------------------------------------------------------------------
89 void draw_cell(int i,int j,g3s_point *p0,g3s_point *p1,g3s_point *p2,g3s_point *p3)
90 {
91         g3s_point *pointlist[3];
92
93         pointlist[0] = p0;
94         pointlist[1] = p1;
95         pointlist[2] = p3;
96         uvl_list1[0].l = LIGHTVAL(i,j);
97         uvl_list1[1].l = LIGHTVAL(i,j+1);
98         uvl_list1[2].l = LIGHTVAL(i+1,j);
99
100         uvl_list1[0].u = (i)*f1_0/4; uvl_list1[0].v = (j)*f1_0/4;
101         uvl_list1[1].u = (i)*f1_0/4; uvl_list1[1].v = (j+1)*f1_0/4;
102         uvl_list1[2].u = (i+1)*f1_0/4;   uvl_list1[2].v = (j)*f1_0/4;
103
104         g3_check_and_draw_tmap(3,pointlist,uvl_list1,terrain_bm,NULL,NULL);
105         if (terrain_outline) {
106                 int lsave=Lighting_on;
107                 Lighting_on=0;
108                 gr_setcolor(BM_XRGB(31,0,0));
109                 g3_draw_line(pointlist[0],pointlist[1]);
110                 g3_draw_line(pointlist[2],pointlist[0]);
111                 Lighting_on=lsave;
112         }
113
114         pointlist[0] = p1;
115         pointlist[1] = p2;
116         uvl_list2[0].l = LIGHTVAL(i,j+1);
117         uvl_list2[1].l = LIGHTVAL(i+1,j+1);
118         uvl_list2[2].l = LIGHTVAL(i+1,j);
119
120         uvl_list2[0].u = (i)*f1_0/4; uvl_list2[0].v = (j+1)*f1_0/4;
121         uvl_list2[1].u = (i+1)*f1_0/4;   uvl_list2[1].v = (j+1)*f1_0/4;
122         uvl_list2[2].u = (i+1)*f1_0/4;   uvl_list2[2].v = (j)*f1_0/4;
123
124         g3_check_and_draw_tmap(3,pointlist,uvl_list2,terrain_bm,NULL,NULL);
125         if (terrain_outline) {
126                 int lsave=Lighting_on;
127                 Lighting_on=0;
128                 gr_setcolor(BM_XRGB(31,0,0));
129                 g3_draw_line(pointlist[0],pointlist[1]);
130                 g3_draw_line(pointlist[1],pointlist[2]);
131                 g3_draw_line(pointlist[2],pointlist[0]);
132                 Lighting_on=lsave;
133         }
134
135         if (i==org_i && j==org_j)
136                 mine_tiles_drawn |= 1;
137         if (i==org_i-1 && j==org_j)
138                 mine_tiles_drawn |= 2;
139         if (i==org_i && j==org_j-1)
140                 mine_tiles_drawn |= 4;
141         if (i==org_i-1 && j==org_j-1)
142                 mine_tiles_drawn |= 8;
143         
144         if (mine_tiles_drawn == 0xf) {
145                 render_mine(exit_segnum,0);
146                 //draw_exit_model();
147                 mine_tiles_drawn=-1;
148                 //if (ext_expl_playing)
149                 //      draw_fireball(&external_explosion);
150         }
151
152 }
153
154 vms_vector y_cache[256];
155 ubyte yc_flags[256];
156
157 extern vms_matrix surface_orient;
158
159 vms_vector *get_dy_vec(int h)
160 {
161         vms_vector *dyp;
162
163         dyp = &y_cache[h];
164
165         if (!yc_flags[h]) {
166                 vms_vector tv;
167
168                 //@@g3_rotate_delta_y(dyp,h*HEIGHT_SCALE);
169
170                 vm_vec_copy_scale(&tv,&surface_orient.uvec,h*HEIGHT_SCALE);
171                 g3_rotate_delta_vec(dyp,&tv);
172
173                 yc_flags[h] = 1;
174         }
175
176         return dyp;
177
178 }
179
180 int im=1;
181
182 void render_terrain(vms_vector *org_point,int org_2dx,int org_2dy)
183 {
184         vms_vector delta_i,delta_j;             //delta_y;
185         g3s_point p,last_p,save_p_low,save_p_high;
186         g3s_point last_p2;
187         int i,j;
188         int low_i,high_i,low_j,high_j;
189         int viewer_i,viewer_j;
190         vms_vector tv;
191
192         mine_tiles_drawn = 0;   //clear flags
193
194         org_i = org_2dy;
195         org_j = org_2dx;
196
197         low_i = 0;  high_i = grid_w-1;
198         low_j = 0;  high_j = grid_h-1;
199
200         //@@start_point.x = org_point->x - GRID_SCALE*(org_i - low_i);
201         //@@start_point.z = org_point->z - GRID_SCALE*(org_j - low_j);
202         //@@start_point.y = org_point->y;
203
204         memset(yc_flags,0,256);
205
206         //Lighting_on = 0;
207         Interpolation_method = im;
208
209         vm_vec_copy_scale(&tv,&surface_orient.rvec,GRID_SCALE);
210         g3_rotate_delta_vec(&delta_i,&tv);
211         vm_vec_copy_scale(&tv,&surface_orient.fvec,GRID_SCALE);
212         g3_rotate_delta_vec(&delta_j,&tv);
213
214         vm_vec_scale_add(&start_point,org_point,&surface_orient.rvec,-(org_i - low_i)*GRID_SCALE);
215         vm_vec_scale_add2(&start_point,&surface_orient.fvec,-(org_j - low_j)*GRID_SCALE);
216
217         vm_vec_sub(&tv,&Viewer->pos,&start_point);
218         viewer_i = vm_vec_dot(&tv,&surface_orient.rvec) / GRID_SCALE;
219         viewer_j = vm_vec_dot(&tv,&surface_orient.fvec) / GRID_SCALE;
220
221 //mprintf((0,"viewer_i,j = %d,%d\n",viewer_i,viewer_j));
222
223         g3_rotate_point(&last_p,&start_point);
224         save_p_low = last_p;
225
226         for (j=low_j;j<=high_j;j++) {
227                 g3_add_delta_vec(&save_row[j],&last_p,get_dy_vec(HEIGHT(low_i,j)));
228                 if (j==high_j)
229                         save_p_high = last_p;
230                 else
231                         g3_add_delta_vec(&last_p,&last_p,&delta_j);
232         }
233
234         for (i=low_i;i<viewer_i;i++) {
235
236                 g3_add_delta_vec(&save_p_low,&save_p_low,&delta_i);
237                 last_p = save_p_low;
238                 g3_add_delta_vec(&last_p2,&last_p,get_dy_vec(HEIGHT(i+1,low_j)));
239                 
240                 for (j=low_j;j<viewer_j;j++) {
241                         g3s_point p2;
242
243                         g3_add_delta_vec(&p,&last_p,&delta_j);
244                         g3_add_delta_vec(&p2,&p,get_dy_vec(HEIGHT(i+1,j+1)));
245
246                         draw_cell(i,j,&save_row[j],&save_row[j+1],&p2,&last_p2);
247
248                         last_p = p;
249                         save_row[j] = last_p2;
250                         last_p2 = p2;
251
252                 }
253
254                 vm_vec_negate(&delta_j);                        //don't have a delta sub...
255
256                 g3_add_delta_vec(&save_p_high,&save_p_high,&delta_i);
257                 last_p = save_p_high;
258                 g3_add_delta_vec(&last_p2,&last_p,get_dy_vec(HEIGHT(i+1,high_j)));
259                 
260                 for (j=high_j-1;j>=viewer_j;j--) {
261                         g3s_point p2;
262
263                         g3_add_delta_vec(&p,&last_p,&delta_j);
264                         g3_add_delta_vec(&p2,&p,get_dy_vec(HEIGHT(i+1,j)));
265
266                         draw_cell(i,j,&save_row[j],&save_row[j+1],&last_p2,&p2);
267
268                         last_p = p;
269                         save_row[j+1] = last_p2;
270                         last_p2 = p2;
271
272                 }
273
274                 save_row[j+1] = last_p2;
275
276                 vm_vec_negate(&delta_j);                //restore sign of j
277
278         }
279
280         //now do i from other end
281
282         vm_vec_negate(&delta_i);                //going the other way now...
283
284         //@@start_point.x += (high_i-low_i)*GRID_SCALE;
285         vm_vec_scale_add2(&start_point,&surface_orient.rvec,(high_i-low_i)*GRID_SCALE);
286         g3_rotate_point(&last_p,&start_point);
287         save_p_low = last_p;
288
289         for (j=low_j;j<=high_j;j++) {
290                 g3_add_delta_vec(&save_row[j],&last_p,get_dy_vec(HEIGHT(high_i,j)));
291                 if (j==high_j)
292                         save_p_high = last_p;
293                 else
294                         g3_add_delta_vec(&last_p,&last_p,&delta_j);
295         }
296
297         for (i=high_i-1;i>=viewer_i;i--) {
298
299                 g3_add_delta_vec(&save_p_low,&save_p_low,&delta_i);
300                 last_p = save_p_low;
301                 g3_add_delta_vec(&last_p2,&last_p,get_dy_vec(HEIGHT(i,low_j)));
302                 
303                 for (j=low_j;j<viewer_j;j++) {
304                         g3s_point p2;
305
306                         g3_add_delta_vec(&p,&last_p,&delta_j);
307                         g3_add_delta_vec(&p2,&p,get_dy_vec(HEIGHT(i,j+1)));
308
309                         draw_cell(i,j,&last_p2,&p2,&save_row[j+1],&save_row[j]);
310
311                         last_p = p;
312                         save_row[j] = last_p2;
313                         last_p2 = p2;
314
315                 }
316
317                 vm_vec_negate(&delta_j);                        //don't have a delta sub...
318
319                 g3_add_delta_vec(&save_p_high,&save_p_high,&delta_i);
320                 last_p = save_p_high;
321                 g3_add_delta_vec(&last_p2,&last_p,get_dy_vec(HEIGHT(i,high_j)));
322                 
323                 for (j=high_j-1;j>=viewer_j;j--) {
324                         g3s_point p2;
325
326                         g3_add_delta_vec(&p,&last_p,&delta_j);
327                         g3_add_delta_vec(&p2,&p,get_dy_vec(HEIGHT(i,j)));
328
329                         draw_cell(i,j,&p2,&last_p2,&save_row[j+1],&save_row[j]);
330
331                         last_p = p;
332                         save_row[j+1] = last_p2;
333                         last_p2 = p2;
334
335                 }
336
337                 save_row[j+1] = last_p2;
338
339                 vm_vec_negate(&delta_j);                //restore sign of j
340
341         }
342
343 }
344
345 void free_height_array()
346 {
347         d_free(height_array);
348 }
349
350 void load_terrain(char *filename)
351 {
352         grs_bitmap height_bitmap;
353         int iff_error;
354         int i,j;
355         ubyte h,min_h,max_h;
356
357         iff_error = iff_read_bitmap(filename,&height_bitmap,BM_LINEAR,NULL);
358         if (iff_error != IFF_NO_ERROR) {
359                 mprintf((1, "File %s - IFF error: %s",filename,iff_errormsg(iff_error)));
360                 Error("File %s - IFF error: %s",filename,iff_errormsg(iff_error));
361         }
362
363         if (height_array)
364                 d_free(height_array);
365         else
366                 atexit(free_height_array);              //first time
367
368         grid_w = height_bitmap.bm_w;
369         grid_h = height_bitmap.bm_h;
370
371         Assert(grid_w <= GRID_MAX_SIZE);
372         Assert(grid_h <= GRID_MAX_SIZE);
373
374         height_array = height_bitmap.bm_data;
375
376         max_h=0; min_h=255;
377         for (i=0;i<grid_w;i++)
378                 for (j=0;j<grid_h;j++) {
379
380                         h = HEIGHT(i,j);
381
382                         if (h > max_h)
383                                 max_h = h;
384
385                         if (h < min_h)
386                                 min_h = h;
387                 }
388
389         for (i=0;i<grid_w;i++)
390                 for (j=0;j<grid_h;j++)
391                         HEIGHT(i,j) -= min_h;
392         
393
394 //      d_free(height_bitmap.bm_data);
395
396         terrain_bm = terrain_bitmap;
397
398         build_light_table();
399 }
400
401
402 void get_pnt(vms_vector *p,int i,int j)
403 {
404         p->x = GRID_SCALE*i;
405         p->z = GRID_SCALE*j;
406         p->y = HEIGHT(i,j)*HEIGHT_SCALE;
407 }
408
409 vms_vector light = {0x2e14,0xe8f5,0x5eb8};
410
411 fix get_face_light(vms_vector *p0,vms_vector *p1,vms_vector *p2)
412 {
413         vms_vector norm;
414
415         vm_vec_normal(&norm,p0,p1,p2);
416
417         return -vm_vec_dot(&norm,&light);
418
419 }
420
421
422 fix get_avg_light(int i,int j)
423 {
424         vms_vector pp,p[6];
425         fix sum;
426         int f;
427
428         get_pnt(&pp,i,j);
429         get_pnt(&p[0],i-1,j);
430         get_pnt(&p[1],i,j-1);
431         get_pnt(&p[2],i+1,j-1);
432         get_pnt(&p[3],i+1,j);
433         get_pnt(&p[4],i,j+1);
434         get_pnt(&p[5],i-1,j+1);
435
436         for (f=0,sum=0;f<6;f++)
437                 sum += get_face_light(&pp,&p[f],&p[(f+1)%5]);
438
439         return sum/6;
440 }
441
442 void free_light_table()
443 {
444         if (light_array)
445                 d_free(light_array);
446
447 }
448
449 void build_light_table()
450 {
451         int i,j;
452         fix l,l2,min_l=0x7fffffff,max_l=0;
453
454
455         if (light_array)
456                 d_free(light_array);
457         else
458                 atexit(free_light_table);               //first time
459
460         MALLOC(light_array,ubyte,grid_w*grid_h);
461
462         for (i=1;i<grid_w;i++)
463                 for (j=1;j<grid_h;j++) {
464                         l = get_avg_light(i,j);
465
466                         if (l > max_l)
467                                 max_l = l;
468
469                         if (l < min_l)
470                                 min_l = l;
471
472                         //printf("light %2d,%2d = %8x\n",i,j,l);
473                 }
474
475         for (i=1;i<grid_w;i++)
476                 for (j=1;j<grid_h;j++) {
477
478                         l = get_avg_light(i,j);
479
480                         if (min_l == max_l) {
481                                 LIGHT(i,j) = l>>8;
482                                 continue;
483                         }                               
484
485                         l2 = fixdiv((l-min_l),(max_l-min_l));
486
487                         if (l2==f1_0)
488                                 l2--;
489
490                         LIGHT(i,j) = l2>>8;
491
492                         //printf("light %2d,%2d = %4x\n",i,j,l2>>8);
493
494                 }
495 }