Lightning-Strike Generator.

Posted By: EvilSOB

Lightning-Strike Generator. - 07/31/09 04:18

Heres another little something Ive put together, a LIGHTING BOLT generator.

Ever needed a genuinely random, 3D lightning-strike from point A to boint B?
With variable thickness, color, and complexity? And with a cool glowing after-image? (retina-burn)
Ever wanted that "beautiful" bolt to be repeatable at a later time?

Now you can with a single function call.

Comes as a complete DEMO main.c with no necessary additional files. Plenty of included documentation.

Once again, any suggestions, questions, or instructional issues, just let me know...

[EDIT] NOW BUGFIXED FOR A7 Ver 7.82.2 !!

Code:
#include <acknex.h>
#include <default.c>
//
//
//////////////////////////////////////////////////////////////////////////////////////////
//	3D-LIGHTNING-BOLT-SPAWN	2.1															//
//	---------------------------															//
//																						//
//	Author	: EvilSOB																	//
//	Date	: 31-07-2009																//
//	Updated	: 06-04-2010	(7.82.2 bugfix)												//
//																						//
//////////////////////////////////////////////////////////////////////////////////////////
//LB_spawn(VECTOR*Start,VECTOR*Finish,Div,Branch,Depth,Size,COLOR*Core,COLOR*Flare,FlareTime,Seed)//
//--------------------------------------------------------------------------------------//
//	Parameters::																		//
//		Start	=	Start Vector of Lightning Bolt 	(sky)								//
//		Finish	=	Target Vector of Lightning Bolt	(ground)							//
//		Div		=	Number of primary "segments" in central bolt 		 (suggest 5->20)//
//		Branch	=	0.0->1.0 chance to "branch" at primary segment point.(suggest 0.4)	//
//		Depth	=	depth of complexity to calculate into branches.		 (suggest 4)	//
//		Size	=	diameter in quants of "core" bolt.	 				 (suggest 8)	//
//		Core	=	color of lightning "bolt" 				   	   (suggest 255,128,128)//
//		Flare	=	color of lightning-bolt 'afterimage'	   	   (suggest 128,  0,  0)//
//		FlareTime=	duration in seconds of 'afterimage'					 (suggest 1.5)	//
//		Seed	=	random number seed (for forcing duplicates)			 (suggest 0)	//
//																						//
//	NOTES : "Flare" = NULL or nullvector will suppress the "afterimage" generation.		//
//			"Seed"  = Zero is random, set to "any" number will generate duplicate stikes//
//			"Div"   = !Be cautious with Divisions above 20, it can be a real FPS eater!	//
//			"Depth" = !Be cautious with the depth above 3, it can be a real FPS eater!	//
//																						//
//////////////////////////////////////////////////////////////////////////////////////////
//	Example::																			//
//		LB_spawn(me.x, you.x, 15, 0.4, 4, 8, vector(255,128,128), vector(180,0,0), 0);	//
//																						//
//////////////////////////////////////////////////////////////////////////////////////////
//																						//
//
void LB_segment_fade(PARTICLE* p)	{  	p.lifespan = p.alpha -= time_step*p.skill_x; 	}
//
void LB_segment_core(PARTICLE* p)
{	vec_set(p.blue, 	you.skill3);
	set(p, BEAM|BRIGHT|TRANSLUCENT|UNLIT|CAST);
	p.alpha   = 100;
	p.size    = you.skill2;
	p.skill_x = 20;
	p.event   = LB_segment_fade;
}
//
void LB_segment_flare(PARTICLE* p)
{	vec_set(p.blue, 	you.skill6);
	set(p, BEAM|BRIGHT|TRANSLUCENT|UNLIT|CAST);
	p.alpha   = 20;
	p.size    = you.skill2*2;
	p.skill_x = 1.28/you.skill7;
	p.event   = LB_segment_fade;
}
//
void LB_divide(VECTOR* A, VECTOR* B, long Div, float noise, VECTOR** Points)
{	VECTOR *points = (VECTOR*)malloc(sizeof(VECTOR)*Div);
	if(!Points)		free(*Points);		*Points = points;
	var idx; for(idx=0; idx<Div; idx++)	
	{	vec_lerp(points[idx], A, B, (float)idx/(Div-1));
		if((idx>0)&&(idx<(Div-1)))	
		{	points[idx].x += random(noise*2)-noise;
			points[idx].y += random(noise*2)-noise;
			points[idx].z += random(noise)-noise/2;
}	}	}
//
//
void LB_spawn(VECTOR* Start, VECTOR* Finish, long Div, float Branch, long Depth, long Size, COLOR* Core, COLOR* Flare, float FlareTime, var Seed)
{	if(Div<3)	return;
	if(!Seed)	Seed = timer();	
	VECTOR A, B, C, D, tmpV, corec, flarec, *fine=0, *crude=0;	vec_zero(flarec);
	vec_set(A, Start);		vec_set(B, Finish);		vec_set(corec, Core);	
	if(Flare)	vec_set(flarec, Flare);		
	wait(1);	
	long i, cnt, seg_size = vec_dist(A,B)/Div;		random_seed(Seed);
	LB_divide(A, B, Div, vec_dist(A,B)/(Div+1), crude);
	me = ent_create(NULL, NULL, NULL);		me.skill2 = Size;		vec_set(me.skill3, corec);
	vec_set(me.skill6, flarec);				me.skill7 = FlareTime;	
	for(i=1; i<Div; i++)	
	{	LB_divide(crude[i-1],crude[i],Div/2,vec_dist(crude[i-1],crude[i])/Div/2+1,fine);
		for(cnt=1; cnt<(Div/2); cnt++)
		{	vec_set(tmpV, fine[cnt]);	vec_sub(tmpV, fine[cnt-1]);
			if(vec_length(tmpV))
				vec_scale(tmpV, vec_length(tmpV)/vec_length(tmpV));
			if(vec_length(flarec))	effect(LB_segment_flare, 1, fine[cnt-1], tmpV);
			effect(LB_segment_core, 1, fine[cnt-1], tmpV);				}	
		if((Depth>1)&&(random(1)<Branch)&&(i<(Div-1)))
		{	vec_diff(C, crude[i], crude[i-1]);
			vec_diff(D, crude[i], crude[i+1]);
			vec_lerp(tmpV, D, C, random(1)+0.35);
			vec_normalize(tmpV, random(seg_size*(Div-i))*0.6);	vec_add(tmpV,crude[i]); 
			LB_spawn(crude[i], tmpV, Div*0.6, Branch, Depth-1, Size*0.6, corec, flarec, FlareTime, Seed+random(15));
	}	}
	wait(1);	ent_remove(me);		free(crude);	free(fine);
}
//
//
//////////////////////////////////////////////////////////////////////////////////////////
//
//







