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