FS2_Open
Open source remastering of the Freespace 2 engine
shield.cpp
Go to the documentation of this file.
1 /*
2  * Copyright (C) Volition, Inc. 1999. All rights reserved.
3  *
4  * All source code herein is the property of Volition, Inc. You may not sell
5  * or otherwise commercially exploit the source or things you created based on the
6  * source.
7  *
8 */
9 
10 
11 // Detail level effects (Detail.shield_effects)
12 // 0 Nothing rendered
13 // 1 An animating bitmap rendered per hit, not shrink-wrapped. Lasts half time. One per ship.
14 // 2 Animating bitmap per hit, not shrink-wrapped. Lasts full time. Unlimited.
15 // 3 Shrink-wrapped texture. Lasts half-time.
16 // 4 Shrink-wrapped texture. Lasts full-time.
17 
18 #include "freespace2/freespace.h"
19 #include "mission/missionparse.h"
20 #include "model/model.h"
21 #include "network/multi.h"
22 #include "object/objectshield.h"
23 #include "render/3d.h"
24 #include "ship/ship.h"
26 
28 
29 // One unit in 3d means this in the shield hit texture map.
30 #define SHIELD_HIT_SCALE 0.15f // Note, larger constant means smaller effect
31 #define MAX_TRIS_PER_HIT 40 // Number of triangles per shield hit, maximum.
32 #define MAX_SHIELD_HITS 20 // Maximum number of active shield hits.
33 #define MAX_SHIELD_TRI_BUFFER (MAX_SHIELD_HITS*MAX_TRIS_PER_HIT) //(MAX_SHIELD_HITS*20) // Persistent buffer of triangle comprising all active shield hits.
34 #define SHIELD_HIT_DURATION (3*F1_0/4) // Duration, in milliseconds, of shield hit effect
35 
36 #define SH_UNUSED -1 // Indicates an unused record in Shield_hits
37 #define SH_TYPE_1 1 // Indicates Shield_hits record is of type 1.
38 
39 #define UV_MAX (63.95f/64.0f) // max allowed value until tmapper bugs fixed, 1/24/97
40 
42 
49 typedef struct gshield_tri {
50  int used; // Set if this triangle is currently in use.
51  int trinum; // a debug parameter
52  fix creation_time; // time at which created.
53  shield_vertex verts[4]; // Triangles, but at lower detail level, a square.
54 } gshield_tri;
55 
56 typedef struct shield_hit {
57  int start_time; // start time of this object
58  int type; // type, probably the weapon type, to indicate the bitmap to use
59  int objnum; // Object index, needed to get current orientation, position.
60  int num_tris; // Number of Shield_tris comprising this shield.
61  int tri_list[MAX_TRIS_PER_HIT]; // Indices into Shield_tris, triangles for this shield hit.
62  ubyte rgb[3]; // rgb colors
63 } shield_hit;
64 
69 typedef struct shield_point {
70  int objnum; // Object that was hit.
71  int shield_tri; // Triangle in shield mesh that took hit.
72  vec3d hit_point; // Point in global 3-space of hit.
73 } shield_point;
74 
75 #define MAX_SHIELD_POINTS 100
78 int Num_multi_shield_points; // used by multiplayer clients
79 
80 gshield_tri Global_tris[MAX_SHIELD_TRI_BUFFER]; // The persistent triangles, part of shield hits.
81 int Num_tris; // Number of triangles in current shield. Would be a local, but needed in numerous routines.
82 
84 
86 
87 // This is a recursive function, so prototype it.
88 extern void create_shield_from_triangle(int trinum, matrix *orient, shield_info *shieldp, vec3d *tcp, vec3d *centerp, float radius, vec3d *rvec, vec3d *uvec);
89 
91 {
92  size_t i;
93  // Check if we've already allocated the shield effect bitmaps
95  return;
96 
98 
99  for (i = 0; i < Species_info.size(); i++ )
100  {
101  if (Species_info[i].shield_anim.filename[0] != '\0')
102  {
103  Species_info[i].shield_anim.first_frame = bm_load_animation(Species_info[i].shield_anim.filename, &Species_info[i].shield_anim.num_frames, NULL, NULL, 1);
104  Assertion((Species_info[i].shield_anim.first_frame >= 0), "Error while loading shield hit ani: %s for species: %s\n", Species_info[i].shield_anim.filename, Species_info[i].species_name);
105  }
106  }
107 }
108 
110 {
111  size_t i;
112 
113  if ( !Shield_bitmaps_loaded ) {
115  }
116 
117  for (i = 0; i < Species_info.size(); i++) {
118  generic_anim *sa = &Species_info[i].shield_anim;
119  if ( sa->first_frame >= 0 ) {
121  }
122  }
123 }
124 
125 
132 {
133  int i;
134 
135  for (i=0; i<MAX_SHIELD_HITS; i++) {
136  Shield_hits[i].type = SH_UNUSED;
137  Shield_hits[i].objnum = -1;
138  }
139 
140  for (i=0; i<MAX_SHIELD_TRI_BUFFER; i++) {
141  Global_tris[i].used = 0;
142  Global_tris[i].creation_time = Missiontime;
143  }
144 
146 
148 }
149 
156 {
157  if ( !Shield_bitmaps_loaded )
158  return;
159 }
160 
161 int Poly_count = 0;
162 
169 {
171 }
172 
174 {
175  Poly_count = 0;
176  Num_shield_points = 0;
177 }
178 
179 void create_low_detail_poly(int global_index, vec3d *tcp, vec3d *rightv, vec3d *upv)
180 {
181  float scale;
182  gshield_tri *trip;
183 
184  trip = &Global_tris[global_index];
185 
186  scale = vm_vec_mag(tcp) * 2.0f;
187 
188  vm_vec_scale_add(&trip->verts[0].pos, tcp, rightv, -scale/2.0f);
189  vm_vec_scale_add2(&trip->verts[0].pos, upv, scale/2.0f);
190 
191  vm_vec_scale_add(&trip->verts[1].pos, &trip->verts[0].pos, rightv, scale);
192 
193  vm_vec_scale_add(&trip->verts[2].pos, &trip->verts[1].pos, upv, -scale);
194 
195  vm_vec_scale_add(&trip->verts[3].pos, &trip->verts[2].pos, rightv, -scale);
196 
197  // Set u, v coordinates.
198  // Note, this need only be done once, as it's common for all explosions.
199  trip->verts[0].u = 0.0f;
200  trip->verts[0].v = 0.0f;
201 
202  trip->verts[1].u = 1.0f;
203  trip->verts[1].v = 0.0f;
204 
205  trip->verts[2].u = 1.0f;
206  trip->verts[2].v = 1.0f;
207 
208  trip->verts[3].u = 0.0f;
209  trip->verts[3].v = 1.0f;
210 
211 }
212 
221 void rs_compute_uvs(shield_tri *stp, shield_vertex *verts, vec3d *tcp, float radius, vec3d *rightv, vec3d *upv)
222 {
223  int i;
224  shield_vertex *sv;
225 
226  for (i=0; i<3; i++) {
227  vec3d v2cp;
228 
229  sv = &verts[stp->verts[i]];
230 
231  vm_vec_sub(&v2cp, &sv->pos, tcp);
232  sv->u = vm_vec_dot(&v2cp, rightv) * Shield_scale + 0.5f;
233  sv->v = - vm_vec_dot(&v2cp, upv) * Shield_scale + 0.5f;
234 
235  CLAMP(sv->u, 0.0f, UV_MAX);
236  CLAMP(sv->v, 0.0f, UV_MAX);
237  }
238 }
239 
243 void free_global_tri_records(int shnum)
244 {
245  int i;
246 
247  Assert((shnum >= 0) && (shnum < MAX_SHIELD_HITS));
248 
249  for (i=0; i<Shield_hits[shnum].num_tris; i++){
250  Global_tris[Shield_hits[shnum].tri_list[i]].used = 0;
251  }
252 }
253 
254 extern int Cmdline_nohtl;
255 
257 {
258  int j;
259  vec3d pnt;
260  vertex verts[4];
261 
262  memset(verts, 0, sizeof(verts));
263 
264  for (j=0; j<4; j++ ) {
265  // Rotate point into world coordinates
266  vm_vec_unrotate(&pnt, &trip->verts[j].pos, orient);
267  vm_vec_add2(&pnt, pos);
268 
269  // Pnt is now the x,y,z world coordinates of this vert.
270  if(!Cmdline_nohtl) g3_transfer_vertex(&verts[j], &pnt);
271  else g3_rotate_vertex(&verts[j], &pnt);
272  verts[j].texture_position.u = trip->verts[j].u;
273  verts[j].texture_position.v = trip->verts[j].v;
274  }
275 
276  verts[0].r = r;
277  verts[0].g = g;
278  verts[0].b = b;
279  verts[1].r = r;
280  verts[1].g = g;
281  verts[1].b = b;
282  verts[2].r = r;
283  verts[2].g = g;
284  verts[2].b = b;
285  verts[3].r = r;
286  verts[3].g = g;
287  verts[3].b = b;
288 
289  vec3d norm;
290  vm_vec_perp(&norm, &trip->verts[0].pos, &trip->verts[1].pos, &trip->verts[2].pos);
291  vertex *vertlist[4];
292  if ( vm_vec_dot(&norm, &trip->verts[1].pos ) < 0.0 ) {
293  vertlist[0] = &verts[3];
294  vertlist[1] = &verts[2];
295  vertlist[2] = &verts[1];
296  vertlist[3] = &verts[0];
298  } else {
299  vertlist[0] = &verts[0];
300  vertlist[1] = &verts[1];
301  vertlist[2] = &verts[2];
302  vertlist[3] = &verts[3];
304  }
305 }
306 
319 {
320  int j;
321  vec3d pnt;
322  vertex *verts[3];
323  vertex points[3];
324 
325  memset(&verts, 0, sizeof(verts));
326 
327  if (trip->trinum == -1)
328  return; // Means this is a quad, must have switched detail_level.
329 
330  for (j=0; j<3; j++ ) {
331  // Rotate point into world coordinates
332  vm_vec_unrotate(&pnt, &trip->verts[j].pos, orient);
333  vm_vec_add2(&pnt, pos);
334 
335  // Pnt is now the x,y,z world coordinates of this vert.
336  // For this example, I am just drawing a sphere at that point.
337 
338  if (!Cmdline_nohtl) g3_transfer_vertex(&points[j],&pnt);
339  else g3_rotate_vertex(&points[j], &pnt);
340 
341  points[j].texture_position.u = trip->verts[j].u;
342  points[j].texture_position.v = trip->verts[j].v;
343  Assert((trip->verts[j].u >= 0.0f) && (trip->verts[j].u <= UV_MAX));
344  Assert((trip->verts[j].v >= 0.0f) && (trip->verts[j].v <= UV_MAX));
345  verts[j] = &points[j];
346  }
347 
348  verts[0]->r = r;
349  verts[0]->g = g;
350  verts[0]->b = b;
351  verts[1]->r = r;
352  verts[1]->g = g;
353  verts[1]->b = b;
354  verts[2]->r = r;
355  verts[2]->g = g;
356  verts[2]->b = b;
357 
358  vec3d norm;
359  Poly_count++;
360  vm_vec_perp(&norm,&verts[0]->world,&verts[1]->world,&verts[2]->world);
361 
363  if (!Cmdline_nohtl) flags |= TMAP_HTL_3D_UNLIT;
364 
365  if ( vm_vec_dot(&norm,&verts[1]->world ) >= 0.0 ) {
366  vertex *vertlist[3];
367  vertlist[0] = verts[2];
368  vertlist[1] = verts[1];
369  vertlist[2] = verts[0];
370  g3_draw_poly( 3, vertlist, flags);
371  } else {
372  g3_draw_poly( 3, verts, flags);
373  }
374 }
375 
376 MONITOR(NumShieldRend)
377 
378 
381 void render_shield(int shield_num)
382 {
383  int i;
384  vec3d *centerp;
385  matrix *orient;
386  object *objp;
387  ship *shipp;
388  ship_info *si;
389 
390  if (Shield_hits[shield_num].type == SH_UNUSED) {
391  return;
392  }
393 
394  Assert(Shield_hits[shield_num].objnum >= 0);
395 
396  objp = &Objects[Shield_hits[shield_num].objnum];
397 
398  if (objp->flags & OF_NO_SHIELDS) {
399  return;
400  }
401 
402  // If this object didn't get rendered, don't render its shields. In fact, make the shield hit go away.
403  if (!(objp->flags & OF_WAS_RENDERED)) {
404  Shield_hits[shield_num].type = SH_UNUSED;
405  return;
406  }
407 
408  // At detail levels 1, 3, animations play at double speed to reduce load.
409  if ( (Detail.shield_effects == 1) || (Detail.shield_effects == 3) ) {
410  Shield_hits[shield_num].start_time -= Frametime;
411  }
412 
413  MONITOR_INC(NumShieldRend,1);
414 
415  shipp = &Ships[objp->instance];
416  si = &Ship_info[shipp->ship_info_index];
417  // objp, shipp, and si are now setup correctly
418 
419  // If this ship is in its deathroll, make the shield hit effects go away faster.
420  if (shipp->flags & SF_DYING) {
421  Shield_hits[shield_num].start_time -= fl2f(2*flFrametime);
422  }
423 
424  // Detail level stuff. When lots of shield hits, maybe make them go away faster.
425  if (Poly_count > 50) {
426  if (Shield_hits[shield_num].start_time + (SHIELD_HIT_DURATION*50)/Poly_count < Missiontime) {
427  Shield_hits[shield_num].type = SH_UNUSED;
428  free_global_tri_records(shield_num);
429  return;
430  }
431  } else if ((Shield_hits[shield_num].start_time + SHIELD_HIT_DURATION) < Missiontime) {
432  Shield_hits[shield_num].type = SH_UNUSED;
433  free_global_tri_records(shield_num);
434  return;
435  }
436 
437  orient = &objp->orient;
438  centerp = &objp->pos;
439 
440  int bitmap_id, frame_num;
441 
442  // Do some sanity checking
443  Assert( (si->species >= 0) && (si->species < (int)Species_info.size()) );
444 
445  generic_anim *sa = &Species_info[si->species].shield_anim;
446 
447  // don't try to draw if we don't have an ani
448  if ( sa->first_frame >= 0 )
449  {
450  frame_num = fl2i( f2fl(Missiontime - Shield_hits[shield_num].start_time) / f2fl(SHIELD_HIT_DURATION) * sa->num_frames );
451  if ( frame_num >= sa->num_frames ) {
452  frame_num = sa->num_frames - 1;
453  } else if ( frame_num < 0 ) {
454  mprintf(( "HEY! Missiontime went backwards! (Shield.cpp)\n" ));
455  frame_num = 0;
456  }
457  bitmap_id = sa->first_frame + frame_num;
458 
459  float alpha = 0.9999f;
461  alpha *= 0.85f;
462  }
463 
465 
466  if ( (Detail.shield_effects == 1) || (Detail.shield_effects == 2) ) {
467  if ( bitmap_id != - 1 ) {
468  render_low_detail_shield_bitmap(&Global_tris[Shield_hits[shield_num].tri_list[0]], orient, centerp, Shield_hits[shield_num].rgb[0], Shield_hits[shield_num].rgb[1], Shield_hits[shield_num].rgb[2]);
469  }
470  } else {
471  if ( bitmap_id != - 1 ) {
472  for (i=0; i<Shield_hits[shield_num].num_tris; i++) {
473  render_shield_triangle(&Global_tris[Shield_hits[shield_num].tri_list[i]], orient, centerp, Shield_hits[shield_num].rgb[0], Shield_hits[shield_num].rgb[1], Shield_hits[shield_num].rgb[2]);
474  }
475  }
476  }
477  }
478 }
479 
487 {
488  int i;
489 
490  if (Detail.shield_effects == 0){
491  return; // No shield effect rendered at lowest detail level.
492  }
493 
494  for (i=0; i<MAX_SHIELD_HITS; i++){
495  if (Shield_hits[i].type != SH_UNUSED){
496  render_shield(i);
497  }
498  }
499 }
500 
501 void create_tris_containing(vec3d *vp, matrix *orient, shield_info *shieldp, vec3d *tcp, vec3d *centerp, float radius, vec3d *rvec, vec3d *uvec)
502 {
503  int i, j;
504  shield_vertex *verts;
505 
506  verts = shieldp->verts;
507 
508  for (i=0; i<Num_tris; i++) {
509  if ( !shieldp->tris[i].used ) {
510  for (j=0; j<3; j++) {
511  vec3d v;
512 
513  v = verts[shieldp->tris[i].verts[j]].pos;
514  if ((vp->xyz.x == v.xyz.x) && (vp->xyz.y == v.xyz.y) && (vp->xyz.z == v.xyz.z))
515  create_shield_from_triangle(i, orient, shieldp, tcp, centerp, radius, rvec, uvec);
516  }
517  }
518  }
519 }
520 
521 void visit_children(int trinum, int vertex_index, matrix *orient, shield_info *shieldp, vec3d *tcp, vec3d *centerp, float radius, vec3d *rvec, vec3d *uvec)
522 {
523  shield_vertex *sv;
524 
525  sv = &(shieldp->verts[shieldp->tris[trinum].verts[vertex_index]]);
526 
527  if ( (sv->u > 0.0f) && (sv->u < UV_MAX) && (sv->v > 0.0f) && (sv->v < UV_MAX))
528  create_tris_containing(&sv->pos, orient, shieldp, tcp, centerp, radius, rvec, uvec);
529 }
530 
531 int Gi_max = 0;
532 
534 {
535  int gi = 0;
536 
537  while ((gi < MAX_SHIELD_TRI_BUFFER) && (Global_tris[gi].used) && (Global_tris[gi].creation_time + SHIELD_HIT_DURATION > Missiontime)) {
538  gi++;
539  }
540 
541  // If couldn't find one, choose a random one.
542  if (gi == MAX_SHIELD_TRI_BUFFER)
543  gi = (int) (frand() * MAX_SHIELD_TRI_BUFFER);
544 
545  return gi;
546 }
547 
549 {
550  int shnum;
551 
552  // Find unused shield hit buffer
553  for (shnum=0; shnum<MAX_SHIELD_HITS; shnum++)
554  if (Shield_hits[shnum].type == SH_UNUSED)
555  break;
556 
557  if (shnum == MAX_SHIELD_HITS) {
558  shnum = myrand() % MAX_SHIELD_HITS;
559  }
560 
561  Assert((shnum >= 0) && (shnum < MAX_SHIELD_HITS));
562 
563  return shnum;
564 }
565 
566 void create_shield_from_triangle(int trinum, matrix *orient, shield_info *shieldp, vec3d *tcp, vec3d *centerp, float radius, vec3d *rvec, vec3d *uvec)
567 {
568  rs_compute_uvs( &shieldp->tris[trinum], shieldp->verts, tcp, radius, rvec, uvec);
569 
570  shieldp->tris[trinum].used = 1;
571 
572  visit_children(trinum, 0, orient, shieldp, tcp, centerp, radius, rvec, uvec);
573  visit_children(trinum, 1, orient, shieldp, tcp, centerp, radius, rvec, uvec);
574  visit_children(trinum, 2, orient, shieldp, tcp, centerp, radius, rvec, uvec);
575 }
576 
585 void copy_shield_to_globals( int objnum, shield_info *shieldp )
586 {
587  int i, j;
588  int gi = 0;
589  int count = 0; // Number of triangles in this shield hit.
590  int shnum; // shield hit number, index in Shield_hits.
591 
592  shnum = get_global_shield_tri();
593 
594  Shield_hits[shnum].type = SH_TYPE_1;
595 
596  for (i = 0; i < shieldp->ntris; i++ ) {
597  if ( shieldp->tris[i].used ) {
598  while ( (gi < MAX_SHIELD_TRI_BUFFER) && (Global_tris[gi].used) && (Global_tris[gi].creation_time + SHIELD_HIT_DURATION > Missiontime)) {
599  gi++;
600  }
601 
602  // If couldn't find one, choose a random one.
603  if (gi == MAX_SHIELD_TRI_BUFFER)
604  gi = (int) (frand() * MAX_SHIELD_TRI_BUFFER);
605 
606  Global_tris[gi].used = shieldp->tris[i].used;
607  Global_tris[gi].trinum = i;
608  Global_tris[gi].creation_time = Missiontime;
609 
610  // copy the pos/u/v elements of the shield_vertex structure into the shield vertex structure for this global triangle.
611  for (j = 0; j < 3; j++)
612  Global_tris[gi].verts[j] = shieldp->verts[shieldp->tris[i].verts[j]];
613  Shield_hits[shnum].tri_list[count++] = gi;
614 
615  if (count >= MAX_TRIS_PER_HIT) {
616  mprintf(("Warning: Too many triangles in shield hit.\n"));
617  break;
618  }
619  }
620  }
621 
622  Shield_hits[shnum].num_tris = count;
623  Shield_hits[shnum].start_time = Missiontime;
624  Shield_hits[shnum].objnum = objnum;
625 
626  Shield_hits[shnum].rgb[0] = 255;
627  Shield_hits[shnum].rgb[1] = 255;
628  Shield_hits[shnum].rgb[2] = 255;
629  if((objnum >= 0) && (objnum < MAX_OBJECTS) && (Objects[objnum].type == OBJ_SHIP) && (Objects[objnum].instance >= 0) && (Objects[objnum].instance < MAX_SHIPS) && (Ships[Objects[objnum].instance].ship_info_index >= 0) && (Ships[Objects[objnum].instance].ship_info_index < static_cast<int>(Ship_info.size()))){
631 
632  Shield_hits[shnum].rgb[0] = sip->shield_color[0];
633  Shield_hits[shnum].rgb[1] = sip->shield_color[1];
634  Shield_hits[shnum].rgb[2] = sip->shield_color[2];
635  }
636 }
637 
638 
644 float apply_damage_to_shield(object *objp, int quadrant, float damage)
645 {
646  ai_info *aip;
647 
648  // multiplayer clients bail here
649  if(MULTIPLAYER_CLIENT){
650  return damage;
651  }
652 
653  if ( (quadrant < 0) || (quadrant >= objp->n_quadrants) ) return damage;
654 
655  Assert(objp->type == OBJ_SHIP);
656  aip = &Ai_info[Ships[objp->instance].ai_index];
657  aip->last_hit_quadrant = quadrant;
658 
659  objp->shield_quadrant[quadrant] -= damage;
660 
661  if (objp->shield_quadrant[quadrant] < 0.0f) {
662  float remaining_damage;
663 
664  remaining_damage = -objp->shield_quadrant[quadrant];
665  objp->shield_quadrant[quadrant] = 0.0f;
666  return remaining_damage;
667  } else {
668  return 0.0f;
669  }
670 
671 }
672 
679 void create_shield_low_detail(int objnum, int model_num, matrix *orient, vec3d *centerp, vec3d *tcp, int tr0, shield_info *shieldp)
680 {
681  matrix tom;
682  int gi;
683  int shnum;
684 
685  shnum = get_global_shield_tri();
686  Shield_hits[shnum].type = SH_TYPE_1;
687 
689 
690  Global_tris[gi].used = 1;
691  Global_tris[gi].trinum = -1; // This tells triangle renderer to not render in case detail_level was switched.
692  Global_tris[gi].creation_time = Missiontime;
693 
694  Shield_hits[shnum].tri_list[0] = gi;
695  Shield_hits[shnum].num_tris = 1;
696  Shield_hits[shnum].start_time = Missiontime;
697  Shield_hits[shnum].objnum = objnum;
698 
699  Shield_hits[shnum].rgb[0] = 255;
700  Shield_hits[shnum].rgb[1] = 255;
701  Shield_hits[shnum].rgb[2] = 255;
702  if((objnum >= 0) && (objnum < MAX_OBJECTS) && (Objects[objnum].type == OBJ_SHIP) && (Objects[objnum].instance >= 0) && (Objects[objnum].instance < MAX_SHIPS) && (Ships[Objects[objnum].instance].ship_info_index >= 0) && (Ships[Objects[objnum].instance].ship_info_index < static_cast<int>(Ship_info.size()))){
704 
705  Shield_hits[shnum].rgb[0] = sip->shield_color[0];
706  Shield_hits[shnum].rgb[1] = sip->shield_color[1];
707  Shield_hits[shnum].rgb[2] = sip->shield_color[2];
708  }
709 
710  vm_vector_2_matrix(&tom, &shieldp->tris[tr0].norm, NULL, NULL);
711 
712  create_low_detail_poly(gi, tcp, &tom.vec.rvec, &tom.vec.uvec);
713 }
714 
715 // Algorithm for shrink-wrapping a texture across a triangular mesh.
716 //
717 // - Given a point of intersection, tcp (local to objnum)
718 // - Vector to center of shield from tcp is v2c.
719 // - Using v2c, compute right and down vectors. These are the vectors of
720 // increasing u and v, respectively.
721 // - Triangle of intersection of tcp is tr0.
722 // - For 3 points in tr0, compute u,v coordinates using up and down vectors
723 // from center point, tcp. Need to know size of explosion texture. N units
724 // along right vector corresponds to O units in explosion texture space.
725 // - For each edge, if either endpoint was outside texture bounds, recursively
726 // apply previous and current step.
727 //
728 // Output of above is a list of triangles with u,v coordinates. These u,v
729 // coordinates will have to be clipped against the explosion texture bounds.
730 
731 void create_shield_explosion(int objnum, int model_num, matrix *orient, vec3d *centerp, vec3d *tcp, int tr0)
732 {
733  matrix tom; // Texture Orientation Matrix
734  shield_info *shieldp;
735  polymodel *pm;
736  int i;
737 
738  if (Objects[objnum].flags & OF_NO_SHIELDS)
739  return;
740 
741  pm = model_get(model_num);
742  Num_tris = pm->shield.ntris;
743  shieldp = &pm->shield;
744 
745  if (Num_tris == 0)
746  return;
747 
748  if ( (Detail.shield_effects == 1) || (Detail.shield_effects == 2) ) {
749  create_shield_low_detail(objnum, model_num, orient, centerp, tcp, tr0, shieldp);
750  return;
751  }
752 
753  for (i=0; i<Num_tris; i++)
754  shieldp->tris[i].used = 0;
755 
756  // Compute orientation matrix from normal of surface hit.
757  // Note, this will cause the shape of the bitmap to change abruptly
758  // as the impact point moves to another triangle. To prevent this,
759  // you could average the normals at the vertices, then interpolate the
760  // normals from the vertices to get a smoothly changing normal across the face.
761  // I had tried using the vector from the impact point to the center, which
762  // changes smoothly, but this looked surprisingly bad.
763  vm_vector_2_matrix(&tom, &shieldp->tris[tr0].norm, NULL, NULL);
764 
765  // Create the shield from the current triangle, as well as its neighbors.
766  create_shield_from_triangle(tr0, orient, shieldp, tcp, centerp, Objects[objnum].radius, &tom.vec.rvec, &tom.vec.uvec);
767 
768  for (i=0; i<3; i++)
769  create_shield_from_triangle(shieldp->tris[tr0].neighbors[i], orient, shieldp, tcp, centerp, Objects[objnum].radius, &tom.vec.rvec, &tom.vec.uvec);
770 
771  copy_shield_to_globals(objnum, shieldp);
772 }
773 
774 MONITOR(NumShieldHits)
775 
776 
779 void add_shield_point(int objnum, int tri_num, vec3d *hit_pos)
780 {
782  return;
783 
784  Verify(objnum < MAX_OBJECTS);
785 
786  MONITOR_INC(NumShieldHits,1);
787 
788  Shield_points[Num_shield_points].objnum = objnum;
789  Shield_points[Num_shield_points].shield_tri = tri_num;
790  Shield_points[Num_shield_points].hit_point = *hit_pos;
791 
793 
794  Ships[Objects[objnum].instance].shield_hits++;
795 }
796 
797 // ugh! I wrote a special routine to store shield points for clients in multiplayer
798 // games. Problem is initilization and flow control of normal gameplay make this problem
799 // more than trivial to solve. Turns out that I think I can just keep track of the
800 // shield_points for multiplayer in a separate count -- then assign the multi count to
801 // the normal count at the correct time.
802 void add_shield_point_multi(int objnum, int tri_num, vec3d *hit_pos)
803 {
805  return;
806 
807  Shield_points[Num_shield_points].objnum = objnum;
808  Shield_points[Num_shield_points].shield_tri = tri_num;
809  Shield_points[Num_shield_points].hit_point = *hit_pos;
810 
812 }
813 
818 {
819  int i;
820 
822 
823  if ( Num_multi_shield_points == 0 )
824  return;
825 
827  for (i = 0; i < Num_shield_points; i++ ){
828  Ships[Objects[Shield_points[i].objnum].instance].shield_hits++;
829  }
830 
832 }
833 
834 
839 {
840  int i;
841  int num;
842  int count;
843  int objnum;
844  ship *shipp;
845 
846  if (Detail.shield_effects == 0){
847  return;
848  }
849 
850  num = objp->instance;
851  shipp = &Ships[num];
852 
853  count = shipp->shield_hits;
854  objnum = objp-Objects;
855 
856  for (i=0; i<Num_shield_points; i++) {
857  if (Shield_points[i].objnum == objnum) {
858  create_shield_explosion(objnum, Ship_info[shipp->ship_info_index].model_num, &objp->orient, &objp->pos, &Shield_points[i].hit_point, Shield_points[i].shield_tri);
859  count--;
860  if (count <= 0){
861  break;
862  }
863  }
864  }
865 
866  // some some reason, clients seem to have a bogus count valud on occation. I"ll chalk it up
867  // to missed packets :-) MWA 2/6/98
868  if ( !MULTIPLAYER_CLIENT ) {
869  Assert(count == 0); // Couldn't find all the alleged shield hits. Bogus!
870  }
871 }
872 
873 int Break_value = -1;
874 
878 #ifndef NDEBUG
879 void ship_draw_shield( object *objp)
880 {
881  int model_num;
882  int i;
883  vec3d pnt;
884  polymodel * pm;
885 
886  if (objp->flags & OF_NO_SHIELDS)
887  return;
888 
889  Assert(objp->instance >= 0);
890 
891  model_num = Ship_info[Ships[objp->instance].ship_info_index].model_num;
892 
893  if ( Fred_running ) return;
894 
895  pm = model_get(model_num);
896 
897  if (pm->shield.ntris<1) return;
898 
899  // Scan all the triangles in the mesh.
900  for (i=0; i<pm->shield.ntris; i++ ) {
901  int j;
902  vec3d gnorm, v2f, tri_point;
903  vertex prev_pnt, pnt0;
904  shield_tri *tri;
905 
906  tri = &pm->shield.tris[i];
907 
908  if (i == Break_value)
909  Int3();
910 
911  // Hack! Only works for object in identity orientation.
912  // Need to rotate eye position into object's reference frame.
913  // Only draw facing triangles.
914  vm_vec_rotate(&tri_point, &pm->shield.verts[tri->verts[0]].pos, &Eye_matrix);
915  vm_vec_add2(&tri_point, &objp->pos);
916 
917  vm_vec_sub(&v2f, &tri_point, &Eye_position);
918  vm_vec_unrotate(&gnorm, &tri->norm, &objp->orient);
919 
920  if (vm_vec_dot(&gnorm, &v2f) < 0.0f) {
921  int intensity;
922 
923  intensity = (int) (Ships[objp->instance].shield_integrity[i] * 255);
924 
925  if (intensity < 0)
926  intensity = 0;
927  else if (intensity > 255)
928  intensity = 255;
929 
930  gr_set_color(0, 0, intensity);
931 
932  // Process the vertices.
933  // Note this rotates each vertex each time it's needed, very dumb.
934  for (j=0; j<3; j++ ) {
935  vertex tmp;
936 
937  // Rotate point into world coordinates
938  vm_vec_unrotate(&pnt, &pm->shield.verts[tri->verts[j]].pos, &objp->orient);
939  vm_vec_add2(&pnt, &objp->pos);
940 
941  // Pnt is now the x,y,z world coordinates of this vert.
942  // For this example, I am just drawing a sphere at that
943  // point.
944  g3_rotate_vertex(&tmp, &pnt);
945 
946  if (j)
947  g3_draw_line(&prev_pnt, &tmp);
948  else
949  pnt0 = tmp;
950  prev_pnt = tmp;
951  }
952 
953  g3_draw_line(&pnt0, &prev_pnt);
954  }
955  }
956 }
957 #endif
958 
964 int ship_is_shield_up( object *obj, int quadrant )
965 {
966  if ( (quadrant >= 0) && (quadrant < obj->n_quadrants)) {
967  // Just check one quadrant
968  if (obj->shield_quadrant[quadrant] > MAX(2.0f, 0.1f * get_max_shield_quad(obj))) {
969  return 1;
970  }
971  } else {
972  // Check all quadrants
973  float strength = shield_get_strength(obj);
974 
975  if ( strength > MAX(2.0f*4.0f, 0.1f * Ships[obj->instance].ship_max_shield_strength )) {
976  return 1;
977  }
978  }
979  return 0; // no shield strength
980 }
981 
982 // return quadrant containing hit_pnt.
983 // \ 1 /.
984 // 3 \ / 0
985 // / \.
986 // / 2 \.
987 // Note: This is in the object's local reference frame. Do _not_ pass a vector in the world frame.
988 int get_quadrant(vec3d *hit_pnt, object *shipobjp)
989 {
990  if (shipobjp != NULL && Ship_info[Ships[shipobjp->instance].ship_info_index].flags2 & SIF2_MODEL_POINT_SHIELDS) {
991  int closest = -1;
992  float closest_dist = FLT_MAX;
993 
994  for (unsigned int i=0; i<Ships[shipobjp->instance].shield_points.size(); i++) {
995  float dist = vm_vec_dist(hit_pnt, &Ships[shipobjp->instance].shield_points.at(i));
996 
997  if (dist < closest_dist) {
998  closest = i;
999  closest_dist = dist;
1000  }
1001  }
1002 
1003  return closest;
1004  } else {
1005  int result = 0;
1006 
1007  if (hit_pnt->xyz.x < hit_pnt->xyz.z)
1008  result |= 1;
1009 
1010  if (hit_pnt->xyz.x < -hit_pnt->xyz.z)
1011  result |= 2;
1012 
1013  return result;
1014  }
1015 }
#define SH_TYPE_1
Definition: shield.cpp:37
GLuint64EXT * result
Definition: Glext.h:10775
#define MULTIPLAYER_CLIENT
Definition: multi.h:132
fix Frametime
Definition: systemvars.cpp:21
int i
Definition: multi_pxo.cpp:466
float get_max_shield_quad(object *objp)
Definition: object.cpp:260
fix Missiontime
Definition: systemvars.cpp:19
void shield_hit_init()
Definition: shield.cpp:131
shield_hit Shield_hits[MAX_SHIELD_HITS]
Definition: shield.cpp:83
#define Verify(x)
Definition: pstypes.h:272
int Shield_bitmaps_loaded
Definition: shield.cpp:85
fix creation_time
Definition: shield.cpp:52
void create_shield_explosion(int objnum, int model_num, matrix *orient, vec3d *centerp, vec3d *tcp, int tr0)
Definition: shield.cpp:731
#define vp(p)
Definition: modelsinc.h:70
int Gi_max
Definition: shield.cpp:531
int Cmdline_nohtl
Definition: cmdline.cpp:438
shield_vertex verts[4]
Definition: shield.cpp:53
void vm_vec_scale_add(vec3d *dest, const vec3d *src1, const vec3d *src2, float k)
Definition: vecmat.cpp:266
#define MISSION_FLAG_FULLNEB
Definition: missionparse.h:70
int Num_tris
Definition: shield.cpp:81
polymodel * model_get(int model_num)
Definition: modelread.cpp:3134
int start_time
Definition: shield.cpp:57
float shield_get_strength(object *objp)
#define SH_UNUSED
Definition: shield.cpp:36
float v
Definition: pstypes.h:135
float vm_vec_mag(const vec3d *v)
Definition: vecmat.cpp:325
float v
Definition: model.h:561
float flFrametime
Definition: fredstubs.cpp:22
ubyte g
Definition: pstypes.h:175
int Fred_running
Definition: fred.cpp:44
int get_quadrant(vec3d *hit_pnt, object *shipobjp)
Definition: shield.cpp:988
#define MAX_SHIPS
Definition: globals.h:37
#define SHIELD_HIT_SCALE
Definition: shield.cpp:30
GLsizei const GLfloat * points
Definition: Glext.h:7583
int tri_list[MAX_TRIS_PER_HIT]
Definition: shield.cpp:61
float ship_max_shield_strength
Definition: ship.h:596
#define MAX_TRIS_PER_HIT
Definition: shield.cpp:31
ubyte g3_transfer_vertex(vertex *dest, const vec3d *src)
Definition: 3dmath.cpp:84
vec3d hit_point
Definition: shield.cpp:72
#define OF_WAS_RENDERED
Definition: object.h:113
Assert(pm!=NULL)
SCP_vector< vec3d > shield_points
Definition: ship.h:662
struct shield_point shield_point
Definition: pstypes.h:88
#define mprintf(args)
Definition: pstypes.h:238
int ai_index
Definition: ship.h:538
void create_shield_from_triangle(int trinum, matrix *orient, shield_info *shieldp, vec3d *tcp, vec3d *centerp, float radius, vec3d *rvec, vec3d *uvec)
Definition: shield.cpp:566
#define MAX_SHIELD_TRI_BUFFER
Definition: shield.cpp:33
matrix Eye_matrix
Definition: 3dsetup.cpp:26
int verts[3]
Definition: model.h:552
#define SHIELD_HIT_DURATION
Definition: shield.cpp:34
#define MAX_SHIELD_POINTS
Definition: shield.cpp:75
struct vec3d::@225::@227 xyz
#define TMAP_HTL_3D_UNLIT
Definition: tmapper.h:63
int shield_effects
Definition: systemvars.h:173
GLclampf f
Definition: Glext.h:7097
#define MAX_OBJECTS
Definition: globals.h:83
#define OF_NO_SHIELDS
Definition: object.h:110
ai_info Ai_info[MAX_AI_INFO]
Definition: ai.cpp:23
vec3d * vm_vec_rotate(vec3d *dest, const vec3d *src, const matrix *m)
Definition: vecmat.cpp:933
#define Assertion(expr, msg,...)
Definition: clang.h:41
int Num_multi_shield_points
Definition: shield.cpp:78
void render_low_detail_shield_bitmap(gshield_tri *trip, matrix *orient, vec3d *pos, ubyte r, ubyte g, ubyte b)
Definition: shield.cpp:256
#define f2fl(fx)
Definition: floating.h:37
#define MAX_SHIELD_HITS
Definition: shield.cpp:32
int trinum
Definition: shield.cpp:51
int used
Definition: shield.cpp:50
int n_quadrants
Definition: object.h:158
void vm_vec_scale_add2(vec3d *dest, const vec3d *src, float k)
Definition: vecmat.cpp:284
void render_shields()
Definition: shield.cpp:486
void add_shield_point_multi(int objnum, int tri_num, vec3d *hit_pos)
Definition: shield.cpp:802
Definition: ai.h:329
shield_vertex * verts
Definition: model.h:569
float u
Definition: model.h:561
int num_tris
Definition: shield.cpp:60
uint flags
Definition: ship.h:644
int Poly_count
Definition: shield.cpp:161
int g3_draw_line(vertex *p0, vertex *p1)
Definition: 3ddraw.cpp:112
hull_check orient
Definition: lua.cpp:5049
object * objp
Definition: lua.cpp:3105
GLenum GLenum GLenum GLenum GLenum scale
Definition: Glext.h:8503
void gr_set_bitmap(int bitmap_num, int alphablend_mode, int bitblt_mode, float alpha)
Definition: 2d.cpp:2105
#define Int3()
Definition: pstypes.h:292
ship * shipp
Definition: lua.cpp:9162
vec3d pos
Definition: object.h:152
void bm_page_in_xparent_texture(int bitmapnum, int nframes)
Marks a textures as being used for level and is transparant.
Definition: bmpman.cpp:2514
int Num_shield_points
Definition: shield.cpp:77
GLenum type
Definition: Gl.h:1492
int neighbors[3]
Definition: model.h:553
int bm_load_animation(const char *real_filename, int *nframes, int *fps, int *keyframe, int can_drop_frames, int dir_type)
Loads a bitmap sequance so we can draw with it.
Definition: bmpman.cpp:1420
#define CLAMP(x, min, max)
Definition: pstypes.h:488
void gr_set_color(int r, int g, int b)
Definition: 2d.cpp:1188
int species
Definition: ship.h:1166
struct shield_hit shield_hit
uv_pair texture_position
Definition: pstypes.h:174
void create_tris_containing(vec3d *vp, matrix *orient, shield_info *shieldp, vec3d *tcp, vec3d *centerp, float radius, vec3d *rvec, vec3d *uvec)
Definition: shield.cpp:501
int num_frames
Definition: generic.h:20
typedef int(SCP_EXT_CALLCONV *SCPDLL_PFVERSION)(SCPDLL_Version *)
int instance
Definition: object.h:150
matrix * vm_vector_2_matrix(matrix *m, const vec3d *fvec, const vec3d *uvec, const vec3d *rvec)
Definition: vecmat.cpp:850
void vm_vec_add2(vec3d *dest, const vec3d *src)
Definition: vecmat.cpp:178
#define GR_ALPHABLEND_FILTER
Definition: 2d.h:349
GLdouble GLdouble GLdouble r
Definition: Glext.h:5337
void create_low_detail_poly(int global_index, vec3d *tcp, vec3d *rightv, vec3d *upv)
Definition: shield.cpp:179
struct matrix::@228::@230 vec
int Show_shield_mesh
Definition: shield.cpp:27
GLboolean GLboolean g
Definition: Glext.h:5781
#define TMAP_FLAG_GOURAUD
Definition: tmapper.h:40
detail_levels Detail
Definition: systemvars.cpp:478
int first_frame
Definition: generic.h:19
void shield_hit_close()
Definition: shield.cpp:168
void shield_frame_init()
Definition: shield.cpp:173
int used
Definition: model.h:551
int Break_value
Definition: shield.cpp:873
int get_free_global_shield_index()
Definition: shield.cpp:533
shield_info shield
Definition: model.h:778
ubyte g3_rotate_vertex(vertex *dest, const vec3d *src)
Definition: 3dmath.cpp:97
float u
Definition: pstypes.h:135
float vm_vec_dist(const vec3d *v0, const vec3d *v1)
Definition: vecmat.cpp:355
float * shield_integrity
Definition: ship.h:634
#define MONITOR(function_name)
Definition: pstypes.h:454
Definition: ship.h:534
float apply_damage_to_shield(object *objp, int quadrant, float damage)
Definition: shield.cpp:644
vec3d * vm_vec_unrotate(vec3d *dest, const vec3d *src, const matrix *m)
Definition: vecmat.cpp:959
object Objects[MAX_OBJECTS]
Definition: object.cpp:62
long fix
Definition: pstypes.h:54
unsigned char ubyte
Definition: pstypes.h:62
#define MONITOR_INC(function_name, inc)
Definition: pstypes.h:457
shield_point Shield_points[MAX_SHIELD_POINTS]
Definition: shield.cpp:76
ubyte shield_color[3]
Definition: ship.h:1362
int shield_tri
Definition: shield.cpp:71
int objnum
Definition: shield.cpp:59
matrix orient
Definition: object.h:153
#define TMAP_FLAG_RGB
Definition: tmapper.h:39
vec3d pos
Definition: model.h:560
ubyte b
Definition: pstypes.h:175
void add_shield_point(int objnum, int tri_num, vec3d *hit_pos)
Definition: shield.cpp:779
#define OBJ_SHIP
Definition: object.h:32
void release_shield_hit_bitmap()
Definition: shield.cpp:155
void shield_point_multi_setup()
Definition: shield.cpp:817
void create_shield_explosion_all(object *objp)
Definition: shield.cpp:838
GLbitfield flags
Definition: Glext.h:6722
typedef void(APIENTRY *PFNGLARRAYELEMENTEXTPROC)(GLint i)
void render_shield_triangle(gshield_tri *trip, matrix *orient, vec3d *pos, ubyte r, ubyte g, ubyte b)
Definition: shield.cpp:318
float Shield_scale
Definition: shield.cpp:41
void vm_vec_sub(vec3d *dest, const vec3d *src0, const vec3d *src1)
Definition: vecmat.cpp:168
vec3d Eye_position
Definition: 3dsetup.cpp:27
GLboolean GLboolean GLboolean b
Definition: Glext.h:5781
int shield_hits
Definition: ship.h:660
ship Ships[MAX_SHIPS]
Definition: ship.cpp:122
if(aifft_max_checks<=0)
Definition: aiturret.cpp:1581
void render_shield(int shield_num)
Definition: shield.cpp:381
GLuint GLuint num
Definition: Glext.h:9089
int type
Definition: shield.cpp:58
float frand()
Return random value in range 0.0..1.0- (1.0- means the closest number less than 1.0)
Definition: floating.cpp:35
#define fl2i(fl)
Definition: floating.h:33
vec3d norm
Definition: model.h:554
void visit_children(int trinum, int vertex_index, matrix *orient, shield_info *shieldp, vec3d *tcp, vec3d *centerp, float radius, vec3d *rvec, vec3d *uvec)
Definition: shield.cpp:521
int ship_info_index
Definition: ship.h:539
SCP_vector< ship_info > Ship_info
Definition: ship.cpp:164
#define TMAP_FLAG_TEXTURED
Definition: tmapper.h:36
SCP_vector< float > shield_quadrant
Definition: object.h:159
SCP_vector< species_info > Species_info
hull_check pos
Definition: lua.cpp:5050
void free_global_tri_records(int shnum)
Definition: shield.cpp:243
#define SIF2_MODEL_POINT_SHIELDS
Definition: ship.h:936
void ship_draw_shield(object *objp)
Definition: shield.cpp:879
GLsizei GLsizei GLuint * obj
Definition: Glext.h:5619
float vm_vec_dot(const vec3d *v0, const vec3d *v1)
Definition: vecmat.cpp:312
vec3d * vm_vec_perp(vec3d *dest, const vec3d *p0, const vec3d *p1, const vec3d *p2)
Definition: vecmat.cpp:667
void create_shield_low_detail(int objnum, int model_num, matrix *orient, vec3d *centerp, vec3d *tcp, int tr0, shield_info *shieldp)
Definition: shield.cpp:679
GLint GLsizei count
Definition: Gl.h:1491
#define GR_BITBLT_MODE_NORMAL
Definition: 2d.h:351
int get_global_shield_tri()
Definition: shield.cpp:548
#define SF_DYING
Definition: ship.h:447
polymodel * pm
Definition: lua.cpp:1598
#define MAX(a, b)
Definition: pstypes.h:299
int objnum
Definition: shield.cpp:70
void load_shield_hit_bitmap()
Definition: shield.cpp:90
void copy_shield_to_globals(int objnum, shield_info *shieldp)
Definition: shield.cpp:585
uint flags
Definition: object.h:151
float radius
Definition: object.h:154
ubyte rgb[3]
Definition: shield.cpp:62
mission The_mission
int g3_draw_poly(int nv, vertex **pointlist, uint tmap_flags)
Definition: 3ddraw.cpp:207
int model_num
Definition: lua.cpp:4996
GLclampf GLclampf GLclampf alpha
Definition: Glext.h:5177
struct gshield_tri gshield_tri
char type
Definition: object.h:146
gshield_tri Global_tris[MAX_SHIELD_TRI_BUFFER]
Definition: shield.cpp:80
void rs_compute_uvs(shield_tri *stp, shield_vertex *verts, vec3d *tcp, float radius, vec3d *rightv, vec3d *upv)
Definition: shield.cpp:221
void shield_hit_page_in()
Definition: shield.cpp:109
const GLdouble * v
Definition: Glext.h:5322
shield_tri * tris
Definition: model.h:570
#define UV_MAX
Definition: shield.cpp:39
int ntris
Definition: model.h:568
int ship_is_shield_up(object *obj, int quadrant)
Definition: shield.cpp:964
int myrand()
Definition: systemvars.cpp:102
#define fl2f(fl)
Definition: floating.h:38
ubyte r
Definition: pstypes.h:175
int last_hit_quadrant
Definition: ai.h:421