//////////////////////////////////////////////////////////////////////////////////////////
//////////////////////////////////////////////////////////////////////////////////////////
//				Remaining code is for DEMO purposes only.								//
//////////////////////////////////////////////////////////////////////////////////////////
//////////////////////////////////////////////////////////////////////////////////////////
//
//
VECTOR FromPoint, ToPoint;
var strike()	{	LB_spawn(FromPoint, ToPoint, 20, 0.7, 7, 8, vector(255,128,128), vector(180,0,0), 1.5, 00);  }	
var arcing()		
{	var last_key = key_lastpressed;
	while(key_pressed(last_key))
	{		LB_spawn(FromPoint, ToPoint, 13, 0.6, 3, 13, vector(255,128,128), vector(128,0,0), 1, 0);	
			wait(-0.07);
}	}
//
//
function main()
{	max_entities = 10000;
	
	level_load(NULL);	wait(2);	diag("\n\n\n");
	vec_set(sky_color, vector(1,1,1));
	vec_set(camera.x, vector(-700,0,255));
	//
	vec_set(FromPoint, vector(0,0,500));		
	vec_set(ToPoint,   vector(0,100,0));
	on_space = strike;
	on_enter = arcing;
	//
	//
	strike();
	while(1)
	{
		draw_text(_str("Hit SPACEBAR for Lightning Strike!"), 10, 10, NULL);
		draw_text(_str("Hold ENTER for an Elecrical Arc!"),   10, 30, NULL);
		draw_point3d(FromPoint,  vector(255,200,200), 100, 10);
		draw_point3d(ToPoint,    vector(255,200,200), 100, 10);

		wait(1);
	}
	//
	sys_exit("");
}




