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