INTRODUCTION
Been beavering away at this for awhile, banging head against a brick wall, finally got it going (finally!!!). Sounds corny but the old addage is true: if you persevere for long enough any unsurmountable obstacle can be overcome. I'm just glad that It actually works (seemed impossible when first thought of it).
The idea was to create a single SIMPLE function that could assist in procedural generation of gradients, lighting, animated, landscaping, etc... effects without using complicated maths like calculus or some brain numbing maths intensive algorithms (well it's a try). Essentially it's a proof of concept with basic functionality that I hope more experienced programmers can take advantage of and share back with gE community.
The technique uses parameters parsed in by the user to create a waveform with an output between -1 and 1 (or 0 and 1) that can be used externally in user createded algorithms with the help of genWave to cut down on the maths. A single code to enable multiple tasks.
DEMO-TUTORIALS
Here's a list of Demo Tutorials that will give you a feeler for what it can do:-
1. STRONGLY RECCOMMEND: genWave Viewer Manual: viewtopic.php?f=8&t=12522#p89133
A gE application that helps to visualise and test output of genWave function. TRY THIS FIRST than came back here and things will be more clear about what it actually can do and how to use it effectively (their not just pretty squiggles ).
2. Gradients: viewtopic.php?f=27&t=12524#p89138
3. Simple Procedural Landscaper / Scroller: LINK? (comming soon)
4. Orbiting Actors viewtopic.php?f=27&t=12524#p89262
5. Simple lighting effects: LINK? (comming soon
6. Simple animated effects: LINK? (comming soon)
BASIC INFORMATION
CODE USE
1. Access game editor's script editor.
2. Copy/Paste Global Code from below into script editor (ALTERNATIVE METHOD: Copy/paste code into a simple text editor and save as a .txt file than use Script Editors FILE=>LOAD option to import this text file into gE).
3. Add this imported code as: genWave
The genWave function should now be globally accessible from all other events.
GLOBAL CODE
- Code: Select all
double genWave(int wMode, int NegON, int invertY, double wStep,double wStart, double wEnd, double vShift, double wAmp1, double wFreq1, double wPhase1,double wAmp2, double wFreq2, double wPhase2,double wAmp3, double wFreq3, double wPhase3)
{
double wave1=0; // stores reference wave 1
double wave2=0; // stores reference wave 2
double wave3=0; // stores reference wave 3
double waveResult=0; // stores generated output wave
double unionAmp=0; // stores multiplier for expanding/shrinking amplitude to 1 unit.
// NOTE: in maths union can mean 1, unity, etc...
// so I've coined the term unionAmp to mean amplitude of 1 always.
// check for valid parameters and make adjustments
if((wStep==0)||(wStep<0.001))
{
wStep=0.1;
}
if(wStart<0)
{
wStart=0.0;
}
if(wEnd>360)
{
wEnd=360.0;
}
if(wAmp1==0)
{
wAmp1=0.01;
}
if(wFreq1==0)
{
wFreq1=0.01;
}
if(wAmp2==0)
{
wAmp2=0.01;
}
if(wFreq2==0)
{
wFreq2=0.01;
}
if(wAmp2==0)
{
wAmp2=0.01;
}
if(wFreq3==0)
{
wFreq3=0.01;
}
if(vShift>1)
{
vShift=1.0;
}
if(vShift<-1)
{
vShift=-1.0;
}
// continue operations if within selection range (i.e. haven't yet reached wEnd )
if((wStart+wStep)<=wEnd)
{
// calculate reference waves from parameters & store
wave1=wAmp1*sin(degtorad((wStart+wStep+((360-invertY*180)/wFreq1)+wPhase1)*wFreq1));
wave2=wAmp2*sin(degtorad((wStart+wStep+((360-invertY*180)/wFreq2)+wPhase2)*wFreq2));
wave3=wAmp3*sin(degtorad((wStart+wStep+((360-invertY*180)/wFreq3)+wPhase3)*wFreq3));
// detect arithmetic mode & generate output wave
switch(wMode)
{
case 0:
waveResult=0;
break;
case 1:
unionAmp=1/wAmp1;
waveResult=unionAmp*wave1;
break;
case 2:
unionAmp=1/wAmp2;
waveResult=unionAmp*wave2;
break;
case 3:
unionAmp=1/wAmp3;
waveResult=unionAmp*wave3;
break;
case 4:
unionAmp=1/(wAmp1+wAmp2);
waveResult=unionAmp*wave1+unionAmp*wave2;
break;
case 5:
unionAmp=1/(wAmp1+wAmp2);
waveResult=unionAmp*wave1-unionAmp*wave2;
break;
case 6:
unionAmp=1/(wAmp1+wAmp2);
waveResult=unionAmp*wave2-unionAmp*wave1;
break;
case 7:
unionAmp=1/(wAmp1+wAmp3);
waveResult=unionAmp*wave1+unionAmp*wave3;
break;
case 8:
unionAmp=1/(wAmp1+wAmp3);
waveResult=unionAmp*wave1-unionAmp*wave3;
break;
case 9:
unionAmp=1/(wAmp1+wAmp3);
waveResult=unionAmp*wave3-unionAmp*wave1;
break;
case 10:
unionAmp=1/(wAmp2+wAmp3);
waveResult=unionAmp*wave3+unionAmp*wave2;
break;
case 11:
unionAmp=1/(wAmp2+wAmp3);
waveResult=unionAmp*wave2-unionAmp*wave3;
break;
case 12:
unionAmp=1/(wAmp2+wAmp3);
waveResult=unionAmp*wave3-unionAmp*wave2;
break;
case 13:
unionAmp=1/(wAmp1+wAmp2+wAmp3);
waveResult=unionAmp*wave1+unionAmp*wave2+unionAmp*wave3;
break;
case 14:
unionAmp=1/(wAmp1+wAmp2+wAmp3);
waveResult=unionAmp*wave3+unionAmp*wave2-unionAmp*wave1;
break;
case 15:
unionAmp=1/(wAmp1+wAmp2+wAmp3);
waveResult=unionAmp*wave1+unionAmp*wave3-unionAmp*wave2;
break;
case 16:
unionAmp=1/(wAmp1+wAmp2+wAmp3);
waveResult=unionAmp*wave3-unionAmp*wave2-unionAmp*wave1;
break;
case 17:
unionAmp=1/(wAmp1+wAmp2+wAmp3);
waveResult=unionAmp*wave1+unionAmp*wave2-unionAmp*wave3;
break;
case 18:
unionAmp=1/(wAmp1+wAmp2+wAmp3);
waveResult=unionAmp*wave2-unionAmp*wave1-unionAmp*wave3;
break;
case 19:
unionAmp=1/(wAmp1+wAmp2+wAmp3);
waveResult=unionAmp*wave1-unionAmp*wave2-unionAmp*wave3;
break;
case 20:
unionAmp=1/(wAmp1+wAmp2+wAmp3);
waveResult=0-unionAmp*wave1-unionAmp*wave2-unionAmp*wave3;
break;
case 21:
unionAmp=1/(pow(wAmp1*wAmp2,0.5));
waveResult=(unionAmp*wave1)*(unionAmp*wave2);
break;
case 22:
unionAmp=1/(pow(wAmp1*wAmp3,0.5));
waveResult=(unionAmp*wave1)*(unionAmp*wave3);
break;
case 23:
unionAmp=1/(pow(wAmp2*wAmp3,0.5));
waveResult=(unionAmp*wave2)*(unionAmp*wave3);
break;
case 24:
unionAmp=1/(pow(wAmp1*wAmp2*wAmp3,0.333333));
waveResult=(unionAmp*wave1)*(unionAmp*wave2)*(unionAmp*wave3);
break;
default:
waveResult=0;
break;
}
}
// Correctly assign negatives depending on Y-axis inversion state
if ((waveResult>0)&&(NegON==0)&&(invertY==1)) // inversion on, adjust required
{
waveResult=0;
}
else
{
if ((waveResult<0)&&(NegON==0)&&(invertY==0)) //inversion off, adjustment not needed
{
waveResult=0;
}
}
// Correctly assign vertical shift depending on Y-axis inversion state
if(invertY=0)
{
waveResult+=vShift; // Y inversion off, addition of vShift required
}
else
{
waveResult-=vShift; // Y inversion on, subtraction of vShift required
}
// check for overflow (due to vShift) and clip to size (make within -1 to 1)
if(waveResult<-1) // clip values under -1
{
waveResult=-1;
}
if(waveResult>1) // clip values over +1
{
waveResult=1;
}
// output the generated waveform
return waveResult;
}