For historical purposes, here is Version 2.0. Its the same as 2.1, just doesnt allow control over the color of the after-image 'flare'.
Click to reveal..
Code:
#include <acknex.h>
#include <default.c>
//
//
//////////////////////////////////////////////////////////////////////////////////////////
//	3D-LIGHTNING-BOLT-SPAWN	2.0															//
//	---------------------------															//
//																						//
//	Author	: EvilSOB																	//
//	Date	: 31-07-2009																//
//	Updated	: 06-04-2010	(7.82.2 bugfix)												//
//																						//
//////////////////////////////////////////////////////////////////////////////////////////
//LB_spawn(VECTOR*Start,VECTOR*Finish,Div,Branch,Depth,Size,COLOR*Core,COLOR*Flare,Seed)//
//--------------------------------------------------------------------------------------//
//	Parameters::																		//
//		Start	=	Start Vector of Lightning Bolt 	(sky)								//
//		Finish	=	Target Vector of Lightning Bolt	(ground)							//
//		Div		=	Number of primary "segments" in central bolt 		 (suggest 5->20)//
//		Branch	=	0.0->1.0 chance to "branch" at primary segment point.(suggest 0.4)	//
//		Depth	=	depth of complexity to calculate into branches.		 (suggest 4)	//
//		Size	=	diameter in quants of "core" bolt.	 				 (suggest 8)	//
//		Core	=	color of lightning "bolt" 				   	   (suggest 255,128,128)//
//		Flare	=	color of lightning-bolt 'afterimage'	   	   (suggest 128,  0,  0)//
//		Seed	=	random number seed (for forcing duplicates)			 (suggest 0)	//
//																						//
//	NOTES : "Flare" = NULL or nullvector will suppress the "afterimage" generation.		//
//			"Seed"  = Zero is random, set to "any" number will generate duplicate stikes//
//			"Div"   = !Be cautious with Divisions above 20, it can be a real FPS eater!	//
//			"Depth" = !Be cautious with the depth above 3, it can be a real FPS eater!	//
//																						//
//////////////////////////////////////////////////////////////////////////////////////////
//	Example::																			//
//		LB_spawn(me.x, you.x, 15, 0.4, 4, 8, vector(255,128,128), vector(180,0,0), 0);	//
//																						//
//////////////////////////////////////////////////////////////////////////////////////////
//																						//
//
void LB_segment_fade(PARTICLE* p)	{  	p.lifespan = p.alpha -= time_step*p.skill_x;	}
//
void LB_segment_core(PARTICLE* p)
{	vec_set(p.blue, 	you.skill3);
	set(p, BEAM|BRIGHT|TRANSLUCENT|UNLIT|CAST);
	p.alpha   = 100;
	p.size    = you.skill2;
	p.skill_x = 20;
	p.event   = LB_segment_fade;
}
//
void LB_segment_flare(PARTICLE* p)
{	vec_set(p.blue, 	you.skill6);
	set(p, BEAM|BRIGHT|TRANSLUCENT|UNLIT|CAST);
	p.alpha   = 20;
	p.size    = you.skill2*2;
	p.skill_x = 1;
	p.event   = LB_segment_fade;
}
//
void LB_divide(VECTOR* A, VECTOR* B, long Div, float noise, VECTOR** Points)
{	VECTOR *points = (VECTOR*)malloc(sizeof(VECTOR)*Div);
	if(!Points)		free(*Points);		*Points = points;
	var idx; for(idx=0; idx<Div; idx++)	
	{	vec_lerp(points[idx], A, B, (float)idx/(Div-1));
		if((idx>0)&&(idx<(Div-1)))	
		{	points[idx].x += random(noise*2)-noise;
			points[idx].y += random(noise*2)-noise;
			points[idx].z += random(noise)-noise/2;
}	}	}
//
//
void LB_spawn(VECTOR* Start, VECTOR* Finish, long Div, float Branch, long Depth, long Size, COLOR* Core, COLOR* Flare, var Seed)
{	if(Div<3)	return;
	if(!Seed)	Seed = timer();	
	VECTOR A, B, C, D, tmpV, corec, flarec, *fine=0, *crude=0;	vec_zero(flarec);
	vec_set(A, Start);		vec_set(B, Finish);		vec_set(corec, Core);	
	if(Flare)	vec_set(flarec, Flare);
	wait(1);	
	long i, cnt, seg_size = vec_dist(A,B)/Div;		random_seed(Seed);
	LB_divide(A, B, Div, vec_dist(A,B)/(Div+1), crude);
	me = ent_create(NULL, NULL, NULL);		me.skill2 = Size;
	vec_set(me.skill3, corec);				vec_set(me.skill6, flarec);
	for(i=1; i<Div; i++)	
	{	LB_divide(crude[i-1],crude[i],Div/2,vec_dist(crude[i-1],crude[i])/Div/2+1,fine);
		for(cnt=1; cnt<(Div/2); cnt++)
		{	vec_set(tmpV, fine[cnt]);	vec_sub(tmpV, fine[cnt-1]);
			if(vec_length(tmpV))
				vec_scale(tmpV, vec_length(tmpV)/vec_length(tmpV));
			if(vec_length(flarec))	effect(LB_segment_flare, 1, fine[cnt-1], tmpV);
			effect(LB_segment_core, 1, fine[cnt-1], tmpV);				}	
		if((Depth>1)&&(random(1)<Branch)&&(i<(Div-1)))
		{	vec_diff(C, crude[i], crude[i-1]);
			vec_diff(D, crude[i], crude[i+1]);
			vec_lerp(tmpV, D, C, random(1)+0.35);
			vec_normalize(tmpV, random(seg_size*(Div-i))*0.6);	vec_add(tmpV,crude[i]); 
			LB_spawn(crude[i], tmpV,Div*0.6,Branch,Depth-1,Size*0.6, corec, flarec, Seed+random(15));
	}	}
	wait(1);	ent_remove(me);		free(crude);	free(fine);
}
//
//
//////////////////////////////////////////////////////////////////////////////////////////
//
//







