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