| | 1 | #include "system.h" |
| | 2 | #include "stratdef.h" |
| | 3 | #include "bh_types.h" |
| | 4 | #include "lighting.h" |
| | 5 | #include "dynamics.h" |
| | 6 | #include <stdio.h> |
| | 7 | #include <assert.h> |
| | 8 | #include "sfx.h" |
| | 9 | |
| | 10 | #define MAX_NO_OF_LIGHTELEMENTS 500 |
| | 11 | |
| | 12 | extern int CloakingPhase; |
| | 13 | extern int NumActiveBlocks; |
| | 14 | extern DISPLAYBLOCK *ActiveBlockList[]; |
| | 15 | extern EULER HeadOrientation; |
| | 16 | |
| | 17 | static VECTORCH RotatingLightPosition; |
| | 18 | LIGHTELEMENT LightElementStorage[MAX_NO_OF_LIGHTELEMENTS]; |
| | 19 | static int LightScale = ONE_FIXED; |
| | 20 | |
| | 21 | int NumActiveLightElements; |
| | 22 | |
| | 23 | void AddLightingEffectToObject(DISPLAYBLOCK *objectPtr, enum LIGHTING_EFFECTS_ID lfxID) |
| | 24 | { |
| | 25 | LIGHTBLOCK *lightPtr = AddLightBlock(objectPtr, NULL); |
| | 26 | |
| | 27 | if (NULL == lightPtr) |
| | 28 | return; |
| | 29 | |
| | 30 | switch(lfxID) |
| | 31 | { |
| | 32 | case LFX_EXPLOSION: |
| | 33 | { |
| | 34 | lightPtr->LightBright = ONE_FIXED*4; |
| | 35 | lightPtr->LightFlags = 0; |
| | 36 | lightPtr->LightRange = EXPLOSION_LIGHT_RANGE; |
| | 37 | lightPtr->RedScale = 255 * 256; |
| | 38 | lightPtr->RedScale = 5 * 56; |
| | 39 | lightPtr->GreenScale = 220 * 256; |
| | 40 | lightPtr->BlueScale = 0; |
| | 41 | } |
| | 42 | break; |
| | 43 | case LFX_BIGEXPLOSION: |
| | 44 | { |
| | 45 | lightPtr->LightBright = ONE_FIXED << 2; |
| | 46 | lightPtr->LightFlags = 0; |
| | 47 | lightPtr->LightRange = EXPLOSION_LIGHT_RANGE; |
| | 48 | lightPtr->RedScale = 255 * 256; |
| | 49 | lightPtr->GreenScale = 120* 256; |
| | 50 | lightPtr->BlueScale = 0; |
| | 51 | } |
| | 52 | break; |
| | 53 | case LFX_MUZZLEFLASH: |
| | 54 | { |
| | 55 | lightPtr->LightBright = 65536 - (FastRandom()&32767); |
| | 56 | lightPtr->LightFlags = LFlag_Deallocate; |
| | 57 | //lightPtr->LightRange = 10000; /* ? */ |
| | 58 | lightPtr->LightRange = 20000; /* ? */ |
| | 59 | lightPtr->RedScale = 255 * 256; |
| | 60 | lightPtr->GreenScale = 230 * 256; |
| | 61 | lightPtr->BlueScale = 200 * 256; |
| | 62 | } |
| | 63 | break; |
| | 64 | case LFX_ROCKETJET: |
| | 65 | { |
| | 66 | lightPtr->LightBright = ONE_FIXED*3/4; |
| | 67 | lightPtr->LightFlags = 0; |
| | 68 | lightPtr->LightRange = 5000; /* ? */ |
| | 69 | lightPtr->RedScale = 255 * 256; |
| | 70 | lightPtr->GreenScale = 255 * 256; |
| | 71 | lightPtr->BlueScale= 128 * 256; |
| | 72 | } |
| | 73 | break; |
| | 74 | case LFX_FLARE: |
| | 75 | { |
| | 76 | lightPtr->LightBright = 0; |
| | 77 | lightPtr->LightFlags = 0; |
| | 78 | lightPtr->LightRange = 10000; /* ? */ |
| | 79 | lightPtr->RedScale = 255 * 256; |
| | 80 | lightPtr->GreenScale = 200 * 256; |
| | 81 | lightPtr->BlueScale = 255 * 256; |
| | 82 | } |
| | 83 | break; |
| | 84 | case LFX_XENO_FIRING: |
| | 85 | { |
| | 86 | lightPtr->LightBright = 226100; |
| | 87 | lightPtr->LightFlags = LFlag_Deallocate; |
| | 88 | lightPtr->LightRange = 5000; /* ? */ |
| | 89 | lightPtr->RedScale = 255 * 256; |
| | 90 | lightPtr->GreenScale = 64 * 256; |
| | 91 | lightPtr->BlueScale=255 * 256; |
| | 92 | } |
| | 93 | break; |
| | 94 | case LFX_PLASMA_BOLT: |
| | 95 | { |
| | 96 | lightPtr->LightBright = ONE_FIXED/4; |
| | 97 | lightPtr->LightFlags = 0; |
| | 98 | lightPtr->LightRange = 10000; |
| | 99 | lightPtr->RedScale = 200 * 256; |
| | 100 | lightPtr->GreenScale = 255 * 256; |
| | 101 | lightPtr->BlueScale = 255 * 256; |
| | 102 | } |
| | 103 | break; |
| | 104 | case LFX_OBJECTONFIRE: |
| | 105 | { |
| | 106 | lightPtr->LightBright = 16484 - (FastRandom()&4095); |
| | 107 | lightPtr->LightFlags = LFlag_Deallocate | LFlag_Thermal; |
| | 108 | lightPtr->LightRange = 10000; |
| | 109 | lightPtr->RedScale = 255*256; |
| | 110 | lightPtr->GreenScale = 110 * 256; |
| | 111 | lightPtr->BlueScale = 50* 256; |
| | 112 | } |
| | 113 | } |
| | 114 | } |
| | 115 | |
| | 116 | static LIGHTELEMENT* AllocateLightElement() |
| | 117 | { |
| | 118 | return (NumActiveLightElements < MAX_NO_OF_LIGHTELEMENTS) ? &LightElementStorage[NumActiveLightElements++] : NULL; |
| | 119 | } |
| | 120 | |
| | 121 | void MakeLightElement(const VECTORCH *positionPtr, enum LIGHTELEMENT_BEHAVIOUR_ID behaviourID) |
| | 122 | { |
| | 123 | LIGHTELEMENT *lightElementPtr = AllocateLightElement(); |
| | 124 | |
| | 125 | if (NULL != lightElementPtr) |
| | 126 | { |
| | 127 | LIGHTBLOCK *lightPtr = &lightElementPtr->LightBlock; |
| | 128 | lightElementPtr->BehaviourID = behaviourID; |
| | 129 | lightElementPtr->LightBlock.LightWorld = *positionPtr; |
| | 130 | lightElementPtr->LifeTime = ONE_FIXED; |
| | 131 | lightPtr->LightFlags = 0; |
| | 132 | |
| | 133 | switch (behaviourID) |
| | 134 | { |
| | 135 | case LIGHTELEMENT_ROTATING: |
| | 136 | RotatingLightPosition = *positionPtr; |
| | 137 | break; |
| | 138 | case LIGHTELEMENT_ALIEN_TEETH: |
| | 139 | { |
| | 140 | lightPtr->LightBright = ONE_FIXED/2; |
| | 141 | lightPtr->LightRange = 200; |
| | 142 | lightPtr->RedScale = lightPtr->GreenScale = lightPtr->BlueScale = ONE_FIXED; |
| | 143 | |
| | 144 | { |
| | 145 | VECTORCH position; |
| | 146 | position.vx = MUL_FIXED(200,GetSin((CloakingPhase)&4095)); |
| | 147 | position.vy = MUL_FIXED(200,GetCos((CloakingPhase)&4095)); |
| | 148 | position.vz = 80+MUL_FIXED(50,GetCos((CloakingPhase/2)&4095)); |
| | 149 | { |
| | 150 | MATRIXCH myMat = Global_VDB.VDB_Mat; |
| | 151 | TransposeMatrixCH(&myMat); |
| | 152 | RotateVector(&position, &myMat); |
| | 153 | position.vx += Global_VDB.VDB_World.vx; |
| | 154 | position.vy += Global_VDB.VDB_World.vy; |
| | 155 | position.vz += Global_VDB.VDB_World.vz; |
| | 156 | } |
| | 157 | |
| | 158 | lightElementPtr->LightBlock.LightWorld = position; |
| | 159 | } |
| | 160 | |
| | 161 | lightElementPtr->LifeTime = 0; |
| | 162 | } |
| | 163 | break; |
| | 164 | case LIGHTELEMENT_ALIEN_TEETH2: |
| | 165 | { |
| | 166 | lightPtr->LightBright = ONE_FIXED/2; |
| | 167 | lightPtr->LightRange = 200; |
| | 168 | lightPtr->RedScale = lightPtr->GreenScale = lightPtr->BlueScale = ONE_FIXED; |
| | 169 | |
| | 170 | { |
| | 171 | VECTORCH position; |
| | 172 | position.vx = MUL_FIXED(200,GetSin((CloakingPhase/3+2048)&4095)); |
| | 173 | position.vy = MUL_FIXED(200,GetCos((CloakingPhase/3+2048)&4095)); |
| | 174 | position.vz = 80+MUL_FIXED(50,GetCos((CloakingPhase/2+2048)&4095)); |
| | 175 | { |
| | 176 | MATRIXCH myMat = Global_VDB.VDB_Mat; |
| | 177 | TransposeMatrixCH(&myMat); |
| | 178 | RotateVector(&position, &myMat); |
| | 179 | position.vx += Global_VDB.VDB_World.vx; |
| | 180 | position.vy += Global_VDB.VDB_World.vy; |
| | 181 | position.vz += Global_VDB.VDB_World.vz; |
| | 182 | } |
| | 183 | |
| | 184 | lightElementPtr->LightBlock.LightWorld = position; |
| | 185 | } |
| | 186 | |
| | 187 | lightElementPtr->LifeTime = 0; |
| | 188 | } |
| | 189 | default: |
| | 190 | break; |
| | 191 | } |
| | 192 | } |
| | 193 | } |
| | 194 | |
| | 195 | void UpdateRunTimeLights() |
| | 196 | { |
| | 197 | int i,j; |
| | 198 | |
| | 199 | for(i=0; i < NumActiveBlocks; i++) |
| | 200 | { |
| | 201 | DISPLAYBLOCK *dptr = ActiveBlockList[i]; |
| | 202 | |
| | 203 | if( (dptr->SpecialFXFlags & SFXFLAG_ONFIRE) || ( dptr->ObStrategyBlock && dptr->ObStrategyBlock->DamageBlock.IsOnFire) ) |
| | 204 | AddLightingEffectToObject(dptr, LFX_OBJECTONFIRE); |
| | 205 | |
| | 206 | for(j = 0; j < dptr->ObNumLights; j++) |
| | 207 | { |
| | 208 | LIGHTBLOCK *lptr = dptr->ObLights[j]; |
| | 209 | |
| | 210 | /* Calculate the light's location */ |
| | 211 | if(!(lptr->LightFlags & LFlag_AbsPos)) |
| | 212 | lptr->LightWorld = dptr->ObWorld; |
| | 213 | |
| | 214 | assert(lptr->LightRange != 0); |
| | 215 | lptr->BrightnessOverRange = DIV_FIXED(MUL_FIXED(lptr->LightBright, LightScale), lptr->LightRange); |
| | 216 | } |
| | 217 | } |
| | 218 | |
| | 219 | i = NumActiveLightElements; |
| | 220 | LIGHTELEMENT *lightElementPtr = LightElementStorage; |
| | 221 | |
| | 222 | while(i--) |
| | 223 | { |
| | 224 | LIGHTBLOCK *lightPtr = &lightElementPtr->LightBlock; |
| | 225 | |
| | 226 | switch(lightElementPtr->BehaviourID) |
| | 227 | { |
| | 228 | case LIGHTELEMENT_MOLTENMETAL: |
| | 229 | { |
| | 230 | lightPtr->LightBright = ONE_FIXED/4; |
| | 231 | //lightPtr->LightFlags; |
| | 232 | lightPtr->LightRange = EXPLOSION_LIGHT_RANGE; |
| | 233 | lightPtr->RedScale = 255 * 256; |
| | 234 | lightPtr->GreenScale = 120 * 256; |
| | 235 | lightPtr->BlueScale = 0; |
| | 236 | } |
| | 237 | break; |
| | 238 | case LIGHTELEMENT_PLASMACASTERHIT: |
| | 239 | { |
| | 240 | //lightPtr->LightFlags; |
| | 241 | lightPtr->LightRange = EXPLOSION_LIGHT_RANGE; |
| | 242 | |
| | 243 | if (lightElementPtr->LifeTime == ONE_FIXED) |
| | 244 | { |
| | 245 | lightPtr->LightBright = ONE_FIXED*4; |
| | 246 | lightPtr->RedScale = 0; //0 * 256; |
| | 247 | lightPtr->GreenScale = 255 * 256; |
| | 248 | lightPtr->BlueScale = 255 * 256; |
| | 249 | } |
| | 250 | else |
| | 251 | { |
| | 252 | lightPtr->LightBright = lightElementPtr->LifeTime / 2; |
| | 253 | lightPtr->LightRange = 1 + MUL_FIXED(EXPLOSION_LIGHT_RANGE, lightElementPtr->LifeTime); |
| | 254 | lightPtr->RedScale = 255 * 256; |
| | 255 | lightPtr->GreenScale = 120 * 256; |
| | 256 | lightPtr->BlueScale = 0; //0 * 256; |
| | 257 | } |
| | 258 | |
| | 259 | lightElementPtr->LifeTime -= NormalFrameTime *4; |
| | 260 | } |
| | 261 | break; |
| | 262 | case LIGHTELEMENT_FROMFMV: |
| | 263 | { |
| | 264 | extern int FmvColourRed; |
| | 265 | extern int FmvColourGreen; |
| | 266 | extern int FmvColourBlue; |
| | 267 | |
| | 268 | lightPtr->LightBright = ONE_FIXED*4; |
| | 269 | //lightPtr->LightFlags; |
| | 270 | lightPtr->LightRange = 15000; |
| | 271 | |
| | 272 | lightPtr->RedScale = FmvColourRed; |
| | 273 | lightPtr->GreenScale = FmvColourGreen; |
| | 274 | lightPtr->BlueScale = FmvColourBlue; |
| | 275 | } |
| | 276 | break; |
| | 277 | case LIGHTELEMENT_EXPLOSION: |
| | 278 | { |
| | 279 | //lightPtr->LightFlags; |
| | 280 | //lightPtr->RedScale = 255 * 256; |
| | 281 | lightPtr->RedScale = 155 * 256; |
| | 282 | lightPtr->GreenScale = 120 * 256; |
| | 283 | lightPtr->BlueScale = 0; |
| | 284 | |
| | 285 | { |
| | 286 | int scale = lightElementPtr->LifeTime * 4; |
| | 287 | |
| | 288 | if (scale < ONE_FIXED) |
| | 289 | { |
| | 290 | lightPtr->LightRange = 1 + MUL_FIXED(EXPLOSION_LIGHT_RANGE, scale); |
| | 291 | lightPtr->LightBright = scale * 8; |
| | 292 | } |
| | 293 | else |
| | 294 | { |
| | 295 | lightPtr->LightRange = EXPLOSION_LIGHT_RANGE; |
| | 296 | lightPtr->LightBright = ONE_FIXED*8; |
| | 297 | } |
| | 298 | } |
| | 299 | |
| | 300 | if (PlayerStatus.Alive) |
| | 301 | { |
| | 302 | VECTORCH d = lightElementPtr->LightBlock.LightWorld; |
| | 303 | d.vx -= Global_VDB.VDB_World.vx; |
| | 304 | d.vy -= Global_VDB.VDB_World.vy; |
| | 305 | d.vz -= Global_VDB.VDB_World.vz; |
| | 306 | int m = Approximate3dMagnitude(&d); |
| | 307 | |
| | 308 | if (m < ONE_FIXED) |
| | 309 | { |
| | 310 | int maxTilt = MUL_FIXED((ONE_FIXED - m) >> 9, lightElementPtr->LifeTime); |
| | 311 | int halfTilt = maxTilt / 2; |
| | 312 | |
| | 313 | if (maxTilt) |
| | 314 | { |
| | 315 | HeadOrientation.EulerX = (FastRandom() % maxTilt) - halfTilt; |
| | 316 | HeadOrientation.EulerY = (FastRandom() % maxTilt) - halfTilt; |
| | 317 | HeadOrientation.EulerZ = (FastRandom() % maxTilt) - halfTilt; |
| | 318 | |
| | 319 | if (HeadOrientation.EulerX < 0) |
| | 320 | HeadOrientation.EulerX += 4096; |
| | 321 | |
| | 322 | if (HeadOrientation.EulerY < 0) |
| | 323 | HeadOrientation.EulerY += 4096; |
| | 324 | |
| | 325 | if (HeadOrientation.EulerZ < 0) |
| | 326 | HeadOrientation.EulerZ += 4096; |
| | 327 | } |
| | 328 | } |
| | 329 | } |
| | 330 | |
| | 331 | lightElementPtr->LifeTime -= NormalFrameTime; |
| | 332 | } |
| | 333 | break; |
| | 334 | case LIGHTELEMENT_ELECTRICAL_EXPLOSION: |
| | 335 | { |
| | 336 | int scale = ONE_FIXED*5/4-lightElementPtr->LifeTime; |
| | 337 | |
| | 338 | lightPtr->LightFlags = LFlag_Electrical; |
| | 339 | |
| | 340 | if (scale > 65536) |
| | 341 | scale = 65536; |
| | 342 | |
| | 343 | scale = ONE_FIXED - scale; |
| | 344 | |
| | 345 | lightPtr->RedScale = scale; |
| | 346 | lightPtr->GreenScale = ONE_FIXED; |
| | 347 | lightPtr->BlueScale = ONE_FIXED; |
| | 348 | lightPtr->LightRange = EXPLOSION_LIGHT_RANGE;// 1+MUL_FIXED(EXPLOSION_LIGHT_RANGE,scale); |
| | 349 | lightPtr->LightBright = scale*16; |
| | 350 | |
| | 351 | lightElementPtr->LifeTime -= NormalFrameTime; |
| | 352 | } |
| | 353 | break; |
| | 354 | case LIGHTELEMENT_ELECTRICAL_SPARKS: |
| | 355 | { |
| | 356 | int scale = lightElementPtr->LifeTime; |
| | 357 | |
| | 358 | lightPtr->LightFlags = LFlag_Electrical; |
| | 359 | |
| | 360 | if (scale == ONE_FIXED) |
| | 361 | { |
| | 362 | lightPtr->RedScale = ONE_FIXED; |
| | 363 | lightPtr->GreenScale = ONE_FIXED; |
| | 364 | lightPtr->BlueScale = ONE_FIXED; |
| | 365 | } |
| | 366 | else |
| | 367 | { |
| | 368 | lightPtr->RedScale = 0; |
| | 369 | lightPtr->GreenScale = scale/2; |
| | 370 | lightPtr->BlueScale = scale; |
| | 371 | } |
| | 372 | lightPtr->LightRange = 4000;// 1+MUL_FIXED(EXPLOSION_LIGHT_RANGE,scale); |
| | 373 | lightPtr->LightBright = scale; |
| | 374 | |
| | 375 | lightElementPtr->LifeTime -= NormalFrameTime * 2; |
| | 376 | } |
| | 377 | break; |
| | 378 | case LIGHTELEMENT_ROTATING: |
| | 379 | { |
| | 380 | lightPtr->LightBright = ONE_FIXED/2; |
| | 381 | //lightPtr->LightFlags; |
| | 382 | lightPtr->LightRange = 10000; |
| | 383 | |
| | 384 | lightPtr->RedScale = ONE_FIXED; |
| | 385 | lightPtr->GreenScale = ONE_FIXED; |
| | 386 | lightPtr->BlueScale = ONE_FIXED; |
| | 387 | |
| | 388 | lightElementPtr->LightBlock.LightWorld = PlayerStatus.DisplayBlock->ObWorld;//RotatingLightPosition; |
| | 389 | lightElementPtr->LightBlock.LightWorld.vy -= 2200; |
| | 390 | } |
| | 391 | break; |
| | 392 | case LIGHTELEMENT_PARGEN_FLAME: |
| | 393 | { |
| | 394 | if(lightElementPtr->LifeTime == ONE_FIXED) |
| | 395 | { |
| | 396 | lightElementPtr->LifeTime = 1; |
| | 397 | |
| | 398 | //lightPtr->LightFlags; |
| | 399 | //lightPtr->RedScale= 255*256; |
| | 400 | //lightPtr->GreenScale= 120*256; |
| | 401 | lightPtr->RedScale= 255*(200+(CloakingPhase%56)); |
| | 402 | lightPtr->GreenScale= 120*(200+((CloakingPhase/8)%56)); |
| | 403 | lightPtr->BlueScale= 0; |
| | 404 | lightPtr->LightRange = 6000; |
| | 405 | lightPtr->LightBright = ONE_FIXED; |
| | 406 | } |
| | 407 | else |
| | 408 | { |
| | 409 | lightElementPtr->LifeTime = 0; |
| | 410 | } |
| | 411 | } |
| | 412 | default: |
| | 413 | break; |
| | 414 | } |
| | 415 | |
| | 416 | lightPtr->BrightnessOverRange = DIV_FIXED(MUL_FIXED(lightPtr->LightBright, LightScale), lightPtr->LightRange); |
| | 417 | |
| | 418 | if (lightElementPtr->LifeTime <= 0) |
| | 419 | *lightElementPtr = LightElementStorage[--NumActiveLightElements]; |
| | 420 | else |
| | 421 | lightElementPtr++; |
| | 422 | } |
| | 423 | } |
| | 424 | /*--------------------------** |
| | 425 | ** Load/Save Light Elements ** |
| | 426 | **--------------------------*/ |
| | 427 | #include "savegame.h" |
| | 428 | |
| | 429 | typedef struct light_element_save_block_header |
| | 430 | { |
| | 431 | SAVE_BLOCK_HEADER header; |
| | 432 | |
| | 433 | int NumActiveLightElements; |
| | 434 | |
| | 435 | //followed by array of light elements |
| | 436 | |
| | 437 | } LIGHT_ELEMENT_SAVE_BLOCK_HEADER; |
| | 438 | |
| | 439 | void Load_LightElements(SAVE_BLOCK_HEADER* header) |
| | 440 | { |
| | 441 | int i; |
| | 442 | LIGHT_ELEMENT_SAVE_BLOCK_HEADER* block = (LIGHT_ELEMENT_SAVE_BLOCK_HEADER*) header; |
| | 443 | LIGHTELEMENT* saved_light_element = (LIGHTELEMENT*) (block+1); |
| | 444 | int expected_size; |
| | 445 | |
| | 446 | //make sure the block is the correct size |
| | 447 | expected_size = sizeof(*block); |
| | 448 | expected_size += sizeof(LIGHTELEMENT) * block->NumActiveLightElements; |
| | 449 | |
| | 450 | if(header->size != expected_size) |
| | 451 | return; |
| | 452 | |
| | 453 | for(i=0; i < block->NumActiveLightElements; i++) |
| | 454 | { |
| | 455 | LIGHTELEMENT* light_element = AllocateLightElement(); |
| | 456 | |
| | 457 | if(light_element) |
| | 458 | *light_element = *saved_light_element++; |
| | 459 | } |
| | 460 | } |
| | 461 | |
| | 462 | void Save_LightElements() |
| | 463 | { |
| | 464 | if(NumActiveLightElements) |
| | 465 | { |
| | 466 | int i; |
| | 467 | LIGHT_ELEMENT_SAVE_BLOCK_HEADER* block; |
| | 468 | //get memory for header |
| | 469 | GET_SAVE_BLOCK_POINTER(block); |
| | 470 | |
| | 471 | //fill in header |
| | 472 | block->header.type = SaveBlock_LightElements; |
| | 473 | block->header.size = sizeof(*block) + NumActiveLightElements * sizeof(LIGHTELEMENT); |
| | 474 | block->NumActiveLightElements = NumActiveLightElements; |
| | 475 | |
| | 476 | //now save the light elements |
| | 477 | for(i=0; i < NumActiveLightElements; i++) |
| | 478 | { |
| | 479 | LIGHTELEMENT* light = GET_SAVE_BLOCK_POINTER(light); |
| | 480 | *light = LightElementStorage[i]; |
| | 481 | } |
| | 482 | } |
| | 483 | } |