//////////////////////////////////////////////////////////////////////////////////////////
//////////////////////////////////////////////////////////////////////////////////////////
//				Remaining code is for DEMO purposes only.								//
//////////////////////////////////////////////////////////////////////////////////////////
//////////////////////////////////////////////////////////////////////////////////////////
//
//
VECTOR FromPoint, ToPoint;
var strike()	{	LB_spawn(FromPoint, ToPoint, 20, 0.4, 5, 8, vector(255,128,128), vector(180,0,0), 0);	}	
var arcing()		
{	var last_key = key_lastpressed;
	while(key_pressed(last_key))
	{		LB_spawn(FromPoint, ToPoint, 10, 0.4, 2, 10, vector(255,128,128), vector(180,0,0), 0);	
			wait(-0.07);
}	}
//
//
function main()
{
	warn_level = 6;

	level_load(NULL);	wait(2);	diag("\n\n\n");
	vec_set(sky_color, vector(1,1,1));
	vec_set(camera.x, vector(-700,0,255));
	//
	vec_set(FromPoint, vector(0,0,500));		
	vec_set(ToPoint,   vector(0,100,0));
	on_space = strike;
	on_1 = arcing;

	//
	//
	strike();
	while(1)
	{
		draw_text(_str("Hit SPACEBAR for Lightning Strike!"), 10, 10, NULL);
		draw_point3d(FromPoint,  vector(255,200,200), 100, 10);
		draw_point3d(ToPoint,    vector(255,200,200), 100, 10);
		wait(1);
	}
	//
	sys_exit("");
}




