source: golgotha/src/golg/map_vert.cc @ 80

Last change on this file since 80 was 80, checked in by Sam Hocevar, 11 years ago
  • Adding the Golgotha source code. Not sure what's going to be interesting in there, but since it's all public domain, there's certainly stuff to pick up.
File size: 17.0 KB
Line 
1/********************************************************************** <BR>
2  This file is part of Crack dot Com's free source code release of
3  Golgotha. <a href="http://www.crack.com/golgotha_release"> <BR> for
4  information about compiling & licensing issues visit this URL</a>
5  <PRE> If that doesn't help, contact Jonathan Clark at
6  golgotha_source@usa.net (Subject should have "GOLG" in it)
7***********************************************************************/
8
9#include "map.hh"
10#include "map_vert.hh"
11#include "math/trig.hh"
12#include "light.hh"
13#include "tick_count.hh"
14#include "g1_render.hh"
15#include "map_man.hh"
16#include "compress/rle.hh"
17#include "loaders/dir_save.hh"
18#include "saver_id.hh"
19#include "saver.hh"
20#include "light.hh"
21#include "objs/model_collide.hh"
22#include "time/profile.hh"
23#include "tile.hh"
24#include "map_cell.hh"
25
26i4_profile_class pf_get_map_height("get_map_height");
27i4_profile_class pf_calc_height_pitch_roll("calc_height_pitch_roll");
28i4_profile_class pf_calc_pitch_roll("calc_pitch_roll");
29i4_profile_class pf_recalc_light_sum("recalc_light_sum");
30i4_profile_class pf_terrain_height("terrain_height");
31
32
33void g1_map_vertex_class::init()
34{
35  shadow_subtract=0;
36  light_sum=0x80000000;
37  normal=0x8000;
38  dynamic_light=0;
39
40  height=5;
41
42  flags=0;
43  clip_code=0;
44}
45
46void g1_map_vertex_class::wave_transform(i4_transform_class &t, float map_x, float map_y)
47{
48#if 0
49  int tick=g1_tick_counter;
50
51  float lx = map_x + cos((tick+map_x) * 0.1)*0.1;
52  float ly = map_y + cos((tick+map_y) * 0.01)*0.1;
53  float lh = get_height() + cos((tick+(map_y+map_x)*10.0) * 0.2)*0.1;
54
55  tick++;
56  float nx = map_x + cos((tick+map_x) * 0.1)*0.1;
57  float ny = map_y + cos((tick+map_y) * 0.01)*0.1;
58  float nh = get_height() + cos((tick+(map_y+map_x)*10.0) * 0.2)*0.1;
59
60
61  t.transform(i4_3d_point_class(lx+(nx-lx)*g1_render.frame_ratio,
62                                ly+(ny-ly)*g1_render.frame_ratio,
63                                lh+(nh-lh)*g1_render.frame_ratio),
64              v);
65#else
66  t.transform(i4_3d_point_class(map_x, map_y, t_height), v);
67#endif
68}
69
70void g1_map_class::calc_height_pitch_roll(i4_float x, i4_float y, i4_float z,
71                                          i4_float &height, i4_float &pitch, i4_float &roll)
72{
73  pf_calc_height_pitch_roll.start();
74 
75  i4_3d_vector normal;
76 
77  sw32 ix = i4_f_to_i(x);
78  sw32 iy = i4_f_to_i(y);
79
80  if (!(ix>=0 && iy>=0 && ix<w && iy<h))
81    i4_error("off map");
82
83   
84  g1_map_cell_class *c = cell(ix,iy); 
85
86  i4_3d_vector ray(0,0,-5);
87  float h;
88  i4_bool check_with_object=i4_F;
89       
90  g1_object_chain_class *chain=c->get_solid_list();
91  for (;chain; chain=chain->next_solid())
92    if (chain->object->flags & g1_object_class::CAN_DRIVE_ON)
93    {
94      g1_object_class *o=chain->object;       
95
96      if (g1_model_collide_polygonal(o, o->draw_params, i4_3d_vector(x,y,z+0.2), ray, normal))
97      {
98        height=z+0.2+ray.z;
99        pitch = i4_atan2(normal.x,sqrt(normal.z*normal.z  + normal.y*normal.y));
100        roll  = i4_atan2(-normal.y,sqrt(normal.z*normal.z + normal.x*normal.x));
101
102        check_with_object=i4_T;
103       
104        if (ray.z>-0.4)    // if we are near the object don't check terrain
105        {
106          pf_calc_height_pitch_roll.stop();
107          return;
108        }
109
110        r1_texture_handle han = g1_tile_man.get_texture(c->type);   
111        if (han==g1_tile_man.get_pink())    // don't check pink surfaces
112        {
113          pf_calc_height_pitch_roll.stop();
114          return;
115        }
116
117      }
118    }
119
120
121  x-=ix;
122  y-=iy;
123
124
125
126  i4_3d_vector u,v;
127  if (x>y)
128  {
129    g1_map_vertex_class *v1=verts+ ix + iy * (w+1), *v2,*v3;
130    v2=v1+1;
131    v3=v2+w+1;   
132
133    i4_float z1=v1->get_height(), z2=v2->get_height(), z3=v3->get_height();   
134
135    u=i4_3d_vector(-1,0,z1-z2);
136    v=i4_3d_vector(0,1,z3-z2);
137    h=z2+(z1-z2)*(1-x) + (z3-z2)*y;
138  }
139  else
140  {
141    g1_map_vertex_class *v1=verts+ ix + iy * (w+1), *v2,*v3;
142    v2=v1+w+1;
143    v3=v2+1;   
144
145    i4_float z1=v1->get_height(), z2=v2->get_height(), z3=v3->get_height();   
146
147    u=i4_3d_vector(1,0,z3-z2);
148    v=i4_3d_vector(0,-1,z1-z2);
149    h=z2+(z1-z2)*(1-y) + (z3-z2)*x;
150  }
151
152
153  if ((check_with_object && h>height && h-0.2<z) || !check_with_object)
154  {   
155    normal.cross(v,u);
156    pitch = i4_atan2(normal.x,sqrt(normal.z*normal.z  + normal.y*normal.y));
157    roll  = i4_atan2(-normal.y,sqrt(normal.z*normal.z + normal.x*normal.x));
158    height=h;
159  }
160
161  pf_calc_height_pitch_roll.stop();
162}
163
164
165
166i4_float g1_map_class::map_height(i4_float x, i4_float y, i4_float z) const
167{
168 
169  sw32 ix = i4_f_to_i(x);
170  sw32 iy = i4_f_to_i(y);
171
172  if (!(ix>=0 && iy>=0 && ix<w && iy<h))
173  {
174    return 1000;
175  }
176
177  g1_map_cell_class *c = cell(ix,iy); 
178
179  i4_3d_vector normal;
180  i4_bool check_with_object=i4_F;
181  float height, h;
182 
183  g1_object_chain_class *chain=c->get_solid_list();
184  for (;chain; chain=chain->next_solid())
185    if (chain->object->flags & g1_object_class::CAN_DRIVE_ON)
186    {
187      g1_object_class *o=chain->object;       
188      i4_3d_vector ray(0,0,-5);
189      if (g1_model_collide_polygonal(o, o->draw_params, i4_3d_vector(x,y,z+0.2), ray, normal))
190      {
191        height=z+0.2+ray.z;
192        if (ray.z>-0.4)    // if we are near the object don't check terrain
193        {
194          return height;
195        }
196       
197        r1_texture_handle han = g1_tile_man.get_texture(c->type);   
198        if (han==g1_tile_man.get_pink())    // don't check pink surfaces
199        {
200          return height;
201        }
202
203        check_with_object=i4_T;
204      }
205
206    }
207 
208  x-=ix;
209  y-=iy;
210
211  if (x>y)
212  {
213    g1_map_vertex_class *v1=verts+ ix + iy * (w+1), *v2,*v3;
214    v2=v1+1;
215    v3=v2+w+1;
216   
217    i4_float z1=v1->get_height(), z2=v2->get_height(), z3=v3->get_height();   
218    h=z2+(z1-z2)*(1-x) + (z3-z2)*y;   
219  }
220  else
221  {
222    g1_map_vertex_class *v1=verts+ ix + iy * (w+1), *v2,*v3;
223    v2=v1+w+1;
224    v3=v2+1;   
225   
226    i4_float z1=v1->get_height(), z2=v2->get_height(), z3=v3->get_height();   
227    h=z2+(z1-z2)*(1-y) + (z3-z2)*x;   
228  }
229 
230  if ((check_with_object && h>height && h-0.2<z) || !check_with_object)
231  {
232    return h;
233  }
234  else
235  {
236    return height;
237  }
238}
239
240i4_float g1_map_class::terrain_height(i4_float x, i4_float y) const
241{
242  pf_terrain_height.start();
243 
244  sw32 ix=i4_f_to_i(x), iy=i4_f_to_i(y);
245
246  x-=ix;
247  y-=iy;
248
249  float ret=0;
250  if (x>y)
251  {
252    g1_map_vertex_class *v1=verts+ ix + iy * (w+1), *v2,*v3;
253    v2=v1+1;
254    v3=v2+w+1;
255 
256    i4_float z1=v1->get_height(), z2=v2->get_height(), z3=v3->get_height();
257    ret=z2+(z1-z2)*(1-x) + (z3-z2)*y;
258  }
259  else
260  {
261    g1_map_vertex_class *v1=verts+ ix + iy * (w+1), *v2,*v3;
262    v2=v1+w+1;
263    v3=v2+1;   
264 
265    i4_float z1=v1->get_height(), z2=v2->get_height(), z3=v3->get_height();
266    ret=z2+(z1-z2)*(1-y) + (z3-z2)*x;
267  } 
268
269
270 
271  pf_terrain_height.stop();
272  return ret;
273}
274
275
276
277void g1_map_class::calc_pitch_and_roll(i4_float x, i4_float y, i4_float z,
278                                       i4_float &pitch, i4_float &roll)
279{
280  pf_calc_pitch_roll.start();
281 
282  i4_3d_vector normal;
283  sw32 ix=i4_f_to_i(x), iy=i4_f_to_i(y);
284
285  x-=(i4_float)ix;
286  y-=(i4_float)iy;
287
288  g1_map_cell_class *c = cell(ix,iy); 
289
290  if (!(ix>=0 && iy>=0 && ix<w && iy<h))
291    i4_error("off map");
292
293  g1_object_chain_class *chain=c->get_solid_list();
294  for (;chain; chain=chain->next_solid())
295    if (chain->object->flags & g1_object_class::CAN_DRIVE_ON)
296    {
297      g1_object_class *o=chain->object;       
298      i4_3d_vector ray(0,0,-5);
299      if (g1_model_collide_polygonal(o, o->draw_params, i4_3d_vector(x,y,z+0.2), ray, normal))
300      {
301        pitch = i4_atan2(normal.x,sqrt(normal.z*normal.z  + normal.y*normal.y));
302        roll  = i4_atan2(-normal.y,sqrt(normal.z*normal.z + normal.x*normal.x));
303        pf_calc_pitch_roll.stop();
304        return ;
305      }
306    }
307
308
309 
310  if (x>y)
311  {
312    g1_map_vertex_class *v1=verts+ ix + iy * (w+1), *v2,*v3;
313    v2=v1+1;
314    v3=v2+w+1;   
315
316    i4_float z1=v1->get_height(), z2=v2->get_height(), z3=v3->get_height();   
317
318    i4_3d_vector u=i4_3d_vector(-1,0,z1-z2), v=i4_3d_vector(0,1,z3-z2);
319    normal.cross(v,u);
320  }
321  else
322  {
323    g1_map_vertex_class *v1=verts+ ix + iy * (w+1), *v2,*v3;
324    v2=v1+w+1;
325    v3=v2+1;   
326
327    i4_float z1=v1->get_height(), z2=v2->get_height(), z3=v3->get_height();   
328
329    i4_3d_vector u=i4_3d_vector(1,0,z3-z2), v=i4_3d_vector(0,-1,z1-z2);
330    normal.cross(v,u);
331  }
332
333  pitch = i4_atan2(normal.x,sqrt(normal.z*normal.z  + normal.y*normal.y));
334  roll  = i4_atan2(-normal.y,sqrt(normal.z*normal.z + normal.x*normal.x));
335  pf_calc_pitch_roll.stop();
336}
337
338void g1_map_class::calc_terrain_normal(i4_float x, i4_float y, i4_3d_vector &normal)
339{
340  sw32 ix=i4_f_to_i(x), iy=i4_f_to_i(y);
341  g1_map_cell_class *c=cells + ix + iy * width();
342
343  if (x>y)
344    c->get_bottom_right_normal(normal,ix,iy);
345  else
346    c->get_top_left_normal(normal,ix,iy);
347}
348
349
350void g1_map_class::change_vert_height(sw32 x, sw32 y, w8 new_height)
351{
352  g1_map_vertex_class *v=verts + x + y*(w+1);
353  v->height=new_height;
354  v->normal=0x8000;
355  v->light_sum=0x80000000;
356}
357
358
359void g1_map_vertex_class::recalc_normal(int x, int y)
360{
361  i4_3d_vector sum(0,0,0), v,v2;
362  g1_map_cell_class *c=g1_get_map()->cell(x,y);
363  int mw=g1_get_map()->width(), mh=g1_get_map()->height();
364
365  I4_ASSERT(x<=mw && y<=mh, "recalc normal : vert out of range");
366
367  if (y<mh)
368  {
369    if (x>0)
370    {
371      c[-1].get_bottom_right_normal(v, x-1, y);
372      sum+=v;
373    }
374
375    if (x<mw)
376    {
377      c[0].get_top_left_normal(v, x,y);
378      c[0].get_bottom_right_normal(v2, x,y);
379     
380      v+=v2;
381      v.normalize();
382      sum+=v;
383    }
384  }
385
386  if (y>0)
387  {
388    if (x<mw)
389    {
390      c[-mw].get_top_left_normal(v, x,y-1);
391      sum+=v;
392    }
393
394    if (x>0)
395    {
396      c[-mw-1].get_top_left_normal(v, x-1,y-1);
397      c[-mw-1].get_bottom_right_normal(v2, x-1,y-1);
398      v+=v2;
399      v.normalize();
400
401      sum+=v;
402    }
403  }
404
405  sum.normalize();
406  normal = g1_normal_to_16(sum);
407}
408
409void g1_map_class::get_illumination_light(i4_float wx, i4_float wy,
410                                          i4_float &red,
411                                          i4_float &green,
412                                          i4_float &blue)
413{
414  sw32 ix=i4_f_to_i(wx), iy=i4_f_to_i(wy);
415
416  i4_float x=wx-ix, y=wy-iy;
417
418  g1_map_vertex_class *v1,*v2,*v3;
419  i4_float r[3],g[3],b[3];
420
421  if (x>y)
422  {
423    v1=verts+ix+iy*(w+1);
424    v2=v1+1;
425    v3=v2+w+1;
426   
427    v1->get_rgb(r[0],g[0],b[0], ix,   iy);
428    v2->get_rgb(r[1],g[1],b[1], ix+1, iy);
429    v3->get_rgb(r[2],g[2],b[2], ix+1, iy+1);   
430
431    red=r[1]+(r[0]-r[1])*(1-x) + (r[2]-r[2])*y;
432    green=g[1]+(g[0]-g[1])*(1-x) + (g[2]-g[2])*y;
433    blue=b[1]+(b[0]-b[1])*(1-x) + (b[2]-b[2])*y;
434
435  }
436  else
437  {
438    v1=verts+ix+iy*(w+1);
439    v2=v1+w+1;
440    v3=v2+1;
441   
442    v1->get_rgb(r[0],g[0],b[0], ix,  iy);
443    v2->get_rgb(r[1],g[1],b[1], ix,  iy+1);
444    v3->get_rgb(r[2],g[2],b[2], ix+1,iy+1);   
445
446    red=r[1]+(r[0]-r[1])*(1-y) + (r[2]-r[1])*x;
447    green=g[1]+(g[0]-g[1])*(1-y) + (g[2]-g[1])*x;
448    blue=b[1]+(b[0]-b[1])*(1-y) + (b[2]-b[1])*x;
449  }
450
451}
452
453
454float g1_map_vertex_class::get_non_dynamic_ligth_intensity(int cvx, int cvy)
455{
456  i4_3d_vector n;
457  get_normal(n, cvx, cvy);
458
459  // directional contribution (white light)
460  float i=-n.dot(g1_lights.direction) * static_intensity * (1.0/255.0);
461  if (i<0) i=0;
462  i+=g1_lights.ambient_intensity;
463  if (i>1) i=1;
464
465  return i;
466}
467
468void g1_map_vertex_class::recalc_light_sum(int cvx, int cvy)
469{
470  pf_recalc_light_sum.start();
471
472  float r,g,b;
473  i4_3d_vector n;
474
475  get_normal(n, cvx, cvy);
476
477  // directional contribution (white light)
478  float i=-n.dot(g1_lights.direction) * static_intensity * (1.0/255.0);
479  i = (i<0) ? 0 : i;
480
481  if (i>1)
482    i4_warning("intensity>1");
483
484  // global contribution (white light)
485  i+=g1_lights.ambient_intensity;
486  i = (i>1)? 1 : i;
487  i*=g1_lights.shadow_intensity[shadow_subtract];
488     
489  // dynamic light contribution
490  r=g1_table_0_255_to_0_1[((dynamic_light>>16)&0xff)] + i;
491  g=g1_table_0_255_to_0_1[((dynamic_light>>8)&0xff)] + i;
492  b=g1_table_0_255_to_0_1[((dynamic_light)&0xff)] + i;
493
494  if (r>1) r=1;
495  if (g>1) g=1;
496  if (b>1) b=1;
497
498  light_sum=(i4_f_to_i(r*255.0) << 16) |
499    (i4_f_to_i(g*255.0) << 8) |
500    (i4_f_to_i(b*255.0));
501
502  pf_recalc_light_sum.stop();
503}
504
505
506void g1_save_map_verts(g1_map_vertex_class *list,
507                       int lsize,
508                       i4_saver_class *fp,
509                       int mark_sections)
510
511{
512  int i;
513  i4_rle_class<w32> fp32(fp);
514  i4_rle_class<w16> fp16(fp);
515  i4_rle_class<w8> fp8(fp);
516
517
518  if (mark_sections)
519    fp->mark_section("golgotha vert height");
520  for (i=0; i<lsize; i++)
521    fp8.write(list[i].height);
522  fp8.flush();
523
524  if (mark_sections)
525    fp->mark_section("golgotha vert light sum v2");
526  for (i=0; i<lsize; i++)
527    fp32.write(list[i].light_sum);
528  fp32.flush();
529
530  if (mark_sections)
531    fp->mark_section("golgotha vert normal");
532  for (i=0; i<lsize; i++)
533    fp16.write(list[i].normal);
534  fp16.flush();
535
536  if (mark_sections)
537    fp->mark_section("golgotha vert static_intensity");
538  for (i=0; i<lsize; i++)
539    fp8.write(list[i].static_intensity);
540  fp8.flush();
541
542  if (mark_sections)
543    fp->mark_section("golgotha vert flags v2");
544  for (i=0; i<lsize; i++)
545    fp8.write(list[i].flags & g1_map_vertex_class::SAVED_FLAGS);
546  fp8.flush();
547 
548
549
550}
551
552
553i4_bool g1_load_map_verts(g1_map_vertex_class *list, int lsize,
554                          i4_loader_class *fp,
555                          int goto_sections)
556{
557  w16 *index=0;
558  int i, load_old=0;
559
560  i4_rle_class<w32> fp32(fp);
561  i4_rle_class<w16> fp16(fp);
562  i4_rle_class<w8> fp8(fp);
563
564  // initialize stuff we aren't loading
565  for (i=0; i<lsize; i++)
566  {
567    list[i].clip_code=0;
568    list[i].dynamic_light=0;       // this should be added in by lights in the level
569    list[i].shadow_subtract=0;
570  }
571
572  if (!goto_sections || fp->goto_section("golgotha vert height"))
573  {
574    for (i=0; i<lsize; i++)
575      list[i].height=fp8.read();
576  }
577  else load_old=1;
578
579  if (!goto_sections || fp->goto_section("golgotha vert light sum v2"))
580  {
581    for (i=0; i<lsize; i++)
582      list[i].light_sum=fp32.read();
583  }
584  else if (fp->goto_section("golgotha vert light sum"))
585  {
586    for (i=0; i<lsize; i++)
587      list[i].light_sum=0x80000000;
588  }
589
590
591  if (!goto_sections || fp->goto_section("golgotha vert normal"))
592  {
593    for (i=0; i<lsize; i++)
594      list[i].normal=fp16.read();
595  }
596
597
598  if (!goto_sections || fp->goto_section("golgotha vert static_intensity"))
599  {
600    for (i=0; i<lsize; i++)
601      list[i].static_intensity=fp8.read();
602  }
603
604
605  if (!goto_sections || fp->goto_section("golgotha vert flags v2"))
606  {
607    for (i=0; i<lsize; i++)
608      list[i].flags=fp8.read() & g1_map_vertex_class::SAVED_FLAGS;
609  }
610  else
611    for (i=0; i<lsize; i++)
612      list[i].flags=g1_map_vertex_class::FOGGED;
613
614   
615  g1_get_map()->mark_for_recalc(G1_RECALC_WATER_VERTS);
616
617
618
619  if (load_old)
620  {
621    int k=lsize;
622    if (fp->goto_section(OLD_G1_SECTION_MAP_VERT_V4))
623    {
624      if (fp->read_8())
625      {
626        w16 index;
627        do
628        {
629          index=fp->read_16();
630          if (index!=0xffff)
631            list[index].load_v4(fp);
632        } while (index!=0xffff);
633      }
634      else for (i=0; i<k; i++)
635        list[i].load_v4(fp);
636    }   
637    else if (fp->goto_section(OLD_G1_SECTION_MAP_VERT_V3))
638    {
639      for (i=0; i<k; i++)
640        list[i].load_v4(fp);
641    }
642    else if (fp->goto_section(OLD_G1_SECTION_MAP_VERT_V2))
643    {
644      for (i=0; i<k; i++)
645        list[i].load_v2(fp);
646    }
647    else if (fp->goto_section(OLD_G1_SECTION_MAP_VERT_V1))
648    {
649      for (i=0; i<k; i++)
650        list[i].load_v1(fp);
651    }
652    else return i4_F;
653  }
654   
655
656  return i4_T;
657
658}
659
660
661
662
663
664////////////////// OLD LOAD METHODS ////////////////////////////////////
665
666void g1_map_vertex_class::load_v1(i4_file_class *fp)
667{
668  dynamic_light=0;
669  light_sum=0x80000000;
670  normal=0x8000;
671  shadow_subtract=0;
672
673  static_intensity=(w8)(g1_lights.directional_intensity * (1.0/255.0));
674
675  fp->read_16();           // light value gone
676  height=fp->read_8();
677  set_is_selected(0);
678  clip_code=0;
679  flags=0;
680}
681
682void g1_map_vertex_class::load_v2(i4_file_class *fp)
683{
684  dynamic_light=0;
685  light_sum=0x80000000;
686  shadow_subtract=0;
687  normal=0x8000;
688  static_intensity=(w8)(g1_lights.directional_intensity * (1.0/255.0));
689
690  fp->read_16();           // light value gone
691  height=fp->read_8();
692
693  fp->read_16();
694  normal &= ~0x8000;
695  flags = 0;
696  clip_code=0;
697}
698
699void g1_map_vertex_class::load_v4(i4_file_class *fp)
700{
701  dynamic_light=0;
702  light_sum=0x80000000;
703  shadow_subtract=0;
704  static_intensity=(w8)(g1_lights.directional_intensity * (1.0/255.0));
705
706
707  fp->read_16();           // light value gone
708  height=fp->read_8();
709  fp->read_16();
710  normal=0x8000;
711
712  flags=0;
713  set_is_selected(fp->read_8()); 
714  clip_code = 0;
715}
Note: See TracBrowser for help on using the repository browser.