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