Also historical purposes, here is Ye-Olde Version 1.0. Much simpler code.
Its basically the same as 2.0, but doesnt allow ANY control over the after-image 'flare'.
Click to reveal..
Code:
#include <acknex.h>
#include <default.c>
//
//
//////////////////////////////////////////////////////////////////////////////////////////
//	3D-LIGHTNING-BOLT-SPAWN	1.0															//
//	---------------------------															//
//																						//
//	Author	: EvilSOB																	//
//	Date	: 25-07-2009																//
//																						//
//////////////////////////////////////////////////////////////////////////////////////////
//LB_spawn(VECTOR* start, VECTOR* finish, long Div, float branch, long depth, long size)//
//--------------------------------------------------------------------------------------//
//	Parameters::																		//
//		start	=	Start Vector of Lightning Bolt 	(sky)								//
//		finish	=	Target Vector of Lightning Bolt	(ground)							//
//		Div		=	Number of primary "segments" in central bolt 		  (suggest 20)	//
//		branch	=	0.0->1.0 chance to "branch" at primary segment point. (suggest 0.4)	//
//		depth	=	depth of complexity to calculate into branches.		  (suggest 4)	//
//		size	=	diameter in quants of "core" bolt.(2^depth minimum)	  (suggest 8)	//
//																						//
//////////////////////////////////////////////////////////////////////////////////////////
//	Example::																			//
//		LB_spawn(start, finish, 20, 0.4, 4, 8);											//
//																						//
//////////////////////////////////////////////////////////////////////////////////////////
//																						//
void LB_segment_fade(PARTICLE* p)
{  	p.alpha -= 20 * p.skill_a * time_step;
    if (p.alpha <= 0)	p.lifespan = 0;
}
//
void LB_segment_flare(PARTICLE* p)
{	vec_set(p.blue, vector(128,0,0));
	set(p, BEAM|BRIGHT|TRANSLUCENT|UNLIT|CAST);
	p.alpha = 50;
	p.size = (long)you*3;
	p.skill_a = 0.3;
	p.event = LB_segment_fade;
}
//
void LB_segment_core(PARTICLE* p)
{	vec_set(p.blue, vector(255,128,128));
	set(p, BEAM|BRIGHT|TRANSLUCENT|UNLIT|CAST);
	p.alpha = 100;
	p.size = (long)you;
	p.skill_a = 1.5;
	p.event = LB_segment_fade;
}
//
void LB_draw_segment(VECTOR *start, VECTOR *finish, long size)
{	me = size;
	VECTOR tmpV;	vec_set(tmpV, finish);	vec_sub(tmpV,start);
	effect(LB_segment_core,  5, start, tmpV);
	effect(LB_segment_flare, 1, start, tmpV);
	me = size;
}
//
//
void LB_randomize(VECTOR* point, float noise)
{
	point.x += random(noise*2)-noise;
	point.y += random(noise*2)-noise;
	point.z += random(noise)-noise/2;
}
//
void LB_subdivide(VECTOR* A, VECTOR* B, long Div, float noise, VECTOR** Points)
{	VECTOR *points = (VECTOR*)malloc(sizeof(VECTOR)*Div);
	if(!Points)		free(*Points);		*Points = points;
	var idx; for(idx=0; idx<Div; idx++)	
	{	vec_lerp(points[idx], A, B, (float)idx/(Div-1));
		if((idx>0)&&(idx<(Div-1)))	LB_randomize(points[idx], noise);
	}
}
//
void LB_spawn(VECTOR* start,VECTOR* finish,long Div,float branch,long depth,long size)
{	VECTOR A, B;	vec_set(A, start);	vec_set(B, finish);		wait(1);
	long i, cnt, seg_size=vec_dist(A,B)/Div;
	VECTOR *fine=0, 	*crude=0;	LB_subdivide(A, B, Div, vec_dist(A,B)/(Div+1), crude);
	for(i=1; i<Div; i++)	
	{	LB_subdivide(crude[i-1],crude[i],Div/2,vec_dist(crude[i-1],crude[i])/Div/2+1,fine);
		for(cnt=1; cnt<(Div/2); cnt++)	LB_draw_segment(fine[cnt-1], fine[cnt], size);
		if((depth>1)&&(random(1)<branch))
		{	VECTOR tmpV;	vec_set(tmpV,crude[i]);	  LB_randomize(tmpV, vec_dist(A,B)/5);
			LB_spawn(crude[i-1], tmpV, Div/2, branch, depth-1, size/2);
	}	}
	free(crude);	free(fine);	
}
//////////////////////////////////////////////////////////////////////////////////////////
//
//
VECTOR start, finish;
void strike()	{	LB_spawn(start, finish, 20, 0.4, 4, 8);		}
//
//
function main()
{
	level_load(NULL);	wait(2);	diag("\n\n\n");
	vec_set(sky_color, vector(1,1,1));
	vec_set(camera.x, vector(-700,0,255));
	//
	on_space = strike;
	//
	vec_set(start, vector(0,0,500));		
	vec_set(finish, vector(0,100,0));
	LB_spawn(start, finish, 20, 0.4, 4, 8);	
	//
	while(1)
	{
		draw_point3d(start,  vector(255,200,200), 100, 10);
		draw_point3d(finish, vector(255,200,200), 100, 10);
		wait(1);
	}
}



Posted By: boyax

Re: Lightning-Strike Generator. - 07/31/09 04:55

This is so cool. grin Thanks.
Posted By: the_mehmaster

Re: Lightning-Strike Generator. - 07/31/09 06:47

Truly wonderful work EvilSOB. You never cease to amaze mesmile
Posted By: Germanunkol

Re: Lightning-Strike Generator. - 07/31/09 08:15

600 particles is a little too much for my needs. Other than that, this rocks. very well done.
So you solved the jagged-particle-ends issue?
Posted By: EvilSOB

Re: Lightning-Strike Generator. - 07/31/09 08:31

Germanunkol :: couldnt fix it(not without doubling the particle count with minimal visual improvement).
But I havent given up, but not trying very hard anymore.
You will never LIKELY have the lightning "fat" enough to notice anyway. (its never displayed for long)

Note, the particle count is pretty heavily dependant in the DIV value (sub-divisions per bolt),
and it is EXTREMELY dependant on the DEPTH value (number of branches "deep" to calculate).
Play with those two values and you WILL be able to bring the count right down as low as you want.
But the lower you go, the less "realistic" it gets.
If you want it for just "electrical" sparks like electrical arcing, go with a Depth of 1, a Div of 8, but spawn multiple bolts.
[EDIT] To see what I mean, try adding this function and triggering it with an "on_key" statement in main.
Its a passable electrial arc but by tweaking its settings could achieve your desired results...
Click to reveal..
Code:
var arcing()		
{	var last_key = key_lastpressed;
	while(key_pressed(last_key))
	{		LB_spawn(FromPoint, ToPoint, 8, 0.4, 1, 5, vector(255,128,128), vector(180,0,0), 0);	
			wait(-0.02);
}	}



