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/Nebula/NebLightning.cpp $
18 * Revision 1.7 2004/09/20 01:31:44 theoddone33
21 * Revision 1.6 2004/07/04 11:39:06 taylor
22 * fix missing debrief text, crash on exit, path separator's, warning fixes, no GR_SOFT
24 * Revision 1.5 2003/05/25 02:30:43 taylor
27 * Revision 1.4 2002/06/17 06:33:09 relnev
28 * ryan's struct patch for gcc 2.95
30 * Revision 1.3 2002/06/09 04:41:23 relnev
31 * added copyright header
33 * Revision 1.2 2002/05/07 03:16:47 theoddone33
34 * The Great Newline Fix
36 * Revision 1.1.1.1 2002/05/03 03:28:10 root
40 * 10 8/15/99 3:50p Dave
41 * Don't process lightning at the very beginning of a mission.
43 * 9 8/12/99 10:38a Anoop
44 * Removed unnecessary Int3().
46 * 8 8/05/99 2:06a Dave
49 * 7 7/27/99 9:51p Andsager
50 * make mprintf's into nprintf's
52 * 6 7/03/99 5:50p Dave
53 * Make rotated bitmaps draw properly in padlock views.
55 * 5 7/02/99 4:31p Dave
56 * Much more sophisticated lightning support.
58 * 4 6/09/99 10:32a Dave
59 * Made random lighting bolts behave more like the E3 demo. Generally more
62 * 3 5/26/99 11:46a Dave
63 * Added ship-blasting lighting and made the randomization of lighting
64 * much more customizable.
66 * 2 5/24/99 5:45p Dave
67 * Added detail levels to the nebula, with a decent speedup. Split nebula
68 * lightning into its own section.
77 #include "freespace.h"
80 #include "missionparse.h"
82 #include "neblightning.h"
85 #include "multimsgs.h"
87 // ------------------------------------------------------------------------------------------------------
88 // NEBULA LIGHTNING DEFINES/VARS
92 #define MAX_BOLT_TYPES_INTERNAL 11
94 // see lightning.tbl for explanations of these values
95 typedef struct bolt_type {
96 char name[NAME_LENGTH];
117 int Num_bolt_types = 0;
118 bolt_type Bolt_types[MAX_BOLT_TYPES_INTERNAL];
121 int Num_storm_types = 0;
122 storm_type Storm_types[MAX_STORM_TYPES];
125 // actual lightning bolt stuff -------
127 #define MAX_LIGHTNING_NODES 500
129 // nodes in a lightning bolt
133 typedef struct l_node {
134 vector pos; // world position
135 l_node *links[3]; // 3 links for lightning children
137 l_node *next, *prev; // for used and free-lists only
142 l_node Nebl_nodes[MAX_LIGHTNING_NODES];
145 // lightning node lists
146 l_node Nebl_free_list;
147 l_node Nebl_used_list;
149 // actual lightning bolt themselves
150 typedef struct l_bolt {
151 l_node *head; // head of the lightning bolt
152 int bolt_life; // remaining life timestamp
153 ubyte used; // used or not
154 ubyte first_frame; // if he hasn't been rendered at least once
158 vector start, strike, midpoint;
159 int delay; // delay stamp
160 int strikes_left; // #of strikes left
164 #define MAX_LIGHTNING_BOLTS 10
167 l_bolt Nebl_bolts[MAX_LIGHTNING_BOLTS];
168 int Nebl_bolt_count = 0;
170 // one cross-section of a lightning bolt
171 typedef struct l_section {
176 // points on the basic cross section
177 vector Nebl_ring[3] = {
178 { { { -1.0f, 0.0f, 0.0f } } },
179 { { { 1.0f, 0.70f, 0.0f } } },
180 { { { 1.0f, -0.70f, 0.0f } } }
183 // pinched off cross-section
184 vector Nebl_ring_pinched[3] = {
185 { { { -0.05f, 0.0f, 0.0f } } },
186 { { { 0.05f, 0.035f, 0.0f } } },
187 { { { 0.05f, -0.035f, 0.0f } } }
190 // globals used for rendering and generating bolts
191 int Nebl_flash_count = 0; // # of points rendered onscreen for this bolt
192 float Nebl_flash_x = 0.0f; // avg x of the points rendered
193 float Nebl_flash_y = 0.0f; // avg y of the points rendered
194 float Nebl_bang = 0.0; // distance to the viewer object
195 float Nebl_alpha = 0.0f; // alpha to use when rendering the bolt itself
196 float Nebl_glow_alpha = 0.0f; // alpha to use when rendering the bolt glow
197 int Nebl_stamp = -1; // random timestamp for making bolts
198 float Nebl_bolt_len; // length of the current bolt being generated
199 bolt_type *Nebl_type; // bolt type
200 matrix Nebl_bolt_dir; // orientation matrix of the bolt being generated
201 vector Nebl_bolt_start; // start point of the bolt being generated
202 vector Nebl_bolt_strike; // strike point of the bolt being generated
204 // the type of active storm
205 storm_type *Storm = NULL;
210 dc_get_arg(ARG_FLOAT);
211 Bolt_types[DEBUG_BOLT].b_scale = Dc_arg_float;
215 dc_get_arg(ARG_FLOAT);
216 Bolt_types[DEBUG_BOLT].b_rand = Dc_arg_float;
220 dc_get_arg(ARG_FLOAT);
221 Bolt_types[DEBUG_BOLT].b_shrink = Dc_arg_float;
225 dc_get_arg(ARG_FLOAT);
226 Bolt_types[DEBUG_BOLT].b_poly_pct = Dc_arg_float;
230 dc_get_arg(ARG_FLOAT);
231 Bolt_types[DEBUG_BOLT].b_add = Dc_arg_float;
236 Bolt_types[DEBUG_BOLT].num_strikes = Dc_arg_int;
240 dc_get_arg(ARG_FLOAT);
241 Bolt_types[DEBUG_BOLT].noise = Dc_arg_float;
245 dc_get_arg(ARG_FLOAT);
246 Bolt_types[DEBUG_BOLT].b_bright = Dc_arg_float;
251 Bolt_types[DEBUG_BOLT].lifetime = Dc_arg_int;
255 dc_printf("Debug lightning bolt settings :\n");
257 dc_printf("b_scale : %f\n", Bolt_types[DEBUG_BOLT].b_scale);
258 dc_printf("b_rand : %f\n", Bolt_types[DEBUG_BOLT].b_rand);
259 dc_printf("b_shrink : %f\n", Bolt_types[DEBUG_BOLT].b_shrink);
260 dc_printf("b_poly_pct : %f\n", Bolt_types[DEBUG_BOLT].b_poly_pct);
261 dc_printf("b_add : %f\n", Bolt_types[DEBUG_BOLT].b_add);
262 dc_printf("b_strikes : %d\n", Bolt_types[DEBUG_BOLT].num_strikes);
263 dc_printf("b_noise : %f\n", Bolt_types[DEBUG_BOLT].noise);
264 dc_printf("b_bright : %f\n", Bolt_types[DEBUG_BOLT].b_bright);
265 dc_printf("b_lifetime : %d\n", Bolt_types[DEBUG_BOLT].lifetime);
269 // nebula lightning intensity (0.0 to 1.0)
270 float Nebl_intensity = 0.6667f;
272 // min and max times for random lightning
273 int Nebl_random_min = 750; // min random time
274 int Nebl_random_max = 10000; // max random time
276 // min and max times for cruiser lightning
277 int Nebl_cruiser_min = 5000; // min cruiser time
278 int Nebl_cruiser_max = 25000; // max cruiser time
280 // min and max times for cap ships
281 int Nebl_cap_min = 4000; // min cap time
282 int Nebl_cap_max = 18000; // max cap time
284 // min and max time for super caps
285 int Nebl_supercap_min = 3000; // min supercap time
286 int Nebl_supercap_max = 12000; // max supercap time
288 DCF(lightning_intensity, "")
290 dc_get_arg(ARG_FLOAT);
291 float val = Dc_arg_float;
294 } else if(val > 1.0f){
298 Nebl_intensity = 1.0f - val;
301 // ------------------------------------------------------------------------------------------------------
302 // NEBULA LIGHTNING FORWARD DECLARATIONS
305 // "new" a lightning node
308 // "delete" a lightning node
309 void nebl_delete(l_node *lp);
311 // free up a the nodes of the passed in bolt
312 void nebl_release(l_node *bolt_head);
314 // generate a lightning bolt, returns l_left (the "head") and l_right (the "tail")
315 int nebl_gen(vector *left, vector *right, float depth, float max_depth, int child, l_node **l_left, l_node **l_right);
317 // output top and bottom vectors
318 // fvec == forward vector (eye viewpoint basically. in world coords)
319 // pos == world coordinate of the point we're calculating "around"
320 // w == width of the diff between top and bottom around pos
321 void nebl_calc_facing_pts_smart( vector *top, vector *bot, vector *fvec, vector *pos, float w, float z_add );
323 // render a section of the bolt
324 void nebl_render_section(bolt_type *bi, l_section *a, l_section *b);
326 // generate a section
327 void nebl_generate_section(bolt_type *bi, float width, l_node *a, l_node *b, l_section *c, l_section *cap, int pinch_a, int pinch_b);
330 void nebl_render(bolt_type *bi, l_node *whee, float width, l_section *prev = NULL);
332 // given a valid, complete bolt, jitter him based upon his noise
333 void nebl_jitter(l_bolt *b);
335 // return the index of a given bolt type by name
336 int nebl_get_bolt_index(char *name);
338 // return the index of a given storm type by name
339 int nebl_get_storm_index(char *name);
342 // ------------------------------------------------------------------------------------------------------
343 // NEBULA LIGHTNING FUNCTIONS
346 // initialize nebula lightning at game startup
350 char name[NAME_LENGTH+10] = "";
351 bolt_type bogus_lightning, *l;
352 storm_type bogus_storm, *s;
356 // parse the lightning table
357 read_file_text("lightning.tbl");
363 memset(Bolt_types, 0, sizeof(bolt_type) * MAX_BOLT_TYPES_INTERNAL);
365 // parse the individual lightning bolt types
366 required_string("#Bolts begin");
367 while(!optional_string("#Bolts end")){
369 if(Num_bolt_types >= MAX_BOLT_TYPES){
370 l = &bogus_lightning;
372 l = &Bolt_types[Num_bolt_types];
376 required_string("$Bolt:");
377 stuff_string(l->name, F_NAME, NULL);
380 required_string("+b_scale:");
381 stuff_float(&l->b_scale);
384 required_string("+b_shrink:");
385 stuff_float(&l->b_shrink);
388 required_string("+b_poly_pct:");
389 stuff_float(&l->b_poly_pct);
392 required_string("+b_rand:");
393 stuff_float(&l->b_rand);
396 required_string("+b_add:");
397 stuff_float(&l->b_add);
400 required_string("+b_strikes:");
401 stuff_int(&l->num_strikes);
404 required_string("+b_lifetime:");
405 stuff_int(&l->lifetime);
408 required_string("+b_noise:");
409 stuff_float(&l->noise);
412 required_string("+b_emp:");
413 stuff_float(&l->emp_intensity);
414 stuff_float(&l->emp_time);
417 required_string("+b_texture:");
418 stuff_string(name, F_NAME, NULL);
419 if((l != &bogus_lightning) && !Fred_running){
420 l->texture = bm_load(name);
424 required_string("+b_glow:");
425 stuff_string(name, F_NAME, NULL);
426 if((l != &bogus_lightning) && !Fred_running){
427 l->glow = bm_load(name);
431 required_string("+b_bright:");
432 stuff_float(&l->b_bright);
434 // increment the # of bolt types
435 if(l != &bogus_lightning){
440 // copy the first bolt to the debug bolt
441 memcpy(&Bolt_types[DEBUG_BOLT], &Bolt_types[0], sizeof(bolt_type));
444 required_string("#Storms begin");
445 while(!optional_string("#Storms end")){
447 if(Num_storm_types >= MAX_STORM_TYPES){
450 s = &Storm_types[Num_storm_types];
454 required_string("$Storm:");
455 stuff_string(s->name, F_NAME, NULL);
458 s->num_bolt_types = 0;
459 while(optional_string("+bolt:")){
460 stuff_string(name, F_NAME, NULL);
463 if(s->num_bolt_types < MAX_BOLT_TYPES){
464 s->bolt_types[s->num_bolt_types] = (char)nebl_get_bolt_index(name);
465 SDL_assert(s->bolt_types[s->num_bolt_types] != -1);
471 required_string("+bolt_prec:");
477 required_string("+flavor:");
478 stuff_float(&s->flavor.xyz.x);
479 stuff_float(&s->flavor.xyz.y);
480 stuff_float(&s->flavor.xyz.z);
483 required_string("+random_freq:");
488 required_string("+random_count:");
489 stuff_int(&s->min_count);
490 stuff_int(&s->max_count);
492 // increment the # of bolt types
493 if(s != &bogus_storm){
497 } catch (parse_error_t rval) {
498 Error(LOCATION, "Unable to parse lightning.tbl! Code = %i.\n", (int)rval);
503 // initialize lightning before entering a level
504 void nebl_level_init()
508 // zero all lightning bolts
509 for(idx=0; idx<MAX_LIGHTNING_BOLTS; idx++){
510 Nebl_bolts[idx].head = NULL;
511 Nebl_bolts[idx].bolt_life = -1;
512 Nebl_bolts[idx].used = 0;
515 // initialize node list
517 list_init( &Nebl_free_list );
518 list_init( &Nebl_used_list );
520 // Link all object slots into the free list
521 for (idx=0; idx<MAX_LIGHTNING_NODES; idx++) {
522 list_append(&Nebl_free_list, &Nebl_nodes[idx] );
525 // zero the random timestamp
528 // null the storm. let mission parsing set it up
532 // render all lightning bolts
533 void nebl_render_all()
539 // no lightning in non-nebula missions
540 if(!(The_mission.flags & MISSION_FLAG_FULLNEB)){
544 // if we have no storm
550 for(idx=0; idx<MAX_LIGHTNING_BOLTS; idx++){
551 b = &Nebl_bolts[idx];
553 // if this is being used
555 SDL_assert(b->head != NULL);
562 if((b->type < 0) || ((b->type >= Num_bolt_types) && (b->type != DEBUG_BOLT)) ){
567 bi = &Bolt_types[(int)b->type];
569 // if this guy is still on a delay
571 if(timestamp_elapsed(b->delay)){
578 // if the timestamp on this guy has expired
579 if((b->bolt_life < 0) || timestamp_elapsed(b->bolt_life)){
580 // if this is a multiple strike bolt, jitter it and reset
581 if(b->strikes_left-1 > 0){
582 b->bolt_life = timestamp(bi->lifetime / bi->num_strikes);
587 // by continuing here we skip rendering for one frame, which makes it look more like real lightning
590 // otherwise he's completely done, so release him
592 // maybe free up node data
594 nebl_release(b->head);
599 nprintf(("lightning", "Released bolt. %d used nodes!\n", Num_lnodes));
606 // pick some cool alpha values
607 Nebl_alpha = frand();
608 Nebl_glow_alpha = frand();
610 // otherwise render him
611 Nebl_flash_count = 0;
614 Nebl_bang = 10000000.0f;
615 nebl_render(bi, b->head, b->width);
617 // if this is the first frame he has been rendered, determine if we need to make a flash and sound effect
623 // if we rendered any points
624 if(Nebl_flash_count){
625 Nebl_flash_x /= (float)Nebl_flash_count;
626 Nebl_flash_y /= (float)Nebl_flash_count;
628 // quick distance from the center of the screen
629 float x = Nebl_flash_x - (gr_screen.max_w / 2.0f);
630 float y = Nebl_flash_y - (gr_screen.max_h / 2.0f);
631 float dist = fl_sqrt((x * x) + (y * y));
632 if(dist / (gr_screen.max_w / 2.0f) < 1.0f){
633 flash = 1.0f - (dist / (gr_screen.max_w / 2.0f));
635 // scale the flash by bolt type
636 flash *= bi->b_bright;
638 game_flash(flash, flash, flash);
641 // do some special stuff on the very first strike of the bolt
642 if(b->strikes_left == bi->num_strikes){
645 if(Nebl_bang < 40.0f){
647 } else if(Nebl_bang > 400.0f){
650 bang = 1.0f - (Nebl_bang / 400.0f);
652 if(frand_range(0.0f, 1.0f) < 0.5f){
653 snd_play(&Snds[SND_LIGHTNING_2], 0.0f, bang, SND_PRIORITY_DOUBLE_INSTANCE);
655 snd_play(&Snds[SND_LIGHTNING_1], 0.0f, bang, SND_PRIORITY_DOUBLE_INSTANCE);
659 if(bi->emp_intensity > 0.0f){
660 emp_apply(&b->midpoint, 0.0f, vm_vec_dist(&b->start, &b->strike), bi->emp_intensity, bi->emp_time);
669 // process lightning (randomly generate bolts, etc, etc);
674 // non-nebula mission
675 if(!(The_mission.flags & MISSION_FLAG_FULLNEB)){
679 // non servers in multiplayer don't do this
680 if((Game_mode & GM_MULTIPLAYER) && !MULTIPLAYER_MASTER){
684 // if there's no chosen storm
689 // don't process lightning bolts unless we're a few seconds in
690 if(f2fl(Missiontime) < 3.0f){
695 if(Nebl_stamp == -1){
696 Nebl_stamp = timestamp((int)frand_range((float)Storm->min, (float)Storm->max));
701 if(timestamp_elapsed(Nebl_stamp)){
702 // determine how many bolts to spew
703 num_bolts = (int)frand_range((float)Storm->min_count, (float)Storm->max_count);
704 for(idx=0; idx<num_bolts; idx++){
705 // hmm. for now just pick a random bolt type and run with it
709 s1 = (int)frand_range(0.0f, (float)Neb2_slices);
710 s2 = (int)frand_range(0.0f, (float)Neb2_slices);
711 s3 = (int)frand_range(0.0f, (float)Neb2_slices);
713 e1 = (int)frand_range(0.0f, (float)Neb2_slices);
714 e2 = (int)frand_range(0.0f, (float)Neb2_slices);
715 e3 = (int)frand_range(0.0f, (float)Neb2_slices);
717 // never choose the middle cube
718 if((s1 == 2) && (s2 == 2) && (s3 == 2)){
722 if((e1 == 2) && (e2 == 2) && (e3 == 2)){
728 } while((s1 == e1) && (s2 == e2) && (s3 == e3));
730 vector start = Neb2_cubes[s1][s2][s3].pt;
731 vector strike = Neb2_cubes[e1][e2][e3].pt;
733 // add some flavor to the bolt. mmmmmmmm, lightning
734 if(!IS_VEC_NULL(&Storm->flavor)){
735 // start with your basic hot sauce. measure how much you have
736 vector your_basic_hot_sauce;
737 vm_vec_sub(&your_basic_hot_sauce, &strike, &start);
738 float how_much_hot_sauce = vm_vec_normalize(&your_basic_hot_sauce);
740 // now figure out how much of that good wing sauce to add
741 vector wing_sauce = Storm->flavor;
742 if(frand_range(0.0, 1.0f) < 0.5f){
743 vm_vec_scale(&wing_sauce, -1.0f);
745 float how_much_of_that_good_wing_sauce_to_add = vm_vec_normalize(&wing_sauce);
747 // mix the two together, taking care not to add too much
749 if(how_much_of_that_good_wing_sauce_to_add > 1000.0f){
750 how_much_of_that_good_wing_sauce_to_add = 1000.0f;
752 vm_vec_interp_constant(&the_mixture, &your_basic_hot_sauce, &wing_sauce, how_much_of_that_good_wing_sauce_to_add / 1000.0f);
754 // take the final sauce and store it in the proper container
755 vm_vec_scale(&the_mixture, how_much_hot_sauce);
757 // make sure to put it on everything! whee!
758 vm_vec_add(&strike, &start, &the_mixture);
761 int type = (int)frand_range(0.0f, (float)(Storm->num_bolt_types-1));
762 nebl_bolt(Storm->bolt_types[type], &start, &strike);
765 // reset the timestamp
766 Nebl_stamp = timestamp((int)frand_range((float)Storm->min, (float)Storm->max));
770 // create a lightning bolt
771 void nebl_bolt(int type, vector *start, vector *strike)
781 if(!(The_mission.flags & MISSION_FLAG_FULLNEB)){
787 for(idx=0; idx<MAX_LIGHTNING_BOLTS; idx++){
788 if(!Nebl_bolts[idx].used){
798 if((type < 0) || ((type >= Num_bolt_types) && (type != DEBUG_BOLT)) ){
801 bi = &Bolt_types[type];
803 // get a pointer to the bolt
804 bolt = &Nebl_bolts[idx];
807 bolt->start = *start;
808 bolt->strike = *strike;
809 bolt->strikes_left = bi->num_strikes;
811 bolt->type = (char)type;
812 bolt->first_frame = 1;
813 bolt->bolt_life = timestamp(bi->lifetime / bi->num_strikes);
815 Nebl_bolt_start = *start;
816 Nebl_bolt_strike = *strike;
819 if(bolt->delay != -1){
820 bolt->delay = timestamp(bolt->delay);
823 // setup the rest of the important bolt data
824 if(vm_vec_same(&Nebl_bolt_start, &Nebl_bolt_strike)){
825 Nebl_bolt_strike.xyz.z += 150.0f;
827 Nebl_bolt_len = vm_vec_dist(&Nebl_bolt_start, &Nebl_bolt_strike);
828 vm_vec_sub(&dir, &Nebl_bolt_strike, &Nebl_bolt_start);
831 vm_vec_scale_add(&bolt->midpoint, &Nebl_bolt_start, &dir, 0.5f);
833 bolt_len = vm_vec_normalize(&dir);
834 vm_vector_2_matrix(&Nebl_bolt_dir, &dir, NULL, NULL);
836 // global type for generating the bolt
839 // try and make the bolt
840 if(!nebl_gen(&Nebl_bolt_start, &Nebl_bolt_strike, 0, 4, 0, &bolt->head, &tail)){
841 if(bolt->head != NULL){
842 nebl_release(bolt->head);
850 // setup the rest of the data
852 bolt->width = bi->b_poly_pct * bolt_len;
854 // if i'm a multiplayer master, send a bolt packet
855 if(MULTIPLAYER_MASTER){
856 send_lightning_packet(type, start, strike);
860 // get the current # of active lightning bolts
861 int nebl_get_active_bolts()
863 return Nebl_bolt_count;
866 // get the current # of active nodes
867 int nebl_get_active_nodes()
872 // set the storm (call from mission parse)
873 void nebl_set_storm(char *name)
875 int index = nebl_get_storm_index(name);
879 if((index >= 0) && (index < Num_storm_types)){
880 Storm = &Storm_types[index];
884 // ------------------------------------------------------------------------------------------------------
885 // NEBULA LIGHTNING FORWARD DEFINITIONS
888 // "new" a lightning node
893 // if we're out of nodes
894 if(Num_lnodes >= MAX_LIGHTNING_NODES){
896 nprintf(("lightning", "Out of lightning nodes!\n"));
900 // get a new node off the freelist
901 lp = GET_FIRST(&Nebl_free_list);
902 SDL_assert( lp != &Nebl_free_list ); // shouldn't have the dummy element
904 // remove trailp from the free list
905 list_remove( &Nebl_free_list, lp );
907 // insert trailp onto the end of used list
908 list_append( &Nebl_used_list, lp );
917 // return the pointer
921 // "delete" a lightning node
922 void nebl_delete(l_node *lp)
924 // remove objp from the used list
925 list_remove( &Nebl_used_list, lp );
927 // add objp to the end of the free
928 list_append( &Nebl_free_list, lp );
934 // free a lightning bolt
935 void nebl_release(l_node *whee)
942 // release all of our children
943 if(whee->links[LINK_RIGHT] != NULL){
944 nebl_release(whee->links[LINK_RIGHT]);
946 if(whee->links[LINK_CHILD] != NULL){
947 nebl_release(whee->links[LINK_CHILD]);
954 int nebl_gen(vector *left, vector *right, float depth, float max_depth, int child, l_node **l_left, l_node **l_right)
956 l_node *child_node = NULL;
957 float d = vm_vec_dist_quick( left, right );
959 // if we've reached the critical point
960 if ( d < 0.30f || (depth > max_depth) ){
962 l_node *new_left = nebl_new();
963 if(new_left == NULL){
966 new_left->links[0] = NULL; new_left->links[1] = NULL; new_left->links[2] = NULL;
967 new_left->pos = vmd_zero_vector;
968 l_node *new_right = nebl_new();
969 if(new_right == NULL){
970 nebl_delete(new_left);
973 new_right->links[0] = NULL; new_right->links[1] = NULL; new_right->links[2] = NULL;
974 new_right->pos = vmd_zero_vector;
977 new_left->pos = *left;
978 new_left->links[LINK_RIGHT] = new_right;
982 new_right->pos = *right;
983 new_right->links[LINK_LEFT] = new_left;
984 *l_right = new_right;
992 vm_vec_avg( &tmp, left, right );
994 // sometimes generate children
995 if(!child && (frand() <= Nebl_type->b_rand)){
996 // get a point on the plane of the strike
998 vm_vec_random_in_circle(&tmp2, &Nebl_bolt_strike, &Nebl_bolt_dir, Nebl_bolt_len * Nebl_type->b_scale, 0);
1000 // maybe move away from the plane
1002 vm_vec_sub(&dir, &tmp2, &tmp);
1003 vm_vec_scale_add(&tmp2, &tmp, &dir, Nebl_type->b_shrink);
1007 if(!nebl_gen(&tmp, &tmp2, 0, 2, 1, &child_node, &argh)){
1008 if(child_node != NULL){
1009 nebl_release(child_node);
1015 float scaler = 0.30f;
1016 tmp.xyz.x += (frand()-0.5f)*d*scaler;
1017 tmp.xyz.y += (frand()-0.5f)*d*scaler;
1018 tmp.xyz.z += (frand()-0.5f)*d*scaler;
1020 // generate left half
1023 if(!nebl_gen( left, &tmp, depth+1, max_depth, child, &ll, &lr )){
1024 if(child_node != NULL){
1025 nebl_release(child_node);
1033 // generate right half
1036 if(!nebl_gen( &tmp, right, depth+1, max_depth, child, &rl, &rr )){
1037 if(child_node != NULL){
1038 nebl_release(child_node);
1049 // splice the two together
1050 lr->links[LINK_RIGHT] = rl->links[LINK_RIGHT];
1051 lr->links[LINK_RIGHT]->links[LINK_LEFT] = lr;
1054 // if we generated a child, stick him on
1055 if(child_node != NULL){
1056 lr->links[LINK_CHILD] = child_node;
1067 // output top and bottom vectors
1068 // fvec == forward vector (eye viewpoint basically. in world coords)
1069 // pos == world coordinate of the point we're calculating "around"
1070 // w == width of the diff between top and bottom around pos
1071 void nebl_calc_facing_pts_smart( vector *top, vector *bot, vector *fvec, vector *pos, float w, float z_add )
1078 vm_vec_sub( &rvec, &Eye_position, &temp );
1079 vm_vec_normalize( &rvec );
1081 vm_vec_crossprod(&uvec,fvec,&rvec);
1082 vm_vec_normalize(&uvec);
1084 vm_vec_scale_add( top, &temp, &uvec, w/2.0f );
1085 vm_vec_scale_add( bot, &temp, &uvec, -w/2.0f );
1087 vm_vec_scale_add2( top, &rvec, z_add );
1088 vm_vec_scale_add2( bot, &rvec, z_add );
1091 // render a section of the bolt
1092 void nebl_render_section(bolt_type *bi, l_section *a, l_section *b)
1095 vertex *verts[4] = {&v[0], &v[1], &v[2], &v[3]};
1098 // Sets mode. Returns previous mode.
1099 gr_zbuffer_set(GR_ZBUFF_FULL);
1102 for(idx=0; idx<2; idx++){
1104 v[0].u = 0.0f; v[0].v = 0.0f;
1106 v[1] = a->vex[idx+1];
1107 v[1].u = 1.0f; v[1].v = 0.0f;
1109 v[2] = b->vex[idx+1];
1110 v[2].u = 1.0f; v[2].v = 1.0f;
1113 v[3].u = 0.0f; v[3].v = 1.0f;
1116 gr_set_bitmap(bi->texture, GR_ALPHABLEND_FILTER, GR_BITBLT_MODE_NORMAL, Nebl_alpha, -1, -1);
1117 g3_draw_poly(4, verts, TMAP_FLAG_TEXTURED | TMAP_FLAG_CORRECT);
1122 v[0].u = 0.0f; v[0].v = 0.0f;
1125 v[1].u = 1.0f; v[1].v = 0.0f;
1128 v[2].u = 1.0f; v[2].v = 1.0f;
1131 v[3].u = 0.0f; v[3].v = 1.0f;
1133 gr_set_bitmap(bi->texture, GR_ALPHABLEND_FILTER, GR_BITBLT_MODE_NORMAL, Nebl_alpha, -1, -1);
1134 g3_draw_poly(4, verts, TMAP_FLAG_TEXTURED | TMAP_FLAG_CORRECT);
1136 // draw the glow beam
1137 verts[0] = &a->glow_vex[0];
1138 verts[0]->v = 0.0f; verts[0]->u = 0.0f;
1140 verts[1] = &a->glow_vex[1];
1141 verts[1]->v = 1.0f; verts[1]->u = 0.0f;
1143 verts[2] = &b->glow_vex[1];
1144 verts[2]->v = 1.0f; verts[2]->u = 1.0f;
1146 verts[3] = &b->glow_vex[0];
1147 verts[3]->v = 0.0f; verts[3]->u = 1.0f;
1149 gr_set_bitmap(bi->glow, GR_ALPHABLEND_FILTER, GR_BITBLT_MODE_NORMAL, Nebl_glow_alpha, -1, -1);
1150 g3_draw_poly(4, verts, TMAP_FLAG_TEXTURED | TMAP_FLAG_CORRECT);
1153 // generate a section
1154 void nebl_generate_section(bolt_type *bi, float width, l_node *a, l_node *b, l_section *c, l_section *cap, int pinch_a, int pinch_b)
1161 vector glow_a, glow_b;
1164 vm_vec_sub(&dir, &a->pos, &b->pos);
1165 vm_vec_copy_normalize(&dir_normal, &dir);
1166 vm_vector_2_matrix(&m, &dir_normal, NULL, NULL);
1168 // distance to player
1169 float bang_dist = vm_vec_dist_quick(&Eye_position, &a->pos);
1170 if(bang_dist < Nebl_bang){
1171 Nebl_bang = bang_dist;
1174 // rotate the basic section into world
1175 for(idx=0; idx<3; idx++){
1178 vm_vec_rotate(&pt, &Nebl_ring_pinched[idx], &m);
1180 vm_vec_copy_scale(&temp, &Nebl_ring[idx], width);
1181 vm_vec_rotate(&pt, &temp, &m);
1183 vm_vec_add2(&pt, &a->pos);
1186 g3_rotate_vertex(&c->vex[idx], &pt);
1187 g3_project_vertex(&c->vex[idx]);
1189 // if first frame, keep track of the average screen pos
1190 if((c->vex[idx].sx >= 0) && (c->vex[idx].sx < gr_screen.max_w) && (c->vex[idx].sy >= 0) && (c->vex[idx].sy < gr_screen.max_h)){
1191 Nebl_flash_x += c->vex[idx].sx;
1192 Nebl_flash_y += c->vex[idx].sy;
1196 // calculate the glow points
1197 nebl_calc_facing_pts_smart(&glow_a, &glow_b, &dir_normal, &a->pos, pinch_a ? 0.5f : width * 6.0f, Nebl_type->b_add);
1198 g3_rotate_vertex(&c->glow_vex[0], &glow_a);
1199 g3_project_vertex(&c->glow_vex[0]);
1200 g3_rotate_vertex(&c->glow_vex[1], &glow_b);
1201 g3_project_vertex(&c->glow_vex[1]);
1205 // rotate the basic section into world
1206 for(idx=0; idx<3; idx++){
1209 vm_vec_rotate(&pt, &Nebl_ring_pinched[idx], &m);
1211 vm_vec_copy_scale(&temp, &Nebl_ring[idx], width);
1212 vm_vec_rotate(&pt, &temp, &m);
1214 vm_vec_add2(&pt, &b->pos);
1217 g3_rotate_vertex(&cap->vex[idx], &pt);
1218 g3_project_vertex(&cap->vex[idx]);
1220 // if first frame, keep track of the average screen pos
1221 if( (c->vex[idx].sx >= 0) && (c->vex[idx].sx < gr_screen.max_w) && (c->vex[idx].sy >= 0) && (c->vex[idx].sy < gr_screen.max_h)){
1222 Nebl_flash_x += c->vex[idx].sx;
1223 Nebl_flash_y += c->vex[idx].sy;
1228 // calculate the glow points
1229 nebl_calc_facing_pts_smart(&glow_a, &glow_b, &dir_normal, &b->pos, pinch_b ? 0.5f : width * 6.0f, bi->b_add);
1230 g3_rotate_vertex(&cap->glow_vex[0], &glow_a);
1231 g3_project_vertex(&cap->glow_vex[0]);
1232 g3_rotate_vertex(&cap->glow_vex[1], &glow_b);
1233 g3_project_vertex(&cap->glow_vex[1]);
1238 void nebl_render(bolt_type *bi, l_node *whee, float width, l_section *prev)
1242 l_section child_start;
1249 // if prev is NULL, we're just starting so we need our start point
1251 SDL_assert(whee->links[LINK_RIGHT] != NULL);
1252 nebl_generate_section(bi, width, whee, whee->links[LINK_RIGHT], &start, NULL, 1, 0);
1257 // if we have a child section
1258 if(whee->links[LINK_CHILD]){
1260 nebl_generate_section(bi, width * 0.5f, whee, whee->links[LINK_CHILD], &child_start, &end, 0, whee->links[LINK_CHILD]->links[LINK_RIGHT] == NULL ? 1 : 0);
1263 nebl_render_section(bi, &child_start, &end);
1266 if(whee->links[LINK_CHILD]->links[LINK_RIGHT] != NULL){
1267 nebl_render(bi, whee->links[LINK_CHILD], width * 0.5f, &end);
1271 // if the next section is an end section
1272 if(whee->links[LINK_RIGHT]->links[LINK_RIGHT] == NULL){
1276 nebl_generate_section(bi, width, whee, whee->links[LINK_RIGHT], &temp, &end, 0, 1);
1278 // render the section
1279 nebl_render_section(bi, &start, &end);
1282 else if(whee->links[LINK_RIGHT]->links[LINK_RIGHT] != NULL){
1284 nebl_generate_section(bi, width, whee->links[LINK_RIGHT], whee->links[LINK_RIGHT]->links[LINK_RIGHT], &end, NULL, 0, 0);
1286 // render the section
1287 nebl_render_section(bi, &start, &end);
1289 // recurse through him
1290 nebl_render(bi, whee->links[LINK_RIGHT], width, &end);
1294 // given a valid, complete bolt, jitter him based upon his noise
1295 void nebl_jitter(l_bolt *b)
1301 bolt_type *bi = NULL;
1307 if((b->type < 0) || ((b->type >= Num_bolt_types) && (b->type != DEBUG_BOLT)) ){
1310 bi = &Bolt_types[(int)b->type];
1312 // get the bolt direction
1313 vm_vec_sub(&temp, &b->strike, &b->start);
1314 length = vm_vec_normalize_quick(&temp);
1315 vm_vector_2_matrix(&m, &temp, NULL, NULL);
1317 // jitter all nodes on the main trunk
1319 while(moveup != NULL){
1321 vm_vec_random_in_circle(&moveup->pos, &temp, &m, frand_range(0.0f, length * bi->noise), 0);
1323 // just on the main trunk
1324 moveup = moveup->links[LINK_RIGHT];
1328 // return the index of a given bolt type by name
1329 int nebl_get_bolt_index(char *name)
1333 for(idx=0; idx<Num_bolt_types; idx++){
1334 if(!strcmp(name, Bolt_types[idx].name)){
1342 // return the index of a given storm type by name
1343 int nebl_get_storm_index(char *name)
1347 for(idx=0; idx<Num_bolt_types; idx++){
1348 if(!strcmp(name, Storm_types[idx].name)){