00001
00002
00003
00004
00005
00006
00007
00008 #include <windows.h>
00009 #include <math.h>
00010 #include <assert.h>
00011
00012 #include "genesis.h"
00013 #include "ErrorLog.h"
00014
00015 #include "Electric.h"
00016 #include "..\\Procedurals\\gebmutil.h"
00017
00018 extern geFloat EffectScale;
00019
00020 static geBitmap *Bitmap;
00021 static geSound_Def * LoopingDef;
00022 static geSound_Def * SingleDef;
00023 static geSound_System * SoundSys;
00024
00025 static geBoolean Electric_SetWorld(geWorld *World, geVFile *Context);
00026
00027 typedef struct Electric_BoltEffect
00028 {
00029 int beInitialized;
00030 int beNumPoints;
00031 geFloat beWildness;
00032
00033
00034 geVec3d beStart;
00035 geVec3d beEnd;
00036
00037
00038 geVec3d * beCenterPoints;
00039 geVec3d * beCurrentPoint;
00040
00041 geFloat beBaseColors[3];
00042 geFloat beCurrentColors[3];
00043 geFloat beBaseBlue;
00044 int beDecayRate;
00045 int beDominantColor;
00046
00047 int beWidth;
00048
00049 geBitmap *beBitmap;
00050
00051 } Electric_BoltEffect;
00052
00053 Electric_BoltEffect * Electric_BoltEffectCreate(
00054 geBitmap *Texture,
00055 geBitmap *Texture2,
00056 int NumPolys,
00057 int Width,
00058 geFloat Wildness);
00059
00060 void Electric_BoltEffectDestroy(Electric_BoltEffect *Effect);
00061
00062 void Electric_BoltEffectAnimate(
00063 Electric_BoltEffect * Effect,
00064 const geVec3d * start,
00065 const geVec3d * end);
00066
00067 void Electric_BoltEffectRender(
00068 geWorld * World,
00069 Electric_BoltEffect * Effect,
00070 const geXForm3d * XForm);
00071
00072 void Electric_BoltEffectSetColorInfo(
00073 Electric_BoltEffect * Effect,
00074 GE_RGBA * BaseColor,
00075 int DominantColor);
00076
00077 static int logBase2(int n)
00078 {
00079 int i = 0;
00080
00081 assert(n != 0);
00082
00083 while (!(n & 1))
00084 {
00085 n = n >> 1;
00086 i++;
00087 }
00088
00089 assert((n & ~1) == 0);
00090
00091 return i;
00092 }
00093
00094 static geBoolean IsPowerOf2(int n)
00095 {
00096 if (n == 0)
00097 return GE_TRUE;
00098
00099 while (!(n & 1))
00100 n = n >> 1;
00101
00102 if (n & ~1)
00103 return GE_FALSE;
00104
00105 return GE_TRUE;
00106 }
00107
00108 Electric_BoltEffect * Electric_BoltEffectCreate(
00109 geBitmap *Bitmap,
00110 geBitmap *Bitmap2,
00111 int NumPolys,
00112 int Width,
00113 geFloat Wildness)
00114 {
00115 Electric_BoltEffect * be;
00116 GE_RGBA color;
00117
00118 assert(Wildness >= 0.0f && Wildness <= 1.0f);
00119
00120
00121 logBase2(NumPolys);
00122
00123 be = (Electric_BoltEffect *)malloc(sizeof(*be));
00124 if (!be)
00125 return be;
00126
00127 memset(be, 0, sizeof(*be));
00128
00129 be->beCenterPoints = (geVec3d *)malloc(sizeof(*be->beCenterPoints) * (NumPolys + 1));
00130 if (!be->beCenterPoints)
00131 goto fail;
00132
00133 be->beBitmap = Bitmap;
00134
00135 be->beNumPoints = NumPolys;
00136 be->beWildness = Wildness;
00137 be->beWidth = Width;
00138
00139
00140
00141
00142
00143
00144
00145
00146
00147
00148
00149 color.r = 160.0f;
00150 color.g = 160.0f;
00151 color.b = 255.0f;
00152 Electric_BoltEffectSetColorInfo(be, &color, ELECTRIC_BOLT_BLUEDOMINANT);
00153
00154 return be;
00155
00156 fail:
00157 if (be->beCenterPoints)
00158 free(be->beCenterPoints);
00159
00160 return NULL;
00161 }
00162
00163 void Electric_BoltEffectDestroy(Electric_BoltEffect *Effect)
00164 {
00165 free(Effect->beCenterPoints);
00166 free(Effect);
00167 }
00168
00169 static geFloat GaussRand(void)
00170 {
00171 int i;
00172 int r;
00173
00174 r = 0;
00175
00176 for (i = 0; i < 6; i++)
00177 r = r + rand() - rand();
00178
00179 return (geFloat)r / ((geFloat)RAND_MAX * 6.0f);
00180 }
00181
00182 static void subdivide(
00183 Electric_BoltEffect * be,
00184 const geVec3d * start,
00185 const geVec3d * end,
00186 geFloat s,
00187 int n)
00188 {
00189 geVec3d tmp;
00190
00191 if (n == 0)
00192 {
00193 be->beCurrentPoint++;
00194 *be->beCurrentPoint = *end;
00195 return;
00196 }
00197
00198 tmp.X = (end->X + start->X) / 2 + s * GaussRand();
00199 tmp.Y = (end->Y + start->Y) / 2 + s * GaussRand();
00200 tmp.Z = (end->Z + start->Z) / 2 + s * GaussRand();
00201 subdivide(be, start, &tmp, s / 2, n - 1);
00202 subdivide(be, &tmp, end, s / 2, n - 1);
00203 }
00204
00205 #define LIGHTNINGWIDTH 8.0f
00206
00207 static void genLightning(
00208 Electric_BoltEffect * be,
00209 int RangeLow,
00210 int RangeHigh,
00211 const geVec3d * start,
00212 const geVec3d * end)
00213 {
00214 geFloat length;
00215 int seed;
00216
00217 assert(be);
00218 assert(start);
00219 assert(end);
00220 assert(RangeHigh > RangeLow);
00221 assert(IsPowerOf2(RangeHigh - RangeLow));
00222
00223
00224 length = (geFloat)(fabs(start->X - end->X) +
00225 fabs(start->Y - end->Y) +
00226 fabs(start->Z - end->Z));
00227
00228 seed = rand();
00229
00230 srand(seed);
00231 be->beCurrentPoint = be->beCenterPoints + RangeLow;
00232 be->beCenterPoints[RangeLow] = *start;
00233 be->beCenterPoints[RangeHigh] = *end;
00234
00235
00236 subdivide(be, start, end, length * be->beWildness, logBase2(RangeHigh - RangeLow));
00237 }
00238
00239 void Electric_BoltEffectSetColorInfo(
00240 Electric_BoltEffect * Effect,
00241 GE_RGBA * BaseColor,
00242 int DominantColor)
00243 {
00244 Effect->beBaseColors[0] = BaseColor->r;
00245 Effect->beBaseColors[1] = BaseColor->g;
00246 Effect->beBaseColors[2] = BaseColor->b;
00247 Effect->beCurrentColors[0] = BaseColor->r;
00248 Effect->beCurrentColors[1] = BaseColor->g;
00249 Effect->beCurrentColors[2] = BaseColor->b;
00250 Effect->beDominantColor = DominantColor;
00251 }
00252
00253 void Electric_BoltEffectAnimate(
00254 Electric_BoltEffect * Effect,
00255 const geVec3d * start,
00256 const geVec3d * end)
00257 {
00258 int dominant;
00259 int nonDominant1;
00260 int nonDominant2;
00261 geVec3d SubdivideStart;
00262 geVec3d SubdivideEnd;
00263 int LowIndex;
00264 int HighIndex;
00265
00266 Effect->beStart = *start;
00267 Effect->beEnd = *end;
00268
00269 dominant = Effect->beDominantColor;
00270 nonDominant1 = (dominant + 1) % 3;
00271 nonDominant2 = (dominant + 2) % 3;
00272 if (Effect->beBaseColors[nonDominant1] == Effect->beCurrentColors[nonDominant1])
00273 {
00274 int DecayRate;
00275 int Spike;
00276
00277 DecayRate = rand() % (int)(Effect->beBaseColors[dominant] - Effect->beBaseColors[nonDominant1]);
00278 DecayRate = max(DecayRate, 5);
00279 Effect->beDecayRate = DecayRate;
00280 if (Effect->beBaseColors[nonDominant1] >= 1.0f)
00281 Spike = rand() % (int)(Effect->beBaseColors[nonDominant1]);
00282 else
00283 Spike = 0;
00284 Effect->beCurrentColors[nonDominant1] -= Spike;
00285 Effect->beCurrentColors[nonDominant2] -= Spike;
00286 }
00287 else
00288 {
00289 Effect->beCurrentColors[nonDominant1] += Effect->beDecayRate;
00290 Effect->beCurrentColors[nonDominant2] += Effect->beDecayRate;
00291 if (Effect->beCurrentColors[nonDominant1] > Effect->beBaseColors[nonDominant1])
00292 {
00293 Effect->beCurrentColors[nonDominant1] = Effect->beBaseColors[nonDominant1];
00294 Effect->beCurrentColors[nonDominant2] = Effect->beBaseColors[nonDominant2];
00295 }
00296 }
00297
00298 if (Effect->beInitialized && Effect->beNumPoints > 16)
00299 {
00300 int P1;
00301 int P2;
00302 int P3;
00303 int P4;
00304
00305 switch (rand() % 7)
00306 {
00307 case 0:
00308 genLightning(Effect, 0, Effect->beNumPoints, start, end);
00309 return;
00310
00311 case 1:
00312 case 2:
00313 case 3:
00314 P1 = 0;
00315 P2 = Effect->beNumPoints / 2;
00316 P3 = P2 + Effect->beNumPoints / 4;
00317 P4 = Effect->beNumPoints;
00318 break;
00319
00320 case 4:
00321 case 5:
00322 case 6:
00323 P1 = 0;
00324 P3 = Effect->beNumPoints / 2;
00325 P2 = P3 - Effect->beNumPoints / 4;
00326 P4 = Effect->beNumPoints;
00327 break;
00328 }
00329 SubdivideStart = Effect->beCenterPoints[P1];
00330 SubdivideEnd = Effect->beCenterPoints[P2];
00331 genLightning(Effect, P1, P2, &SubdivideStart, &SubdivideEnd);
00332 SubdivideStart = Effect->beCenterPoints[P2];
00333 SubdivideEnd = Effect->beCenterPoints[P3];
00334 genLightning(Effect, P2, P3, &SubdivideStart, &SubdivideEnd);
00335 SubdivideStart = Effect->beCenterPoints[P3];
00336 SubdivideEnd = Effect->beCenterPoints[P4];
00337 genLightning(Effect, P3, P4, &SubdivideStart, &SubdivideEnd);
00338 }
00339 else
00340 {
00341 Effect->beInitialized = 1;
00342 LowIndex = 0;
00343 HighIndex = Effect->beNumPoints;
00344 SubdivideStart = *start;
00345 SubdivideEnd = *end;
00346
00347 genLightning(Effect, LowIndex, HighIndex, &SubdivideStart, &SubdivideEnd);
00348 }
00349 }
00350
00351 #if 0
00352 static void DrawPoint(geWorld *world, geVec3d *pos, geBitmap *Bitmap, int r, int g, int b)
00353 {
00354 GE_LVertex vert;
00355
00356 vert.X = pos->X;
00357 vert.Y = pos->Y;
00358 vert.Z = pos->Z;
00359 vert.r = (geFloat)r;
00360 vert.g = (geFloat)g;
00361 vert.b = (geFloat)b;
00362 vert.a = 255.0f;
00363 vert.u = vert.v = 0.0f;
00364
00365 GE_WorldAddPolyOnce(world,
00366 &vert,
00367 1,
00368 Bitmap,
00369 GE_TEXTURED_POINT,
00370 GE_FX_TRANSPARENT,
00371 EffectScale);
00372 }
00373 #endif
00374
00375 #define LIGHTNINGALPHA 160.0f
00376
00377 void Electric_BoltEffectRender(
00378 geWorld * World,
00379 Electric_BoltEffect * be,
00380 const geXForm3d * XForm)
00381 {
00382 geVec3d perp;
00383 geVec3d temp;
00384 geVec3d in;
00385 GE_LVertex verts[4];
00386 int i;
00387
00388 geVec3d_Subtract(&be->beStart, &be->beEnd, &temp);
00389 geXForm3d_GetIn(XForm, &in);
00390
00391 geVec3d_CrossProduct(&in, &temp, &perp);
00392 geVec3d_Normalize(&perp);
00393
00394 geVec3d_Scale(&perp, be->beWidth / 2.0f, &perp);
00395
00396
00397
00398
00399
00400
00401
00402 for (i = 0; i < be->beNumPoints - 1; i++)
00403 {
00404 geVec3d temp;
00405
00406 geVec3d_Subtract(&be->beCenterPoints[i], &perp, &temp);
00407 verts[0].X = temp.X;
00408 verts[0].Y = temp.Y;
00409 verts[0].Z = temp.Z;
00410 verts[0].u = 0.0f;
00411 verts[0].v = 0.0f;
00412 verts[0].r = be->beCurrentColors[0];
00413 verts[0].g = be->beCurrentColors[1];
00414 verts[0].b = be->beCurrentColors[2];
00415 verts[0].a = LIGHTNINGALPHA;
00416
00417 geVec3d_Subtract(&be->beCenterPoints[i + 1], &perp, &temp);
00418 verts[1].X = temp.X;
00419 verts[1].Y = temp.Y;
00420 verts[1].Z = temp.Z;
00421 verts[1].u = 0.0f;
00422 verts[1].v = 1.0f;
00423 verts[1].r = be->beCurrentColors[0];
00424 verts[1].g = be->beCurrentColors[1];
00425 verts[1].b = be->beCurrentColors[2];
00426 verts[1].a = LIGHTNINGALPHA;
00427
00428 geVec3d_Add(&be->beCenterPoints[i + 1], &perp, &temp);
00429 verts[2].X = temp.X;
00430 verts[2].Y = temp.Y;
00431 verts[2].Z = temp.Z;
00432 verts[2].u = 1.0f;
00433 verts[2].v = 1.0f;
00434 verts[2].r = be->beCurrentColors[0];
00435 verts[2].g = be->beCurrentColors[1];
00436 verts[2].b = be->beCurrentColors[2];
00437 verts[2].a = LIGHTNINGALPHA;
00438
00439 geVec3d_Add(&be->beCenterPoints[i], &perp, &temp);
00440 verts[3].X = temp.X;
00441 verts[3].Y = temp.Y;
00442 verts[3].Z = temp.Z;
00443 verts[3].u = 1.0f;
00444 verts[3].v = 0.0f;
00445 verts[3].r = be->beCurrentColors[0];
00446 verts[3].g = be->beCurrentColors[1];
00447 verts[3].b = be->beCurrentColors[2];
00448 verts[3].a = LIGHTNINGALPHA;
00449
00450 geWorld_AddPolyOnce(World,
00451 verts,
00452 4,
00453 be->beBitmap,
00454 GE_TEXTURED_POLY,
00455 GE_RENDER_DO_NOT_OCCLUDE_OTHERS,
00456 1.0f);
00457
00458
00459 }
00460 }
00461
00462 geBoolean Electric_Init(geEngine *Engine, geWorld *World, geVFile * MainFS, geSound_System *SoundSystem)
00463 {
00464 Engine;
00465
00466 if (SoundSystem)
00467 {
00468 geVFile * File;
00469
00470 SoundSys = SoundSystem;
00471 assert(SoundSys);
00472 File = geVFile_Open(MainFS, "wav\\loopbzzt.wav", GE_VFILE_OPEN_READONLY);
00473 if (!File)
00474 return GE_FALSE;
00475 LoopingDef = geSound_LoadSoundDef(SoundSys, File);
00476 geVFile_Close(File);
00477 File = geVFile_Open(MainFS, "wav\\onebzzt.wav", GE_VFILE_OPEN_READONLY);
00478 if (!File)
00479 return GE_FALSE;
00480
00481 SingleDef = geSound_LoadSoundDef(SoundSys, File);
00482
00483 geVFile_Close(File);
00484 if (!LoopingDef || !SingleDef)
00485 return GE_FALSE;
00486 }
00487
00488 if (!Electric_SetWorld(World, MainFS))
00489 {
00490
00491 return GE_FALSE;
00492 }
00493
00494 return GE_TRUE;
00495 }
00496
00497 geBoolean Electric_Reset(geWorld *World)
00498 {
00499 geEntity_EntitySet * Set;
00500 geEntity * Entity;
00501
00502 if (!World)
00503 return GE_TRUE;
00504
00505 Set = geWorld_GetEntitySet(World, "ElectricBolt");
00506 if (Set == NULL)
00507 return GE_TRUE;
00508
00509 Entity = geEntity_EntitySetGetNextEntity(Set, NULL);
00510 while (Entity)
00511 {
00512 ElectricBolt * Bolt;
00513
00514 Bolt = geEntity_GetUserData(Entity);
00515 Bolt->LastTime = 0.0f;
00516 Bolt->LastBoltTime = 0.0f;
00517
00518 Entity = geEntity_EntitySetGetNextEntity(Set, Entity);
00519 }
00520
00521 return GE_TRUE;
00522 }
00523
00524 static geBoolean Electric_SetWorld(geWorld *World, geVFile *MainFS)
00525 {
00526 geEntity_EntitySet * Set;
00527 geEntity * Entity;
00528
00529 assert(World);
00530 assert(MainFS);
00531
00532 assert(Bitmap == NULL);
00533
00534 Set = geWorld_GetEntitySet(World, "ElectricBolt");
00535
00536 if (Set == NULL)
00537 return GE_TRUE;
00538
00539 Bitmap = geBitmapUtil_CreateFromFileAndAlphaNames(MainFS, "Bmp\\Bolt.Bmp", "Bmp\\Bolt.Bmp");
00540
00541 if (!Bitmap)
00542 {
00543 geErrorLog_AddString(-1, "Electric_SetWorld: geBitmapUtil_CreateFromFileAndAlphaNames failed:", "Bmp\\Bolt.Bmp, Bmp\\Bolt.Bmp");
00544 return GE_FALSE;
00545 }
00546
00547 if (!geWorld_AddBitmap(World, Bitmap))
00548 {
00549 geBitmap_Destroy(&Bitmap);
00550 return GE_FALSE;
00551 }
00552
00553 Entity = geEntity_EntitySetGetNextEntity(Set, NULL);
00554 while (Entity)
00555 {
00556 ElectricBolt * Bolt;
00557
00558 Bolt = geEntity_GetUserData(Entity);
00559 if (Bolt->Terminus == NULL)
00560 {
00561 #define MAX_NAME 100
00562 char EntityName[MAX_NAME];
00563 char s[MAX_NAME + 200];
00564 geEntity_GetName(Entity, EntityName, MAX_NAME-1);
00565 EntityName[MAX_NAME-1]=0;
00566 sprintf(s,"Name='%s' Origin=%f,%f,%f",EntityName,Bolt->origin.X,Bolt->origin.Y,Bolt->origin.Z);
00567 geErrorLog_AddString(-1,"Electric_SetWorld: ElectricBolt entity has no terminius. ",s);
00568 geWorld_RemoveBitmap(World, Bitmap);
00569 geBitmap_Destroy(&Bitmap);
00570 return GE_FALSE;
00571 }
00572 Bolt->Bolt = Electric_BoltEffectCreate(Bitmap,
00573 NULL,
00574 Bolt->NumPoints,
00575 Bolt->Width,
00576 Bolt->Wildness);
00577
00578 Electric_BoltEffectSetColorInfo(Bolt->Bolt, &Bolt->Color, Bolt->DominantColor);
00579
00580 if (Bolt->Bolt == NULL)
00581 {
00582 geWorld_RemoveBitmap(World, Bitmap);
00583 geBitmap_Destroy(&Bitmap);
00584 return GE_FALSE;
00585 }
00586
00587 if (!Bolt->Intermittent && SoundSys)
00588 {
00589 Bolt->LoopingSound = geSound_PlaySoundDef(SoundSys,
00590 LoopingDef,
00591 0.0f,
00592 0.0f,
00593 0.0f,
00594 GE_TRUE);
00595 if (!Bolt->LoopingSound)
00596 {
00597 geWorld_RemoveBitmap(World, Bitmap);
00598 geBitmap_Destroy(&Bitmap);
00599 return GE_FALSE;
00600 }
00601 }
00602
00603 Entity = geEntity_EntitySetGetNextEntity(Set, Entity);
00604 }
00605
00606 return GE_TRUE;
00607 }
00608
00609 geBoolean Electric_Shutdown(void)
00610 {
00611 if (LoopingDef)
00612 {
00613 geSound_FreeSoundDef(SoundSys, LoopingDef);
00614 LoopingDef = NULL;
00615 }
00616
00617 if (SingleDef)
00618 {
00619 geSound_FreeSoundDef(SoundSys, SingleDef);
00620 SingleDef = NULL;
00621 }
00622
00623 if (Bitmap)
00624 {
00625
00626 geBitmap_Destroy(&Bitmap);
00627 Bitmap = NULL;
00628 }
00629
00630 return GE_TRUE;
00631 }
00632
00633 static geFloat frand(geFloat Low, geFloat High)
00634 {
00635 geFloat Range;
00636
00637
00638
00639 Range = High - Low;
00640
00641 return ((geFloat)(((rand() % 1000) + 1))) / 1000.0f * Range + Low;
00642 }
00643
00644 #define LIGHTNINGSTROKEDURATION 0.05f
00645
00646 geBoolean Electric_Frame(geWorld *World, const geXForm3d *XForm, geFloat DeltaTime)
00647 {
00648 geEntity_EntitySet * Set;
00649 geEntity * Entity;
00650
00651 if (!World)
00652 return GE_TRUE;
00653
00654 Set = geWorld_GetEntitySet(World, "ElectricBolt");
00655 if (Set == NULL)
00656 return GE_TRUE;
00657
00658 Entity = geEntity_EntitySetGetNextEntity(Set, NULL);
00659 while (Entity)
00660 {
00661 ElectricBolt * Bolt;
00662 geFloat Volume;
00663 geFloat Pan;
00664 geFloat Frequency;
00665 geVec3d MidPoint;
00666 int32 Leaf;
00667
00668 Bolt = geEntity_GetUserData(Entity);
00669
00670 geVec3d_Subtract(&Bolt->Terminus->origin, &Bolt->origin, &MidPoint);
00671 geVec3d_AddScaled(&Bolt->origin, &MidPoint, 0.5f, &MidPoint);
00672
00673 geWorld_GetLeaf(World, &MidPoint, &Leaf);
00674
00675 if (geWorld_MightSeeLeaf(World, Leaf))
00676 {
00677 geSound3D_GetConfig(World,
00678 XForm,
00679 &MidPoint,
00680 600.0f,
00681 2.0f,
00682 &Volume,
00683 &Pan,
00684 &Frequency);
00685
00686 Bolt->LastTime += DeltaTime;
00687
00688 if (!Bolt->Intermittent ||
00689 (Bolt->LastTime - Bolt->LastBoltTime > frand(Bolt->MaxFrequency, Bolt->MinFrequency)))
00690 {
00691 Electric_BoltEffectAnimate(Bolt->Bolt,
00692 &Bolt->origin,
00693 &Bolt->Terminus->origin);
00694
00695 if (Bolt->Intermittent && SoundSys)
00696 geSound_PlaySoundDef(SoundSys, SingleDef, Volume, Pan, Frequency, GE_FALSE);
00697
00698 Bolt->LastBoltTime = Bolt->LastTime;
00699 }
00700
00701 if (!Bolt->Intermittent && SoundSys)
00702 geSound_ModifySound(SoundSys, Bolt->LoopingSound, Volume, Pan, Frequency);
00703
00704 if (Bolt->LastTime - Bolt->LastBoltTime <= LIGHTNINGSTROKEDURATION)
00705 Electric_BoltEffectRender(World, Bolt->Bolt, XForm);
00706 }
00707
00708 Entity = geEntity_EntitySetGetNextEntity(Set, Entity);
00709 }
00710
00711 return GE_TRUE;
00712 }
00713