Im inclined to think that DEPTH should be "calculated" based on current FPS,
and the DIV value should be based in the GPU-quality divided-by number-of-bolts-visible-at-once.
But thats up to the end programmer to implement.
Posted By: Germanunkol

Re: Lightning-Strike Generator. - 08/01/09 06:59

As this in contributions, I take it it's for free?
I'll give credits, of course, but if it's all right I'll replace my lightning-gun effect with your lightning-strike effect, after tweaking it a little for my needs.
It totally rocks. It looks less realistic now, of course, but I don't need a realistic lightning strike, I need a cool effect laugh
Posted By: EvilSOB

Re: Lightning-Strike Generator. - 08/01/09 07:13

Credit is all I ask for... Honing my skills is the real payment.

And I would be interested in YOUR finished effect.
Not the actual code, just as in what "tweaks" did/will you make and why?
(just in case I am leaving out a useful capability.
If there is enough missing, I may try to put together an "Electric Bolt" function
that is tailored more to "weapon" effects, rather than "weather" effects as it is now.)


I HAVE been having 'background' thoughts of a single-bolt effect that is animated...
Any ideas/suggestions requests ANYONE?
Posted By: Germanunkol

Re: Lightning-Strike Generator. - 08/01/09 07:52

after playing with your code for a few minutes, I think I know the sort of tweaks I'll make: as I may have really long (and many) lightning 'shots' visible at the same time and still want them detaild, I'm going to use your code the way it was and make screenshots of it. those screens I'll edit (rotate/scale) and save as tga files. about 4 should be enough. then i'll use your code again and change just the particles to use these images, in combo with the streak flag instead of beam. So what I'm using from your code is the afterglow (awesome idea), the positioning of the particles (how you make them go from point a to point b exactly) and the look of the effect by generating the bmaps from it. I'll see how it works out.

I may post screens later, depending on how it looks.
Again, thanks a lot for letting me use this. You were already in the list of people I'd have given a "thanks to:" place (placement? placing?) in the credits, because you helped me with quite a few pieces of code before, now you've gotten a special place on those credits smile
Posted By: EvilSOB

Re: Lightning-Strike Generator. - 08/01/09 08:25

My thanks kind sir.
If you need any help with the tweaking, just PM me. I'll be glad to help.

Couple of hints straight up ::
1> Make use of the "seed" value when you are 'choosing' your bolt pattern. If you like the shape,
it will keep that shape and you can play with the Size and Depth to get a better look.
2> When Photoshopping the results, I suggest to try the "blur" options to get rid of the "jaggies" around joints.
Posted By: Germanunkol

Re: Lightning-Strike Generator. - 08/01/09 08:38

Hm. I should've read those suggestions before I worked on it... both would have helped me.
Anyways, here's a temporary result. Note the number of particles:
http://www4.picfront.org/picture/Ehamfp2if/img/screeniee.jpg
Posted By: EvilSOB

Re: Lightning-Strike Generator. - 08/01/09 10:58

Looks great, and uses random bmap's as particles right?
But MY aim was to aviod using any external files.
It was more a mental exercise than enything.

Still, everyone has different needs. And youve used mine to achieve yours.
Well done.

Just curious...
How many different bmaps are in the random list?
Have you tried letting a few of them have branches? What did it look like?
Posted By: JXT

Re: Lightning-Strike Generator. - 04/03/10 19:36

Hi everyone ^^

I just wanted to use this generator... but it doesn't work frown

I tried you "test"-code and it doesn't work, too...

Please help me...
Posted By: Razoron

Re: Lightning-Strike Generator. - 04/04/10 13:09

Yes, he is right, it doesn't work anymore. I remember it worked. I think it was 7.77. Why doesn't this work at the moment.
Posted By: JXT

Re: Lightning-Strike Generator. - 04/04/10 14:21

So it doesn't work if using 7.8?
Shit...
Posted By: EvilSOB

Re: Lightning-Strike Generator. - 04/04/10 14:49

Hmm, it seems it hasnt worked only since 7.82
Im looking into this now.
Posted By: EvilSOB

Re: Lightning-Strike Generator. - 04/04/10 15:41

OK, this could take a while, cause its no longer up to me.
This is being caused either by a new engine bug, or an old "undocumented feature" I was using, and has been repaired.
I am using dummy entities to pass data to the particles, but its stopped working for some reason, and Im going to
chase this up in the "Bugs" forum.

