00001
00002
00003
00004
00005
00006
00007
00008
00009
00010
00011
00012
00013
00014
00015
00016
00017
00018
00019
00020
00021
00022 #include <windows.h>
00023 #include <math.h>
00024 #include <assert.h>
00025
00026 #include "genesis.h"
00027 #include "ErrorLog.h"
00028
00029 #include "Electric.h"
00030 #include "ram.h"
00031
00032 static int logBase2(int n)
00033 {
00034 int i = 0;
00035
00036 assert(n != 0);
00037
00038 while (!(n & 1))
00039 {
00040 n = n >> 1;
00041 i++;
00042 }
00043
00044 assert((n & ~1) == 0);
00045
00046 return i;
00047 }
00048
00049 static geBoolean IsPowerOf2(int n)
00050 {
00051 if (n == 0)
00052 return GE_TRUE;
00053
00054 while (!(n & 1))
00055 n = n >> 1;
00056
00057 if (n & ~1)
00058 return GE_FALSE;
00059
00060 return GE_TRUE;
00061 }
00062
00063 _Electric_BoltEffect * _Electric_BoltEffectCreate(
00064 int NumPolys,
00065 int Width,
00066 geFloat Wildness)
00067 {
00068 _Electric_BoltEffect * be;
00069 GE_RGBA color;
00070
00071 assert(Wildness >= 0.0f && Wildness <= 1.0f);
00072
00073
00074 logBase2(NumPolys);
00075
00076 be = (_Electric_BoltEffect *)geRam_Allocate(sizeof(*be));
00077 if (!be)
00078 return be;
00079
00080 memset(be, 0, sizeof(*be));
00081
00082 be->beCenterPoints = (geVec3d *)geRam_Allocate(sizeof(*be->beCenterPoints) * (NumPolys + 1));
00083 if (!be->beCenterPoints)
00084 goto fail;
00085
00086 be->beNumPoints = NumPolys;
00087 be->beWildness = Wildness;
00088 be->beWidth = Width;
00089
00090 color.r = 160.0f;
00091 color.g = 160.0f;
00092 color.b = 255.0f;
00093 _Electric_BoltEffectSetColorInfo(be, &color, ELECTRIC_BOLT_BLUEDOMINANT);
00094
00095 return be;
00096
00097 fail:
00098 if (be->beCenterPoints)
00099 geRam_Free(be->beCenterPoints);
00100 if (be)
00101 geRam_Free(be);
00102
00103 return NULL;
00104 }
00105
00106 void _Electric_BoltEffectDestroy(_Electric_BoltEffect *Effect)
00107 {
00108 geRam_Free(Effect->beCenterPoints);
00109 geRam_Free(Effect);
00110 }
00111
00112 static geFloat GaussRand(void)
00113 {
00114 int i;
00115 int r;
00116
00117 r = 0;
00118
00119 for (i = 0; i < 6; i++)
00120 r = r + rand() - rand();
00121
00122 return (geFloat)r / ((geFloat)RAND_MAX * 6.0f);
00123 }
00124
00125 static void subdivide(
00126 _Electric_BoltEffect * be,
00127 const geVec3d * start,
00128 const geVec3d * end,
00129 geFloat s,
00130 int n)
00131 {
00132 geVec3d tmp;
00133
00134 if (n == 0)
00135 {
00136 be->beCurrentPoint++;
00137 *be->beCurrentPoint = *end;
00138 return;
00139 }
00140
00141 tmp.X = (end->X + start->X) / 2 + s * GaussRand();
00142 tmp.Y = (end->Y + start->Y) / 2 + s * GaussRand();
00143 tmp.Z = (end->Z + start->Z) / 2 + s * GaussRand();
00144 subdivide(be, start, &tmp, s / 2, n - 1);
00145 subdivide(be, &tmp, end, s / 2, n - 1);
00146 }
00147
00148 #define LIGHTNINGWIDTH 8.0f
00149
00150 static void genLightning(
00151 _Electric_BoltEffect * be,
00152 int RangeLow,
00153 int RangeHigh,
00154 const geVec3d * start,
00155 const geVec3d * end)
00156 {
00157 geFloat length;
00158 int seed;
00159
00160 assert(be);
00161 assert(start);
00162 assert(end);
00163 assert(RangeHigh > RangeLow);
00164 assert(IsPowerOf2(RangeHigh - RangeLow));
00165
00166
00167 length = (geFloat)(fabs(start->X - end->X) +
00168 fabs(start->Y - end->Y) +
00169 fabs(start->Z - end->Z));
00170
00171 seed = rand();
00172
00173 srand(seed);
00174 be->beCurrentPoint = be->beCenterPoints + RangeLow;
00175 be->beCenterPoints[RangeLow] = *start;
00176 be->beCenterPoints[RangeHigh] = *end;
00177 subdivide(be, start, end, length * be->beWildness, logBase2(RangeHigh - RangeLow));
00178 }
00179
00180 void _Electric_BoltEffectSetColorInfo(
00181 _Electric_BoltEffect * Effect,
00182 GE_RGBA * BaseColor,
00183 int DominantColor)
00184 {
00185 Effect->beBaseColors[0] = BaseColor->r;
00186 Effect->beBaseColors[1] = BaseColor->g;
00187 Effect->beBaseColors[2] = BaseColor->b;
00188 Effect->beCurrentColors[0] = BaseColor->r;
00189 Effect->beCurrentColors[1] = BaseColor->g;
00190 Effect->beCurrentColors[2] = BaseColor->b;
00191 Effect->beDominantColor = DominantColor;
00192 }
00193
00194 void _Electric_BoltEffectAnimate(
00195 _Electric_BoltEffect * Effect,
00196 const geVec3d * start,
00197 const geVec3d * end)
00198 {
00199 int dominant;
00200 int nonDominant1;
00201 int nonDominant2;
00202 geVec3d SubdivideStart;
00203 geVec3d SubdivideEnd;
00204 int LowIndex;
00205 int HighIndex;
00206
00207 Effect->beStart = *start;
00208 Effect->beEnd = *end;
00209
00210 dominant = Effect->beDominantColor;
00211 nonDominant1 = (dominant + 1) % 3;
00212 nonDominant2 = (dominant + 2) % 3;
00213 if (Effect->beBaseColors[nonDominant1] == Effect->beCurrentColors[nonDominant1])
00214 {
00215 int DecayRate;
00216 int Spike;
00217
00218 DecayRate = rand() % (int)(Effect->beBaseColors[dominant] - Effect->beBaseColors[nonDominant1]);
00219 DecayRate = max(DecayRate, 5);
00220 Effect->beDecayRate = DecayRate;
00221 if (Effect->beBaseColors[nonDominant1] >= 1.0f)
00222 Spike = rand() % (int)(Effect->beBaseColors[nonDominant1]);
00223 else
00224 Spike = 0;
00225 Effect->beCurrentColors[nonDominant1] -= Spike;
00226 Effect->beCurrentColors[nonDominant2] -= Spike;
00227 }
00228 else
00229 {
00230 Effect->beCurrentColors[nonDominant1] += Effect->beDecayRate;
00231 Effect->beCurrentColors[nonDominant2] += Effect->beDecayRate;
00232 if (Effect->beCurrentColors[nonDominant1] > Effect->beBaseColors[nonDominant1])
00233 {
00234 Effect->beCurrentColors[nonDominant1] = Effect->beBaseColors[nonDominant1];
00235 Effect->beCurrentColors[nonDominant2] = Effect->beBaseColors[nonDominant2];
00236 }
00237 }
00238
00239 Effect->beInitialized = 1;
00240 LowIndex = 0;
00241 HighIndex = Effect->beNumPoints;
00242 SubdivideStart = *start;
00243 SubdivideEnd = *end;
00244
00245 genLightning(Effect, LowIndex, HighIndex, &SubdivideStart, &SubdivideEnd);
00246 }
00247
00248
00249 #define LIGHTNINGALPHA 220.0f
00250
00251 void _Electric_BoltEffectRender(
00252 geWorld * World,
00253 _Electric_BoltEffect * be,
00254 const geXForm3d * XForm)
00255 {
00256 geVec3d perp;
00257 geVec3d temp;
00258 geVec3d in;
00259 GE_LVertex verts[4];
00260 int i;
00261
00262 geVec3d_Subtract(&be->beStart, &be->beEnd, &temp);
00263 geXForm3d_GetIn(XForm, &in);
00264
00265 geVec3d_CrossProduct(&in, &temp, &perp);
00266 geVec3d_Normalize(&perp);
00267
00268 geVec3d_Scale(&perp, be->beWidth / 2.0f, &perp);
00269
00270
00271
00272
00273
00274
00275
00276 for (i = 0; i < be->beNumPoints - 1; i++)
00277 {
00278 geVec3d temp;
00279
00280 geVec3d_Subtract(&be->beCenterPoints[i], &perp, &temp);
00281 verts[0].X = temp.X;
00282 verts[0].Y = temp.Y;
00283 verts[0].Z = temp.Z;
00284 verts[0].u = 0.0f;
00285 verts[0].v = 0.0f;
00286 verts[0].r = be->beCurrentColors[0];
00287 verts[0].g = be->beCurrentColors[1];
00288 verts[0].b = be->beCurrentColors[2];
00289 verts[0].a = LIGHTNINGALPHA;
00290
00291 geVec3d_Subtract(&be->beCenterPoints[i + 1], &perp, &temp);
00292 verts[1].X = temp.X;
00293 verts[1].Y = temp.Y;
00294 verts[1].Z = temp.Z;
00295 verts[1].u = 0.0f;
00296 verts[1].v = 1.0f;
00297 verts[1].r = be->beCurrentColors[0];
00298 verts[1].g = be->beCurrentColors[1];
00299 verts[1].b = be->beCurrentColors[2];
00300 verts[1].a = LIGHTNINGALPHA;
00301
00302 geVec3d_Add(&be->beCenterPoints[i + 1], &perp, &temp);
00303 verts[2].X = temp.X;
00304 verts[2].Y = temp.Y;
00305 verts[2].Z = temp.Z;
00306 verts[2].u = 1.0f;
00307 verts[2].v = 1.0f;
00308 verts[2].r = be->beCurrentColors[0];
00309 verts[2].g = be->beCurrentColors[1];
00310 verts[2].b = be->beCurrentColors[2];
00311 verts[2].a = LIGHTNINGALPHA;
00312
00313 geVec3d_Add(&be->beCenterPoints[i], &perp, &temp);
00314 verts[3].X = temp.X;
00315 verts[3].Y = temp.Y;
00316 verts[3].Z = temp.Z;
00317 verts[3].u = 1.0f;
00318 verts[3].v = 0.0f;
00319 verts[3].r = be->beCurrentColors[0];
00320 verts[3].g = be->beCurrentColors[1];
00321 verts[3].b = be->beCurrentColors[2];
00322 verts[3].a = LIGHTNINGALPHA;
00323
00324 geWorld_AddPolyOnce(World,
00325 verts,
00326 4,
00327 NULL,
00328 GE_GOURAUD_POLY,
00329 GE_RENDER_DO_NOT_OCCLUDE_OTHERS,
00330 1.0f);
00331
00332 }
00333 }