2 * Copyright (C) Volition, Inc. 1999. All rights reserved.
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
10 * $Logfile: /Freespace2/code/Ship/Shield.cpp $
15 * Stuff pertaining to shield graphical effects, etc.
18 * Revision 1.5 2004/09/20 01:31:44 theoddone33
21 * Revision 1.4 2002/06/17 06:33:11 relnev
22 * ryan's struct patch for gcc 2.95
24 * Revision 1.3 2002/06/09 04:41:26 relnev
25 * added copyright header
27 * Revision 1.2 2002/05/07 03:16:52 theoddone33
28 * The Great Newline Fix
30 * Revision 1.1.1.1 2002/05/03 03:28:10 root
34 * 11 8/03/99 1:46p Dave
35 * Make opacity higher.
37 * 10 8/03/99 11:28a Dave
38 * Fixed shield problem.
40 * 9 8/02/99 10:42p Dave
41 * Make shields less opaque in the nebula.
43 * 8 8/02/99 10:39p Dave
44 * Added colored shields. OoOoOoooOoo
46 * 7 7/15/99 9:20a Andsager
47 * FS2_DEMO initial checkin
49 * 6 3/10/99 6:50p Dave
50 * Changed the way we buffer packets for all clients. Optimized turret
51 * fired packets. Did some weapon firing optimizations.
53 * 5 1/12/99 5:45p Dave
54 * Moved weapon pipeline in multiplayer to almost exclusively client side.
55 * Very good results. Bandwidth goes down, playability goes up for crappy
56 * connections. Fixed object update problem for ship subsystems.
58 * 4 12/01/98 8:06a Dave
59 * Temporary checkin to fix some texture transparency problems in d3d.
61 * 3 11/05/98 5:55p Dave
62 * Big pass at reducing #includes
64 * 2 10/07/98 10:53a Dave
67 * 1 10/07/98 10:51a Dave
69 * 65 5/25/98 12:12a Mike
70 * Make shield effect less CPU-intensive in software. Always use lower
73 * 64 4/22/98 8:37p Mike
74 * Recover gracefully from exhausted MAX_GLOBAL_TRIS asserts.
76 * 63 4/09/98 7:58p John
77 * Cleaned up tmapper code a bit. Put NDEBUG around some ndebug stuff.
78 * Took out XPARENT flag settings in all the alpha-blended texture stuff.
80 * 62 4/02/98 6:28p Lawrance
81 * remove shield code from demo build
83 * 61 4/02/98 11:40a Lawrance
84 * check for #ifdef DEMO instead of #ifdef DEMO_RELEASE
86 * 60 3/31/98 5:32p Mike
87 * Reduce size of some buffers.
89 * 59 3/31/98 5:19p John
90 * Removed demo/save/restore. Made NDEBUG defined compile. Removed a
91 * bunch of debug stuff out of player file. Made model code be able to
92 * unload models and malloc out only however many models are needed.
95 * 58 3/30/98 4:02p John
96 * Made machines with < 32 MB of RAM use every other frame of certain
97 * bitmaps. Put in code to keep track of how much RAM we've malloc'd.
99 * 57 3/30/98 12:18a Lawrance
100 * change some DEMO_RELEASE code to not compile code rather than return
103 * 56 3/29/98 11:33p Mike
104 * Speedup sheidl hit effect at detail levels 1, 3 (in 0..4).
106 * 55 3/29/98 5:02p Adam
107 * changed ANIs referenced for shieldhit effect to all be
108 * shieldhit01a.ani. There won't be different ones for different species
109 * like I once thought.
111 * 54 3/29/98 4:05p John
112 * New paging code that loads everything necessary at level startup.
114 * 53 3/27/98 9:06p Mike
115 * Make shield effect larger in lower detail levels (to match size in
116 * higher detail level) and handle changing detail level whiel shield
119 * 52 3/27/98 8:35p Mike
120 * Detail level support in shield effect system.
122 * 51 3/16/98 4:07p Sandeep
124 * 50 3/12/98 1:24p Mike
125 * When weapons linked, increase firing delay.
126 * Free up weapon slots for AI ships, if necessary.
127 * Backside render shield effect.
128 * Remove shield hit triangle if offscreen.
130 * 49 3/02/98 5:42p John
131 * Removed WinAVI stuff from Freespace. Made all HUD gauges wriggle from
132 * afterburner. Made gr_set_clip work good with negative x &y. Made
133 * model_caching be on by default. Made each cached model have it's own
134 * bitmap id. Made asteroids not rotate when model_caching is on.
136 * 48 2/22/98 4:17p John
137 * More string externalization classification... 190 left to go!
139 * 47 2/14/98 11:13p Mike
140 * Optimize a bit by making old ones go away if Poly_count high.
142 * 46 2/06/98 9:10a Allender
143 * removed an SDL_assert for multiplayer clients
145 * 45 2/05/98 9:21p John
146 * Some new Direct3D code. Added code to monitor a ton of stuff in the
149 * 44 1/28/98 11:15p Allender
150 * work on getting shield effect to show correctly in client side
153 * 43 12/30/97 4:26p Lawrance
154 * Remove .ani from shield animations, avoids bmpman warning
159 // Detail level effects (Detail.shield_effects)
160 // 0 Nothing rendered
161 // 1 An animating bitmap rendered per hit, not shrink-wrapped. Lasts half time. One per ship.
162 // 2 Animating bitmap per hit, not shrink-wrapped. Lasts full time. Unlimited.
163 // 3 Shrink-wrapped texture. Lasts half-time.
164 // 4 Shrink-wrapped texture. Lasts full-time.
172 #include "floating.h"
174 #include "lighting.h"
175 #include "fireballs.h"
179 #include "player.h" // #include of "player.h" is only for debugging!
181 #include "freespace.h"
182 #include "packunpack.h"
183 #include "animplay.h"
185 #include "missionparse.h"
186 #include "multimsgs.h"
189 int New_shield_system = 1;
190 int Show_shield_mesh = 0;
192 #ifndef DEMO // not for FS2_DEMO
194 // One unit in 3d means this in the shield hit texture map.
195 //#define SHIELD_HIT_SCALE 0.075f // Scale decreased by MK on 12/18/97, made about 1/4x as large. Note, larger constant means smaller effect
196 #define SHIELD_HIT_SCALE 0.15f // Doubled on 12/23/97 by MK. Was overflowing. See todo item #924.
197 //#define MAX_SHIELD_HITS 20
198 #define MAX_TRIS_PER_HIT 40 // Number of triangles per shield hit, maximum.
199 #define MAX_SHIELD_HITS 20 // Maximum number of active shield hits.
200 #define MAX_SHIELD_TRI_BUFFER (MAX_SHIELD_HITS*20) // Persistent buffer of triangle comprising all active shield hits.
201 #define SHIELD_HIT_DURATION (3*F1_0/4) // Duration, in milliseconds, of shield hit effect
203 #define SH_UNUSED -1 // Indicates an unused record in Shield_hits
204 #define SH_TYPE_1 1 // Indicates Shield_hits record is of type 1.
206 #define UV_MAX (63.95f/64.0f) // max allowed value until tmapper bugs fixed, 1/24/97
208 float Shield_scale = SHIELD_HIT_SCALE;
210 // Structure which mimics the shield_tri structure in model.h. Since the global shield triangle
211 // array needs the vertex information, we will acutally store the information in this
212 // structure instead of the indices into the vertex list
213 typedef struct gshield_tri {
214 int used; // Set if this triangle is currently in use.
215 int trinum; // a debug parameter
216 fix creation_time; // time at which created.
217 shield_vertex verts[4]; // Triangles, but at lower detail level, a square.
220 typedef struct shield_hit {
221 int start_time; // start time of this object
222 int type; // type, probably the weapon type, to indicate the bitmap to use
223 int objnum; // Object index, needed to get current orientation, position.
224 int num_tris; // Number of Shield_tris comprising this shield.
225 int tri_list[MAX_TRIS_PER_HIT]; // Indices into Shield_tris, triangles for this shield hit.
226 ubyte rgb[3]; // rgb colors
229 // Stores point at which shield was hit.
230 // Gets processed in frame interval.
231 typedef struct shield_point {
232 int objnum; // Object that was hit.
233 int shield_tri; // Triangle in shield mesh that took hit.
234 vector hit_point; // Point in global 3-space of hit.
237 #define MAX_SHIELD_POINTS 100
238 shield_point Shield_points[MAX_SHIELD_POINTS];
239 int Num_shield_points;
240 int Num_multi_shield_points; // used by multiplayer clients
242 gshield_tri Global_tris[MAX_SHIELD_TRI_BUFFER]; // The persistent triangles, part of shield hits.
243 int Num_tris; // Number of triangles in current shield. Would be a local, but needed in numerous routines.
245 shield_hit Shield_hits[MAX_SHIELD_HITS];
247 typedef struct shield_ani {
248 const char *filename;
254 #define MAX_SHIELD_ANIMS MAX_SPECIES_NAMES
255 shield_ani Sheild_ani[MAX_SHIELD_ANIMS] = {
256 { "shieldhit01a", -1, -1 },
257 { "shieldhit01a", -1, -1 },
258 { "shieldhit01a", -1, -1 },
262 int Shield_bitmaps_loaded = 0;
264 // This is a recursive function, so prototype it.
265 extern void create_shield_from_triangle(int trinum, matrix *orient, shield_info *shieldp, vector *tcp, vector *centerp, float radius, vector *rvec, vector *uvec);
267 void load_shield_hit_bitmap()
269 #ifndef DEMO // not for FS2_DEMO
272 // Check if we've already allocated the shield effect bitmaps
273 if ( Shield_bitmaps_loaded )
276 Shield_bitmaps_loaded = 1;
278 for (i=0; i<MAX_SHIELD_ANIMS; i++ ) {
279 Sheild_ani[i].first_frame = bm_load_animation(Sheild_ani[i].filename, &Sheild_ani[i].nframes,NULL, 1);
280 if ( Sheild_ani[i].first_frame < 0 )
287 void shield_hit_page_in()
291 if ( !Shield_bitmaps_loaded ) {
292 load_shield_hit_bitmap();
295 for (i=0; i<MAX_SHIELD_ANIMS; i++ ) {
296 bm_page_in_xparent_texture( Sheild_ani[i].first_frame, Sheild_ani[i].nframes );
301 // Initialize shield hit system. Called from game_level_init()
302 void shield_hit_init()
306 for (i=0; i<MAX_SHIELD_HITS; i++)
307 Shield_hits[i].type = SH_UNUSED;
309 for (i=0; i<MAX_SHIELD_TRI_BUFFER; i++) {
310 Global_tris[i].used = 0;
311 Global_tris[i].creation_time = Missiontime;
314 Num_multi_shield_points = 0;
316 load_shield_hit_bitmap();
319 // ---------------------------------------------------------------------
320 // release_shield_hit_bitmap()
322 // Release the storage allocated to store the shield effect.
324 void release_shield_hit_bitmap()
326 if ( !Shield_bitmaps_loaded )
329 // This doesn't need to do anything; the bitmap manager will
330 // release everything.
335 // ---------------------------------------------------------------------
336 // shield_hit_close()
338 // De-initalize the shield hit system. Called from game_level_close().
340 // TODO: We should probably not bother releasing the shield hit bitmaps every level.
342 void shield_hit_close()
344 release_shield_hit_bitmap();
347 void shield_frame_init()
349 //nprintf(("AI", "Frame %i: Number of shield hits: %i, polycount = %i\n", Framecount, Num_shield_points, Poly_count));
353 Num_shield_points = 0;
356 void create_low_detail_poly(int global_index, vector *tcp, vector *rightv, vector *upv)
361 trip = &Global_tris[global_index];
363 scale = vm_vec_mag(tcp) * 2.0f;
365 vm_vec_scale_add(&trip->verts[0].pos, tcp, rightv, -scale/2.0f);
366 vm_vec_scale_add2(&trip->verts[0].pos, upv, scale/2.0f);
368 vm_vec_scale_add(&trip->verts[1].pos, &trip->verts[0].pos, rightv, scale);
370 vm_vec_scale_add(&trip->verts[2].pos, &trip->verts[1].pos, upv, -scale);
372 vm_vec_scale_add(&trip->verts[3].pos, &trip->verts[2].pos, rightv, -scale);
374 // Set u, v coordinates.
375 // Note, this need only be done once, as it's common for all explosions.
376 trip->verts[0].u = 0.0f;
377 trip->verts[0].v = 0.0f;
379 trip->verts[1].u = 1.0f;
380 trip->verts[1].v = 0.0f;
382 trip->verts[2].u = 1.0f;
383 trip->verts[2].v = 1.0f;
385 trip->verts[3].u = 0.0f;
386 trip->verts[3].v = 1.0f;
390 // ----------------------------------------------------------------------------------------------------
391 // Given a shield triangle, compute the uv coordinates at its vertices given
392 // the center point of the explosion texture, distance to center of shield and
393 // right and up vectors.
394 // For small distances (relative to radius), coordinates can be computed using
395 // distance. For larger values, should comptue angle.
396 void rs_compute_uvs(shield_tri *stp, shield_vertex *verts, vector *tcp, float radius, vector *rightv, vector *upv)
401 for (i=0; i<3; i++) {
404 sv = &verts[stp->verts[i]];
406 vm_vec_sub(&v2cp, &sv->pos, tcp);
407 sv->u = vm_vec_dot(&v2cp, rightv) * Shield_scale + 0.5f;
408 sv->v = - vm_vec_dot(&v2cp, upv) * Shield_scale + 0.5f;
426 // mprintf(("u, v = %7.3f %7.3f\n", stp->verts[i].u, stp->verts[i].v));
432 // ----------------------------------------------------------------------------------------------------
433 // Free records in Global_tris previously used by Shield_hits[shnum].tri_list
434 void free_global_tri_records(int shnum)
438 SDL_assert((shnum >= 0) && (shnum < MAX_SHIELD_HITS));
440 //mprintf(("Freeing up %i global records.\n", Shield_hits[shnum].num_tris));
442 for (i=0; i<Shield_hits[shnum].num_tris; i++){
443 Global_tris[Shield_hits[shnum].tri_list[i]].used = 0;
447 void render_low_detail_shield_bitmap(gshield_tri *trip, matrix *orient, vector *pos, ubyte r, ubyte g, ubyte b)
454 vm_copy_transpose_matrix(&m,orient);
456 for (j=0; j<4; j++ ) {
457 // Rotate point into world coordinates
458 vm_vec_rotate(&pnt, &trip->verts[j].pos, &m);
459 vm_vec_add2(&pnt, pos);
461 // Pnt is now the x,y,z world coordinates of this vert.
462 g3_rotate_vertex(&verts[j], &pnt);
463 verts[j].u = trip->verts[j].u;
464 verts[j].v = trip->verts[j].v;
481 vm_vec_perp(&norm, &trip->verts[0].pos, &trip->verts[1].pos, &trip->verts[2].pos);
483 if ( vm_vec_dot(&norm, &trip->verts[1].pos ) < 0.0 ) {
484 vertlist[0] = &verts[3];
485 vertlist[1] = &verts[2];
486 vertlist[2] = &verts[1];
487 vertlist[3] = &verts[0];
488 g3_draw_poly( 4, vertlist, TMAP_FLAG_TEXTURED | TMAP_FLAG_RGB | TMAP_FLAG_GOURAUD);
490 vertlist[0] = &verts[0];
491 vertlist[1] = &verts[1];
492 vertlist[2] = &verts[2];
493 vertlist[3] = &verts[3];
494 g3_draw_poly( 4, vertlist, TMAP_FLAG_TEXTURED | TMAP_FLAG_RGB | TMAP_FLAG_GOURAUD);
498 // Render one triangle of a shield hit effect on one ship.
499 // Each frame, the triangle needs to be rotated into global coords.
500 // trip pointer to triangle in global array
501 // orient orientation of object shield is associated with
502 // pos center point of object
503 void render_shield_triangle(gshield_tri *trip, matrix *orient, vector *pos, ubyte r, ubyte g, ubyte b)
511 if (trip->trinum == -1)
512 return; // Means this is a quad, must have switched detail_level.
514 vm_copy_transpose_matrix(&m,orient);
516 for (j=0; j<3; j++ ) {
517 // Rotate point into world coordinates
518 vm_vec_rotate(&pnt, &trip->verts[j].pos, &m);
519 vm_vec_add2(&pnt, pos);
521 // Pnt is now the x,y,z world coordinates of this vert.
522 // For this example, I am just drawing a sphere at that point.
523 g3_rotate_vertex(&points[j], &pnt);
524 points[j].u = trip->verts[j].u;
525 points[j].v = trip->verts[j].v;
526 SDL_assert((trip->verts[j].u >= 0.0f) && (trip->verts[j].u <= UV_MAX));
527 SDL_assert((trip->verts[j].v >= 0.0f) && (trip->verts[j].v <= UV_MAX));
528 verts[j] = &points[j];
543 vm_vec_perp(&norm,(vector *)&verts[0]->x,(vector *)&verts[1]->x,(vector*)&verts[2]->x);
544 if ( vm_vec_dot(&norm,(vector *)&verts[1]->x ) >= 0.0 ) {
546 vertlist[0] = verts[2];
547 vertlist[1] = verts[1];
548 vertlist[2] = verts[0];
549 g3_draw_poly( 3, vertlist, TMAP_FLAG_TEXTURED | TMAP_FLAG_RGB | TMAP_FLAG_GOURAUD);
551 g3_draw_poly( 3, verts, TMAP_FLAG_TEXTURED | TMAP_FLAG_RGB | TMAP_FLAG_GOURAUD);
555 MONITOR(NumShieldRend);
557 // Render a shield mesh in the global array Shield_hits[]
558 void render_shield(int shield_num) //, matrix *orient, vector *centerp)
567 if (Shield_hits[shield_num].type == SH_UNUSED) {
571 SDL_assert(Shield_hits[shield_num].objnum >= 0);
573 objp = &Objects[Shield_hits[shield_num].objnum];
575 if (objp->flags & OF_NO_SHIELDS) {
579 // If this object didn't get rendered, don't render its shields. In fact, make the shield hit go away.
580 if (!(objp->flags & OF_WAS_RENDERED)) {
581 Shield_hits[shield_num].type = SH_UNUSED;
585 // At detail levels 1, 3, animations play at double speed to reduce load.
586 if ( (Detail.shield_effects == 1) || (Detail.shield_effects == 3) ) {
587 Shield_hits[shield_num].start_time -= Frametime;
590 MONITOR_INC(NumShieldRend,1);
592 shipp = &Ships[objp->instance];
593 si = &Ship_info[shipp->ship_info_index];
595 // objp, shipp, and si are now setup correctly
597 // If this ship is in its deathroll, make the shield hit effects go away faster.
598 if (shipp->flags & SF_DYING) {
599 Shield_hits[shield_num].start_time -= fl2f(2*flFrametime);
602 // Detail level stuff. When lots of shield hits, maybe make them go away faster.
603 if (Poly_count > 50) {
604 if (Shield_hits[shield_num].start_time + (SHIELD_HIT_DURATION*50)/Poly_count < Missiontime) {
605 Shield_hits[shield_num].type = SH_UNUSED;
606 free_global_tri_records(shield_num);
607 // nprintf(("AI", "* "));
610 } else if ((Shield_hits[shield_num].start_time + SHIELD_HIT_DURATION) < Missiontime) {
611 Shield_hits[shield_num].type = SH_UNUSED;
612 free_global_tri_records(shield_num);
616 orient = &objp->orient;
617 centerp = &objp->pos;
619 int bitmap_id, frame_num, n;
621 // mprintf(("Percent = %7.3f\n", f2fl(Missiontime - Shield_hits[shield_num].start_time)));
624 // Do some sanity checking
625 SDL_assert( (n >=0) && (n<MAX_SPECIES_NAMES));
626 SDL_assert( (n >=0) && (n<MAX_SHIELD_ANIMS));
628 frame_num = fl2i( f2fl(Missiontime - Shield_hits[shield_num].start_time) * Sheild_ani[n].nframes);
629 if ( frame_num >= Sheild_ani[n].nframes ) {
630 frame_num = Sheild_ani[n].nframes - 1;
631 } else if ( frame_num < 0 ) {
632 mprintf(( "HEY! Missiontime went backwards! (Shield.cpp)\n" ));
635 bitmap_id = Sheild_ani[n].first_frame + frame_num;
637 float alpha = 0.9999f;
638 if(The_mission.flags & MISSION_FLAG_FULLNEB){
641 gr_set_bitmap(bitmap_id, GR_ALPHABLEND_FILTER, GR_BITBLT_MODE_NORMAL, alpha, -1, -1);
643 if ( (Detail.shield_effects == 1) || (Detail.shield_effects == 2) ) {
644 if ( bitmap_id != - 1 ) {
645 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]);
649 // AL 06/01/97 don't use SDL_assert() until issue with Missiontime being reset to 0 are worked out
650 if ( bitmap_id != - 1 ) {
651 for (i=0; i<Shield_hits[shield_num].num_tris; i++) {
652 //if (Missiontime == Shield_hits[shield_num].start_time)
653 // nprintf(("AI", "Frame %i: Render triangle %i.\n", Framecount, Global_tris[Shield_hits[shield_num].tri_list[i]].trinum));
654 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]);
660 // Render all the shield hits in the global array Shield_hits[]
661 // This is a temporary function. Shield hit rendering will at least have to
662 // occur with the ship, perhaps even internal to the ship.
663 void render_shields()
667 if (Detail.shield_effects == 0){
668 return; // No shield effect rendered at lowest detail level.
671 if (!New_shield_system){
675 for (i=0; i<MAX_SHIELD_HITS; i++){
676 if (Shield_hits[i].type != SH_UNUSED){
683 // -----------------------------------------------------------------------------------------------------
684 void create_tris_containing(vector *vp, matrix *orient, shield_info *shieldp, vector *tcp, vector *centerp, float radius, vector *rvec, vector *uvec)
687 shield_vertex *verts;
689 verts = shieldp->verts;
691 for (i=0; i<Num_tris; i++) {
692 if ( !shieldp->tris[i].used ) {
693 for (j=0; j<3; j++) {
696 v = verts[shieldp->tris[i].verts[j]].pos;
697 if ((vp->xyz.x == v.xyz.x) && (vp->xyz.y == v.xyz.y) && (vp->xyz.z == v.xyz.z))
698 create_shield_from_triangle(i, orient, shieldp, tcp, centerp, radius, rvec, uvec);
704 void visit_children(int trinum, int vertex_index, matrix *orient, shield_info *shieldp, vector *tcp, vector *centerp, float radius, vector *rvec, vector *uvec)
708 sv = &(shieldp->verts[shieldp->tris[trinum].verts[vertex_index]]);
710 if ( (sv->u > 0.0f) && (sv->u < UV_MAX) && (sv->v > 0.0f) && (sv->v < UV_MAX))
711 create_tris_containing(&sv->pos, orient, shieldp, tcp, centerp, radius, rvec, uvec);
716 int get_free_global_shield_index()
720 while ((gi < MAX_SHIELD_TRI_BUFFER) && (Global_tris[gi].used) && (Global_tris[gi].creation_time + SHIELD_HIT_DURATION > Missiontime)) {
724 // If couldn't find one, choose a random one.
725 if (gi == MAX_SHIELD_TRI_BUFFER)
726 gi = (int) (frand() * MAX_SHIELD_TRI_BUFFER);
731 int get_global_shield_tri()
735 // Find unused shield hit buffer
736 for (shnum=0; shnum<MAX_SHIELD_HITS; shnum++)
737 if (Shield_hits[shnum].type == SH_UNUSED)
740 if (shnum == MAX_SHIELD_HITS) {
741 //nprintf(("AI", "Warning: Shield_hit buffer full! Stealing an old one!\n"));
742 shnum = myrand() % MAX_SHIELD_HITS;
745 SDL_assert((shnum >= 0) && (shnum < MAX_SHIELD_HITS));
750 void create_shield_from_triangle(int trinum, matrix *orient, shield_info *shieldp, vector *tcp, vector *centerp, float radius, vector *rvec, vector *uvec)
752 //nprintf(("AI", "[%3i] ", trinum));
754 rs_compute_uvs( &shieldp->tris[trinum], shieldp->verts, tcp, radius, rvec, uvec);
756 //SDL_assert(trinum < MAX_SHIELD_HITS);
757 shieldp->tris[trinum].used = 1;
759 //mprintf(("%i ", trinum));
760 visit_children(trinum, 0, orient, shieldp, tcp, centerp, radius, rvec, uvec);
761 visit_children(trinum, 1, orient, shieldp, tcp, centerp, radius, rvec, uvec);
762 visit_children(trinum, 2, orient, shieldp, tcp, centerp, radius, rvec, uvec);
765 // Copy information from Current_tris to Global_tris, stuffing information
766 // in a slot in Shield_hits. The Global_tris array is not a shield_tri structure.
767 // We need to store vertex information in the global array since the vertex list
768 // will not be available to us when we actually use the array.
769 void copy_shield_to_globals( int objnum, shield_info *shieldp )
773 int count = 0; // Number of triangles in this shield hit.
774 int shnum; // shield hit number, index in Shield_hits.
776 shnum = get_global_shield_tri();
778 Shield_hits[shnum].type = SH_TYPE_1;
779 // mprintf(("Creating hit #%i at time = %7.3f\n", shnum, f2fl(Missiontime)));
781 for (i = 0; i < shieldp->ntris; i++ ) {
782 if ( shieldp->tris[i].used ) {
783 while ( (gi < MAX_SHIELD_TRI_BUFFER) && (Global_tris[gi].used) && (Global_tris[gi].creation_time + SHIELD_HIT_DURATION > Missiontime)) {
787 // If couldn't find one, choose a random one.
788 if (gi == MAX_SHIELD_TRI_BUFFER)
789 gi = (int) (frand() * MAX_SHIELD_TRI_BUFFER);
791 Global_tris[gi].used = shieldp->tris[i].used;
792 Global_tris[gi].trinum = i;
793 Global_tris[gi].creation_time = Missiontime;
795 // copy the pos/u/v elements of the shield_vertex structure into the shield vertex structure for this global triangle.
796 for (j = 0; j < 3; j++)
797 Global_tris[gi].verts[j] = shieldp->verts[shieldp->tris[i].verts[j]];
798 Shield_hits[shnum].tri_list[count++] = gi;
800 if (count >= MAX_TRIS_PER_HIT) {
801 mprintf(("Warning: Too many triangles in shield hit.\n"));
807 Shield_hits[shnum].num_tris = count;
808 Shield_hits[shnum].start_time = Missiontime;
809 Shield_hits[shnum].objnum = objnum;
811 Shield_hits[shnum].rgb[0] = 255;
812 Shield_hits[shnum].rgb[1] = 255;
813 Shield_hits[shnum].rgb[2] = 255;
814 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 < Num_ship_types)){
815 ship_info *sip = &Ship_info[Ships[Objects[objnum].instance].ship_info_index];
817 Shield_hits[shnum].rgb[0] = sip->shield_color[0];
818 Shield_hits[shnum].rgb[1] = sip->shield_color[1];
819 Shield_hits[shnum].rgb[2] = sip->shield_color[2];
823 // ***** This is the version that works on a quadrant basis.
824 // Return absolute amount of damage not applied.
825 float apply_damage_to_shield(object *objp, int shield_quadrant, float damage)
829 // multiplayer clients bail here if nodamage
830 // if(MULTIPLAYER_CLIENT && (Netgame.debug_flags & NETD_FLAG_CLIENT_NODAMAGE)){
831 if(MULTIPLAYER_CLIENT){
835 if ( (shield_quadrant < 0) || (shield_quadrant > 3) ) return damage;
837 SDL_assert(objp->type == OBJ_SHIP);
838 aip = &Ai_info[Ships[objp->instance].ai_index];
839 aip->last_hit_quadrant = shield_quadrant;
841 objp->shields[shield_quadrant] -= damage;
843 if (objp->shields[shield_quadrant] < 0.0f) {
844 float remaining_damage;
846 remaining_damage = -objp->shields[shield_quadrant];
847 objp->shields[shield_quadrant] = 0.0f;
848 //nprintf(("AI", "Applied %7.3f damage to quadrant #%i, %7.3f passes through\n", damage - remaining_damage, quadrant_num, remaining_damage));
849 return remaining_damage;
851 //nprintf(("AI", "Applied %7.3f damage to quadrant #%i\n", damage, quadrant_num));
857 // At lower detail levels, shield hit effects are a single texture, applied to one enlarged triangle.
858 void create_shield_low_detail(int objnum, int model_num, matrix *orient, vector *centerp, vector *tcp, int tr0, shield_info *shieldp)
864 shnum = get_global_shield_tri();
865 Shield_hits[shnum].type = SH_TYPE_1;
867 gi = get_free_global_shield_index();
869 Global_tris[gi].used = 1;
870 Global_tris[gi].trinum = -1; // This tells triangle renderer to not render in case detail_level was switched.
871 Global_tris[gi].creation_time = Missiontime;
873 Shield_hits[shnum].tri_list[0] = gi;
874 Shield_hits[shnum].num_tris = 1;
875 Shield_hits[shnum].start_time = Missiontime;
876 Shield_hits[shnum].objnum = objnum;
878 Shield_hits[shnum].rgb[0] = 255;
879 Shield_hits[shnum].rgb[1] = 255;
880 Shield_hits[shnum].rgb[2] = 255;
881 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 < Num_ship_types)){
882 ship_info *sip = &Ship_info[Ships[Objects[objnum].instance].ship_info_index];
884 Shield_hits[shnum].rgb[0] = sip->shield_color[0];
885 Shield_hits[shnum].rgb[1] = sip->shield_color[1];
886 Shield_hits[shnum].rgb[2] = sip->shield_color[2];
889 vm_vector_2_matrix(&tom, &shieldp->tris[tr0].norm, NULL, NULL);
890 //rs_compute_uvs( &shieldp->tris[tr0], shieldp->verts, tcp, Objects[objnum].radius, &tom.rvec, &tom.uvec);
892 create_low_detail_poly(gi, tcp, &tom.v.rvec, &tom.v.uvec);
896 // Algorithm for shrink-wrapping a texture across a triangular mesh.
898 // - Given a point of intersection, tcp (local to objnum)
899 // - Vector to center of shield from tcp is v2c.
900 // - Using v2c, compute right and down vectors. These are the vectors of
901 // increasing u and v, respectively.
902 // - Triangle of intersection of tcp is tr0.
903 // - For 3 points in tr0, compute u,v coordinates using up and down vectors
904 // from center point, tcp. Need to know size of explosion texture. N units
905 // along right vector corresponds to O units in explosion texture space.
906 // - For each edge, if either endpoint was outside texture bounds, recursively
907 // apply previous and current step.
909 // Output of above is a list of triangles with u,v coordinates. These u,v
910 // coordinates will have to be clipped against the explosion texture bounds.
912 void create_shield_explosion(int objnum, int model_num, matrix *orient, vector *centerp, vector *tcp, int tr0)
914 // vector v2c; // Vector to center from point tcp
915 matrix tom; // Texture Orientation Matrix
916 // float radius; // Radius of shield, computed as distance from tcp to objp->pos.
917 shield_info *shieldp;
921 if (!New_shield_system)
924 if (Objects[objnum].flags & OF_NO_SHIELDS)
927 pm = model_get(model_num);
928 Num_tris = pm->shield.ntris;
929 //SDL_assert(Num_tris < MAX_SHIELD_HITS);
930 shieldp = &pm->shield;
935 //nprintf(("AI", "Frame %i: Creating explosion on %i.\n", Framecount, objnum));
937 if ( (Detail.shield_effects == 1) || (Detail.shield_effects == 2) ) {
938 create_shield_low_detail(objnum, model_num, orient, centerp, tcp, tr0, shieldp);
942 for (i=0; i<Num_tris; i++)
943 shieldp->tris[i].used = 0;
945 // Compute orientation matrix from normal of surface hit.
946 // Note, this will cause the shape of the bitmap to change abruptly
947 // as the impact point moves to another triangle. To prevent this,
948 // you could average the normals at the vertices, then interpolate the
949 // normals from the vertices to get a smoothly changing normal across the face.
950 // I had tried using the vector from the impact point to the center, which
951 // changes smoothly, but this looked surprisingly bad.
952 vm_vector_2_matrix(&tom, &shieldp->tris[tr0].norm, NULL, NULL);
953 //vm_vec_sub(&v2c, tcp, &Objects[objnum].pos);
955 // Create the shield from the current triangle, as well as its neighbors.
956 create_shield_from_triangle(tr0, orient, shieldp, tcp, centerp, Objects[objnum].radius, &tom.v.rvec, &tom.v.uvec);
957 //nprintf(("AI", "\n"));
959 create_shield_from_triangle(shieldp->tris[tr0].neighbors[i], orient, shieldp, tcp, centerp, Objects[objnum].radius, &tom.v.rvec, &tom.v.uvec);
961 copy_shield_to_globals(objnum, shieldp);
962 // render_shield(orient, centerp);
965 MONITOR(NumShieldHits);
967 // Add data for a shield hit.
968 void add_shield_point(int objnum, int tri_num, vector *hit_pos)
970 //SDL_assert(Num_shield_points < MAX_SHIELD_POINTS);
971 if (Num_shield_points >= MAX_SHIELD_POINTS)
974 MONITOR_INC(NumShieldHits,1);
976 Shield_points[Num_shield_points].objnum = objnum;
977 Shield_points[Num_shield_points].shield_tri = tri_num;
978 Shield_points[Num_shield_points].hit_point = *hit_pos;
982 // in multiplayer -- send the shield hit data to the clients
983 // if ( MULTIPLAYER_MASTER && !(Netgame.debug_flags & NETD_FLAG_CLIENT_NODAMAGE)){
984 // send_shield_explosion_packet( objnum, tri_num, *hit_pos );
987 Ships[Objects[objnum].instance].shield_hits++;
990 // ugh! I wrote a special routine to store shield points for clients in multiplayer
991 // games. Problem is initilization and flow control of normal gameplay make this problem
992 // more than trivial to solve. Turns out that I think I can just keep track of the
993 // shield_points for multiplayer in a separate count -- then assign the multi count to
994 // the normal count at the correct time.
995 void add_shield_point_multi(int objnum, int tri_num, vector *hit_pos)
997 //SDL_assert(Num_multi_shield_points < MAX_SHIELD_POINTS);
999 if (Num_multi_shield_points >= MAX_SHIELD_POINTS)
1002 Shield_points[Num_shield_points].objnum = objnum;
1003 Shield_points[Num_shield_points].shield_tri = tri_num;
1004 Shield_points[Num_shield_points].hit_point = *hit_pos;
1006 Num_multi_shield_points++;
1009 // sets up the shield point hit information for multiplayer clients
1010 void shield_point_multi_setup()
1014 SDL_assert( MULTIPLAYER_CLIENT );
1016 if ( Num_multi_shield_points == 0 )
1019 Num_shield_points = Num_multi_shield_points;
1020 for (i = 0; i < Num_shield_points; i++ ){
1021 Ships[Objects[Shield_points[i].objnum].instance].shield_hits++;
1024 Num_multi_shield_points = 0;
1028 // Create all the shield explosions that occurred on object *objp this frame.
1029 void create_shield_explosion_all(object *objp)
1037 if (Detail.shield_effects == 0){
1041 num = objp->instance;
1042 shipp = &Ships[num];
1044 count = shipp->shield_hits;
1045 objnum = objp-Objects;
1047 for (i=0; i<Num_shield_points; i++) {
1048 if (Shield_points[i].objnum == objnum) {
1049 create_shield_explosion(objnum, shipp->modelnum, &objp->orient, &objp->pos, &Shield_points[i].hit_point, Shield_points[i].shield_tri);
1057 //mprintf(("Creating %i explosions took %7.3f seconds\n", shipp->shield_hits, (float) (timer_get_milliseconds() - start_time)/1000.0f));
1059 // some some reason, clients seem to have a bogus count valud on occation. I"ll chalk it up
1060 // to missed packets :-) MWA 2/6/98
1061 if ( !MULTIPLAYER_CLIENT ){
1062 SDL_assert(count == 0); // Couldn't find all the alleged shield hits. Bogus!
1066 int Break_value = -1;
1068 // This is a debug function.
1069 // Draw the whole shield as a wireframe mesh, not looking at the current
1072 void ship_draw_shield( object *objp)
1080 if (!New_shield_system)
1083 if (objp->flags & OF_NO_SHIELDS)
1086 SDL_assert(objp->instance >= 0);
1088 model_num = Ships[objp->instance].modelnum;
1090 if ( Fred_running ) return;
1092 pm = model_get(model_num);
1094 if (pm->shield.ntris<1) return;
1096 vm_copy_transpose_matrix(&m, &objp->orient);
1098 // Scan all the triangles in the mesh.
1099 for (i=0; i<pm->shield.ntris; i++ ) {
1101 vector gnorm, v2f, tri_point;
1102 vertex prev_pnt, pnt0;
1105 tri = &pm->shield.tris[i];
1107 if (i == Break_value)
1110 // Hack! Only works for object in identity orientation.
1111 // Need to rotate eye position into object's reference frame.
1112 // Only draw facing triangles.
1113 vm_vec_rotate(&tri_point, &pm->shield.verts[tri->verts[0]].pos, &Eye_matrix);
1114 vm_vec_add2(&tri_point, &objp->pos);
1116 vm_vec_sub(&v2f, &tri_point, &Eye_position);
1117 vm_vec_rotate(&gnorm, &tri->norm, &m);
1119 if (vm_vec_dot(&gnorm, &v2f) < 0.0f) {
1122 intensity = (int) (Ships[objp->instance].shield_integrity[i] * 255);
1126 else if (intensity > 255)
1129 gr_set_color(0, 0, intensity);
1131 // Process the vertices.
1132 // Note this rotates each vertex each time it's needed, very dumb.
1133 for (j=0; j<3; j++ ) {
1136 // Rotate point into world coordinates
1137 vm_vec_rotate(&pnt, &pm->shield.verts[tri->verts[j]].pos, &m);
1138 //vm_vec_rotate(&pnt,&pm->shield[i].pnt[j],&m);
1139 vm_vec_add2(&pnt, &objp->pos);
1141 // Pnt is now the x,y,z world coordinates of this vert.
1142 // For this example, I am just drawing a sphere at that
1144 g3_rotate_vertex(&tmp, &pnt);
1147 g3_draw_line(&prev_pnt, &tmp);
1153 g3_draw_line(&pnt0, &prev_pnt);
1159 // Returns true if the shield presents any opposition to something
1160 // trying to force through it.
1161 // If quadrant is -1, looks at entire shield, otherwise
1162 // just one quadrant
1163 int ship_is_shield_up( object *obj, int quadrant )
1165 if ( (quadrant>=0) && (quadrant<=3)) {
1166 // Just check one quadrant
1167 if (obj->shields[quadrant] > SDL_max(2.0f, 0.1f * Ship_info[Ships[obj->instance].ship_info_index].shields/4.0f)) {
1171 // Check all quadrants
1172 float strength = get_shield_strength(obj);
1174 if ( strength > SDL_max(2.0f*4.0f, 0.1f * Ship_info[Ships[obj->instance].ship_info_index].shields )) {
1178 return 0; // no shield strength
1183 //-- CODE TO "BOUNCE" AN ARRAY FROM A GIVEN POINT.
1184 //-- LIKE A MATTRESS.
1185 #define BOUNCE_SIZE ???
1187 byte Bouncer1[BOUNCE_SIZE];
1188 byte Bouncer2[BOUNCE_SIZE];
1190 byte * Bouncer = Bouncer1;
1191 byte * OldBouncer = Bouncer2;
1193 // To wiggle, add value to Bouncer[]
1200 for (i=0; i<BOUNCE_SIZE; i++ ) {
1203 t += OldBouncer[ LEFT ];
1204 t += OldBouncer[ RIGHT ];
1205 t += OldBouncer[ UP ];
1206 t += OldBouncer[ DOWN ];
1208 t = (t/2) - Bouncer[i];
1209 tmp = t - t/16; // 8
1211 if ( tmp < -127 ) tmp = -127;
1212 if ( tmp > 127 ) tmp = 127;
1216 if ( Bouncer == Bouncer1 ) {
1217 OldBouncer = Bouncer1;
1220 OldBouncer = Bouncer2;
1228 // stub out shield functions for the demo
1229 void shield_hit_init() {}
1230 void create_shield_explosion_all(object *objp) {}
1231 void shield_frame_init() {}
1232 void add_shield_point(int objnum, int tri_num, vector *hit_pos) {}
1233 void add_shield_point_multi(int objnum, int tri_num, vector *hit_pos) {}
1234 void shield_point_multi_setup() {}
1235 void shield_hit_close() {}
1236 void ship_draw_shield( object *objp) {}
1237 void shield_hit_page_in() {}
1238 void render_shields() {}
1239 float apply_damage_to_shield(object *objp, int shield_quadrant, float damage) {return damage;}
1240 int ship_is_shield_up( object *obj, int quadrant ) {return 0;}
1245 // return quadrant containing hit_pnt.
1250 // Note: This is in the object's local reference frame. Do _not_ pass a vector in the world frame.
1251 int get_quadrant(vector *hit_pnt)
1255 if (hit_pnt->xyz.x < hit_pnt->xyz.z)
1258 if (hit_pnt->xyz.x < -hit_pnt->xyz.z)