For the time being, here is an older version. Its not quite as powerful, or as "pretty" but it does still work in newer engine versions.
Click to reveal..
Code:
#include <acknex.h>
#include <default.c>
//
//
//////////////////////////////////////////////////////////////////////////////////////////
//	3D-LIGHTNING-BOLT-SPAWN																//
//	-----------------------																//
//																						//
//	Author	: EvilSOB																	//
//	Date	: 25-07-2009																//
//																						//
//////////////////////////////////////////////////////////////////////////////////////////
//LB_spawn(VECTOR* start, VECTOR* finish, long Div, float branch, long depth, long size)//
//--------------------------------------------------------------------------------------//
//	Parameters::																		//
//		start	=	Start Vector of Lightning Bolt 	(sky)								//
//		finish	=	Target Vector of Lightning Bolt	(ground)							//
//		Div		=	Number of primary "segments" in central bolt 		  (suggest 20)	//
//		branch	=	0.0->1.0 chance to "branch" at primary segment point. (suggest 0.4)	//
//		depth	=	depth of complexity to calculate into branches.		  (suggest 4)	//
//		size	=	diameter in quants of "core" bolt.(2^depth minimum)	  (suggest 8)	//
//																						//
//////////////////////////////////////////////////////////////////////////////////////////
//	Example::																			//
//		LB_spawn(start, finish, 20, 0.4, 4, 8);											//
//																						//
//////////////////////////////////////////////////////////////////////////////////////////
//																						//
void LB_segment_fade(PARTICLE* p)
{  	p.alpha -= 20 * p.skill_a * time_step;
    if (p.alpha <= 0)	p.lifespan = 0;
}
//
void LB_segment_flare(PARTICLE* p)
{	vec_set(p.blue, vector(128,0,0));
	set(p, BEAM|BRIGHT|TRANSLUCENT|UNLIT|CAST);
	p.alpha = 50;
	p.size = (long)you*3;
	p.skill_a = 0.3;
	p.event = LB_segment_fade;
}
//
void LB_segment_core(PARTICLE* p)
{	vec_set(p.blue, vector(255,128,128));
	set(p, BEAM|BRIGHT|TRANSLUCENT|UNLIT|CAST);
	p.alpha = 100;
	p.size = (long)you;
	p.skill_a = 1.5;
	p.event = LB_segment_fade;
}
//
void LB_draw_segment(VECTOR *start, VECTOR *finish, long size)
{	me = size;
	VECTOR tmpV;	vec_set(tmpV, finish);	vec_sub(tmpV,start);
	effect(LB_segment_core,  5, start, tmpV);
	effect(LB_segment_flare, 1, start, tmpV);
	me = size;
}
//
//
void LB_randomize(VECTOR* point, float noise)
{
	point.x += random(noise*2)-noise;
	point.y += random(noise*2)-noise;
	point.z += random(noise)-noise/2;
}
//
void LB_subdivide(VECTOR* A, VECTOR* B, long Div, float noise, VECTOR** Points)
{	VECTOR *points = (VECTOR*)malloc(sizeof(VECTOR)*Div);
	if(!Points)		free(*Points);		*Points = points;
	var idx; for(idx=0; idx<Div; idx++)	
	{	vec_lerp(points[idx], A, B, (float)idx/(Div-1));
		if((idx>0)&&(idx<(Div-1)))	LB_randomize(points[idx], noise);
	}
}
//
void LB_spawn(VECTOR* start,VECTOR* finish,long Div,float branch,long depth,long size)
{	VECTOR A, B;	vec_set(A, start);	vec_set(B, finish);		wait(1);
	long i, cnt, seg_size=vec_dist(A,B)/Div;
	VECTOR *fine=0, 	*crude=0;	LB_subdivide(A, B, Div, vec_dist(A,B)/(Div+1), crude);
	for(i=1; i<Div; i++)	
	{	LB_subdivide(crude[i-1],crude[i],Div/2,vec_dist(crude[i-1],crude[i])/Div/2+1,fine);
		for(cnt=1; cnt<(Div/2); cnt++)	LB_draw_segment(fine[cnt-1], fine[cnt], size);
		if((depth>1)&&(random(1)<branch))
		{	VECTOR tmpV;	vec_set(tmpV,crude[i]);	  LB_randomize(tmpV, vec_dist(A,B)/5);
			LB_spawn(crude[i-1], tmpV, Div/2, branch, depth-1, size/2);
	}	}
	free(crude);	free(fine);	
}
//////////////////////////////////////////////////////////////////////////////////////////
//
//
VECTOR start, finish;
void strike()	{	LB_spawn(start, finish, 20, 0.4, 4, 8);		}
//
//
function main()
{
	level_load(NULL);	wait(2);	diag("\n\n\n");
	vec_set(sky_color, vector(1,1,1));
	vec_set(camera.x, vector(-700,0,255));
	//
	on_space = strike;
	//
	vec_set(start, vector(0,0,500));		
	vec_set(finish, vector(0,100,0));
	LB_spawn(start, finish, 20, 0.4, 4, 8);	
	//
	while(1)
	{
		draw_point3d(start,  vector(255,200,200), 100, 10);
		draw_point3d(finish, vector(255,200,200), 100, 10);
		wait(1);
	}
}


Posted By: JXT

Re: Lightning-Strike Generator. - 04/04/10 16:49

Thank you laugh
Has to work anyhow ^^

€: even it's an older version, it's AWESOME!!! Thank you EvilSOB grin
Posted By: mikaldinho

Re: Lightning-Strike Generator. - 04/05/10 13:10

this should be in AUM92!

anyway, thanks EvilSOB!
Posted By: EvilSOB

Re: Lightning-Strike Generator. - 04/05/10 14:59

OK, Ive found the problem, and it wasnt an engine bug, it was a timing bug in my code.
It appears (in MY opinion) the A7 7.82.2 is "cleaner" when removing entities, where there
was a (behind the scenes) one-frame lag between the execution of an ent_remove
and the actual memory getting flushed and re-used.
Now there is no longer that lag, it highlighted my timing problem.

So here is the fix. Just replace the old LB_spawn (from Version 2.0) with this.
Code:
//
void LB_spawn(VECTOR* Start, VECTOR* Finish, long Div, float Branch, long Depth, long Size, COLOR* Core, COLOR* Flare, var Seed)
{	if(Div<3)	return;
	if(!Seed)	Seed = timer();	
	VECTOR A, B, C, D, tmpV, corec, flarec, *fine=0, *crude=0;	vec_zero(flarec);
	vec_set(A, Start);		vec_set(B, Finish);		vec_set(corec, Core);	
	if(Flare)	vec_set(flarec, Flare);
	wait(1);	
	long i, cnt, seg_size = vec_dist(A,B)/Div;		random_seed(Seed);
	LB_divide(A, B, Div, vec_dist(A,B)/(Div+1), crude);
	me = ent_create(NULL, NULL, NULL);		me.skill2 = Size;
	vec_set(me.skill3, corec);				vec_set(me.skill6, flarec);
	for(i=1; i<Div; i++)	
	{	LB_divide(crude[i-1],crude[i],Div/2,vec_dist(crude[i-1],crude[i])/Div/2+1,fine);
		for(cnt=1; cnt<(Div/2); cnt++)
		{	vec_set(tmpV, fine[cnt]);	vec_sub(tmpV, fine[cnt-1]);
			if(vec_length(tmpV))
				vec_scale(tmpV, vec_length(tmpV)/vec_length(tmpV));
			if(vec_length(flarec))	effect(LB_segment_flare, 1, fine[cnt-1], tmpV);
			effect(LB_segment_core, 1, fine[cnt-1], tmpV);				}	
		if((Depth>1)&&(random(1)<Branch)&&(i<(Div-1)))
		{	vec_diff(C, crude[i], crude[i-1]);
			vec_diff(D, crude[i], crude[i+1]);
			vec_lerp(tmpV, D, C, random(1)+0.35);
			vec_normalize(tmpV, random(seg_size*(Div-i))*0.6);	vec_add(tmpV,crude[i]); 
			LB_spawn(crude[i], tmpV,Div*0.6,Branch,Depth-1,Size*0.6, corec, flarec, Seed+random(15));
	}	}
	wait(1);	ent_remove(me);		free(crude);	free(fine);
}
//



Sorry guys. My bad.

{EDIT] This code has also been fixed in Ver 2.0 and Ver 2.1 in the top post of this thread.
Posted By: JXT

Re: Lightning-Strike Generator. - 04/05/10 15:03

Thanks grin
Posted By: EvilSOB

Re: Lightning-Strike Generator. - 04/05/10 15:14

Slightly-new version also available in the initial post of this thread. 2.1 !

Does the same as the last, but now the timing of the after-image flare is controllable.
Posted By: mikaldinho

Re: Lightning-Strike Generator. - 04/05/10 15:46

thanks m8 for the bug free version!
Posted By: PrenceOfDarkness

Re: Lightning-Strike Generator. - 04/22/10 03:43

...
...
...
-_-'
...

idk what to say... I LOVE YOU! o_O'

I've been craving for this for such a long time... AND YOU MADE IT SOOOOOOO CUSTOMIZABLE....

thank you, thank you, thank you!
© 2024 lite-C Forums