diff --git a/source/blood/src/actor.cpp b/source/blood/src/actor.cpp index b7d8fd26f..9b3af1744 100644 --- a/source/blood/src/actor.cpp +++ b/source/blood/src/actor.cpp @@ -7890,4 +7890,327 @@ bool isImmune(spritetype* pSprite, int dmgType, int minScale) { return true; } + +#ifdef POLYMER + +// this is the same crap as in game.c's tspr manipulation. puke. +// XXX: may access tilesizy out-of-bounds by bad user code. +#define LIGHTRAD(spriteNum, s) (s->yrepeat * tilesiz[s->picnum].y) +#define LIGHTRAD2(spriteNum, s) ((s->yrepeat + ((rand() % s->yrepeat)>>2)) * tilesiz[s->picnum].y) + +void G_AddGameLight(int lightRadius, int spriteNum, int zOffset, int lightRange, int lightColor, int lightPrio) +{ + auto const s = &sprite[spriteNum]; + + if (videoGetRenderMode() != REND_POLYMER || pr_lighting != 1) + return; + + if (gPolymerLight[spriteNum].lightptr == NULL) + { +#pragma pack(push, 1) + _prlight mylight; +#pragma pack(pop) + Bmemset(&mylight, 0, sizeof(mylight)); + + mylight.sector = s->sectnum; + mylight.x = s->x; + mylight.y = s->y; + mylight.z = s->z - zOffset; + mylight.color[0] = lightColor & 255; + mylight.color[1] = (lightColor >> 8) & 255; + mylight.color[2] = (lightColor >> 16) & 255; + mylight.radius = lightRadius; + gPolymerLight[spriteNum].lightmaxrange = mylight.range = lightRange; + + mylight.priority = lightPrio; + mylight.tilenum = 0; + + mylight.publicflags.emitshadow = 1; + mylight.publicflags.negative = 0; + + gPolymerLight[spriteNum].lightId = polymer_addlight(&mylight); + if (gPolymerLight[spriteNum].lightId >= 0) + gPolymerLight[spriteNum].lightptr = &prlights[gPolymerLight[spriteNum].lightId]; + return; + } + + s->z -= zOffset; + + if (lightRange> 1) + gPolymerLight[spriteNum].lightmaxrange = 0; + + if (lightRange > gPolymerLight[spriteNum].lightmaxrange || lightPrio != gPolymerLight[spriteNum].lightptr->priority || + Bmemcmp(&sprite[spriteNum], gPolymerLight[spriteNum].lightptr, sizeof(int32_t) * 3)) + { + if (lightRange > gPolymerLight[spriteNum].lightmaxrange) + gPolymerLight[spriteNum].lightmaxrange = lightRange; + + Bmemcpy(gPolymerLight[spriteNum].lightptr, &sprite[spriteNum], sizeof(int32_t) * 3); + gPolymerLight[spriteNum].lightptr->sector = s->sectnum; + gPolymerLight[spriteNum].lightptr->flags.invalidate = 1; + } + + gPolymerLight[spriteNum].lightptr->priority = lightPrio; + gPolymerLight[spriteNum].lightptr->range = lightRange; + gPolymerLight[spriteNum].lightptr->color[0] = lightColor & 255; + gPolymerLight[spriteNum].lightptr->color[1] = (lightColor >> 8) & 255; + gPolymerLight[spriteNum].lightptr->color[2] = (lightColor >> 16) & 255; + + s->z += zOffset; +} + +void actDoLight(int nSprite) +{ + auto const pSprite = &sprite[nSprite]; + int savedFires = 0; + if (((sector[pSprite->sectnum].floorz - sector[pSprite->sectnum].ceilingz) < 16) || pSprite->z > sector[pSprite->sectnum].floorz) + { + if (gPolymerLight[nSprite].lightptr != NULL) + DeleteLight(nSprite); + } + else + { + if (gPolymerLight[nSprite].lightptr != NULL && gPolymerLight[nSprite].lightcount) + { + if (!(--gPolymerLight[nSprite].lightcount)) + DeleteLight(nSprite); + } + + if (pr_lighting != 1) + return; + + switch (pSprite->type) + { + case kMissileTeslaRegular: + { + int32_t x = ((sintable[(pSprite->ang+512)&2047])>>6); + int32_t y = ((sintable[(pSprite->ang)&2047])>>6); + + pSprite->x -= x; + pSprite->y -= y; + + G_AddGameLight(0, nSprite, ((pSprite->yrepeat*tilesiz[pSprite->picnum].y)<<1), 2048, 80+(252<<8)+(120<<16),PR_LIGHT_PRIO_HIGH_GAME); + + pSprite->x += x; + pSprite->y += y; + } + break; + } + } +#if 0 + if (((sector[pSprite->sectnum].floorz - sector[pSprite->sectnum].ceilingz) < 16) || pSprite->z > sector[pSprite->sectnum].floorz || pSprite->z > actor[spriteNum].floorz || + (pSprite->picnum != SECTOREFFECTOR && ((pSprite->cstat & 32768) || pSprite->yrepeat < 4)) || + A_CheckSpriteFlags(spriteNum, SFLAG_NOLIGHT) || (A_CheckSpriteFlags(spriteNum, SFLAG_USEACTIVATOR) && sector[pSprite->sectnum].lotag & 16384)) + { + if (actor[spriteNum].lightptr != NULL) + A_DeleteLight(spriteNum); + } + else + { + if (actor[spriteNum].lightptr != NULL && actor[spriteNum].lightcount) + { + if (!(--actor[spriteNum].lightcount)) + A_DeleteLight(spriteNum); + } + + if (pr_lighting != 1) + return; + +#ifndef EDUKE32_STANDALONE + for (int ii=0; ii<2; ii++) + { + if (pSprite->picnum <= 0) // oob safety + break; + + switch (DYNAMICTILEMAP(pSprite->picnum-1+ii)) + { + case DIPSWITCH__STATIC: + case DIPSWITCH2__STATIC: + case DIPSWITCH3__STATIC: + case PULLSWITCH__STATIC: + case SLOTDOOR__STATIC: + case LIGHTSWITCH__STATIC: + case SPACELIGHTSWITCH__STATIC: + case SPACEDOORSWITCH__STATIC: + case FRANKENSTINESWITCH__STATIC: + case POWERSWITCH1__STATIC: + case LOCKSWITCH1__STATIC: + case POWERSWITCH2__STATIC: + case TECHSWITCH__STATIC: + case ACCESSSWITCH__STATIC: + case ACCESSSWITCH2__STATIC: + { + if ((pSprite->cstat & 32768) || A_CheckSpriteFlags(spriteNum, SFLAG_NOLIGHT)) + { + if (actor[spriteNum].lightptr != NULL) + A_DeleteLight(spriteNum); + break; + } + + vec2_t const d = { sintable[(pSprite->ang+512)&2047]>>7, sintable[(pSprite->ang)&2047]>>7 }; + + pSprite->x += d.x; + pSprite->y += d.y; + + int16_t sectnum = pSprite->sectnum; + updatesector(pSprite->x, pSprite->y, §num); + + if ((unsigned) sectnum >= MAXSECTORS || pSprite->z > sector[sectnum].floorz || pSprite->z < sector[sectnum].ceilingz) + goto POOP; + + G_AddGameLight(0, spriteNum, (pSprite->yrepeat*tilesiz[pSprite->picnum].y)<<1, 512-ii*128, + ii==0 ? (172+(200<<8)+(104<<16)) : 216+(52<<8)+(20<<16), PR_LIGHT_PRIO_LOW); + + POOP: + pSprite->x -= d.x; + pSprite->y -= d.y; + } + break; + } + } + + switch (DYNAMICTILEMAP(pSprite->picnum)) + { + case ATOMICHEALTH__STATIC: + G_AddGameLight(0, spriteNum, ((pSprite->yrepeat*tilesiz[pSprite->picnum].y)<<1), LIGHTRAD2(spriteNum, pSprite), 128+(128<<8)+(255<<16),PR_LIGHT_PRIO_HIGH_GAME); + break; + + case FIRE__STATIC: + case FIRE2__STATIC: + case BURNING__STATIC: + case BURNING2__STATIC: + { + uint32_t color; + int32_t jj; + + static int32_t savedfires[32][4]; // sectnum x y z + + /* + if (Actor[i].floorz - Actor[i].ceilingz < 128) break; + if (s->z > Actor[i].floorz+2048) break; + */ + + switch (pSprite->pal) + { + case 1: color = 128+(128<<8)+(255<<16); break; + case 2: color = 255+(48<<8)+(48<<16); break; + case 8: color = 48+(255<<8)+(48<<16); break; + default: color = 240+(160<<8)+(80<<16); break; + } + + for (jj=savedFires-1; jj>=0; jj--) + if (savedfires[jj][0]==pSprite->sectnum && savedfires[jj][1]==(pSprite->x>>3) && + savedfires[jj][2]==(pSprite->y>>3) && savedfires[jj][3]==(pSprite->z>>7)) + break; + + if (jj==-1 && savedFires<32) + { + jj = savedFires; + G_AddGameLight(0, spriteNum, ((pSprite->yrepeat*tilesiz[pSprite->picnum].y)<<1), LIGHTRAD2(spriteNum, pSprite), color, PR_LIGHT_PRIO_HIGH_GAME); + savedfires[jj][0] = pSprite->sectnum; + savedfires[jj][1] = pSprite->x>>3; + savedfires[jj][2] = pSprite->y>>3; + savedfires[jj][3] = pSprite->z>>7; + savedFires++; + } + } + break; + + case OOZFILTER__STATIC: + if (pSprite->xrepeat > 4) + G_AddGameLight(0, spriteNum, ((pSprite->yrepeat*tilesiz[pSprite->picnum].y)<<1), 4096, 176+(252<<8)+(120<<16),PR_LIGHT_PRIO_HIGH_GAME); + break; + case FLOORFLAME__STATIC: + case FIREBARREL__STATIC: + case FIREVASE__STATIC: + G_AddGameLight(0, spriteNum, ((pSprite->yrepeat*tilesiz[pSprite->picnum].y)<<2), LIGHTRAD2(spriteNum, pSprite)>>1, 255+(95<<8),PR_LIGHT_PRIO_HIGH_GAME); + break; + + case EXPLOSION2__STATIC: + if (!actor[spriteNum].lightcount) + { + // XXX: This block gets CODEDUP'd too much. + int32_t x = ((sintable[(pSprite->ang+512)&2047])>>6); + int32_t y = ((sintable[(pSprite->ang)&2047])>>6); + + pSprite->x -= x; + pSprite->y -= y; + + G_AddGameLight(0, spriteNum, ((pSprite->yrepeat*tilesiz[pSprite->picnum].y)<<1), LIGHTRAD(spriteNum, pSprite), 240+(160<<8)+(80<<16), + pSprite->yrepeat > 32 ? PR_LIGHT_PRIO_HIGH_GAME : PR_LIGHT_PRIO_LOW_GAME); + + pSprite->x += x; + pSprite->y += y; + } + break; + case FORCERIPPLE__STATIC: + case TRANSPORTERBEAM__STATIC: + G_AddGameLight(0, spriteNum, ((pSprite->yrepeat*tilesiz[pSprite->picnum].y)<<1), LIGHTRAD(spriteNum, pSprite), 80+(80<<8)+(255<<16),PR_LIGHT_PRIO_LOW_GAME); + break; + case GROWSPARK__STATIC: + { + int32_t x = ((sintable[(pSprite->ang+512)&2047])>>6); + int32_t y = ((sintable[(pSprite->ang)&2047])>>6); + + pSprite->x -= x; + pSprite->y -= y; + + G_AddGameLight(0, spriteNum, ((pSprite->yrepeat*tilesiz[pSprite->picnum].y)<<1), 1024, 216+(52<<8)+(20<<16),PR_LIGHT_PRIO_HIGH_GAME); + + pSprite->x += x; + pSprite->y += y; + } + break; + case SHRINKEREXPLOSION__STATIC: + { + int32_t x = ((sintable[(pSprite->ang+512)&2047])>>6); + int32_t y = ((sintable[(pSprite->ang)&2047])>>6); + + pSprite->x -= x; + pSprite->y -= y; + + G_AddGameLight(0, spriteNum, ((pSprite->yrepeat*tilesiz[pSprite->picnum].y)<<1), 2048, 176+(252<<8)+(120<<16),PR_LIGHT_PRIO_HIGH_GAME); + + pSprite->x += x; + pSprite->y += y; + } + break; + case FREEZEBLAST__STATIC: + G_AddGameLight(0, spriteNum, ((pSprite->yrepeat*tilesiz[pSprite->picnum].y)<<1), LIGHTRAD(spriteNum, pSprite)<<2, 72+(88<<8)+(140<<16),PR_LIGHT_PRIO_HIGH_GAME); + break; + case COOLEXPLOSION1__STATIC: + G_AddGameLight(0, spriteNum, ((pSprite->yrepeat*tilesiz[pSprite->picnum].y)<<1), LIGHTRAD(spriteNum, pSprite)<<2, 128+(0<<8)+(255<<16),PR_LIGHT_PRIO_HIGH_GAME); + break; + case SHRINKSPARK__STATIC: + G_AddGameLight(0, spriteNum, ((pSprite->yrepeat*tilesiz[pSprite->picnum].y)<<1), LIGHTRAD(spriteNum, pSprite), 176+(252<<8)+(120<<16),PR_LIGHT_PRIO_HIGH_GAME); + break; + case FIRELASER__STATIC: + if (pSprite->statnum == STAT_PROJECTILE) + G_AddGameLight(0, spriteNum, ((pSprite->yrepeat*tilesiz[pSprite->picnum].y)<<1), 64 * pSprite->yrepeat, 255+(95<<8),PR_LIGHT_PRIO_LOW_GAME); + break; + case RPG__STATIC: + G_AddGameLight(0, spriteNum, ((pSprite->yrepeat*tilesiz[pSprite->picnum].y)<<1), 128 * pSprite->yrepeat, 255+(95<<8),PR_LIGHT_PRIO_LOW_GAME); + break; + case SHOTSPARK1__STATIC: + if (actor[spriteNum].t_data[2] == 0) // check for first frame of action + { + int32_t x = ((sintable[(pSprite->ang+512)&2047])>>7); + int32_t y = ((sintable[(pSprite->ang)&2047])>>7); + + pSprite->x -= x; + pSprite->y -= y; + + G_AddGameLight(0, spriteNum, ((pSprite->yrepeat*tilesiz[pSprite->picnum].y)<<1), 8 * pSprite->yrepeat, 240+(160<<8)+(80<<16),PR_LIGHT_PRIO_LOW_GAME); + actor[spriteNum].lightcount = 1; + + pSprite->x += x; + pSprite->y += y; + } + break; + } +#endif + } +#endif +} +#endif // POLYMER END_BLD_NS diff --git a/source/blood/src/actor.h b/source/blood/src/actor.h index d3163b508..8426bcb5b 100644 --- a/source/blood/src/actor.h +++ b/source/blood/src/actor.h @@ -200,6 +200,10 @@ extern int gDudeDrag; extern short gAffectedSectors[kMaxSectors]; extern short gAffectedXWalls[kMaxXWalls]; +#ifdef POLYMER +extern +#endif + inline bool IsPlayerSprite(spritetype *pSprite) { if (pSprite->type >= kDudePlayer1 && pSprite->type <= kDudePlayer8) @@ -220,6 +224,11 @@ inline void actBurnSprite(int nSource, XSPRITE *pXSprite, int nTime) pXSprite->burnSource = nSource; } +#ifdef POLYMER +void actAddGameLight(int lightRadius, int spriteNum, int zOffset, int lightRange, int lightColor, int lightPrio); +void actDoLight(int spriteNum); +#endif + bool IsItemSprite(spritetype *pSprite); bool IsWeaponSprite(spritetype *pSprite); bool IsAmmoSprite(spritetype *pSprite); diff --git a/source/blood/src/blood.cpp b/source/blood/src/blood.cpp index c9f2a5505..5eeb81201 100644 --- a/source/blood/src/blood.cpp +++ b/source/blood/src/blood.cpp @@ -160,11 +160,6 @@ enum gametokens int blood_globalflags; -void G_Polymer_UnInit(void) -{ - // NUKE-TODO: -} - void ShutDown(void) { if (!in3dmode()) @@ -478,6 +473,29 @@ void G_LoadMapHack(char* outbuf, const char* filename) } } +#ifdef POLYMER +void G_RefreshLights(void) +{ + if (Numsprites && videoGetRenderMode() == REND_POLYMER) + { + int statNum = 0; + + do + { + int spriteNum = headspritestat[statNum++]; + + while (spriteNum >= 0) + { + actDoLight(spriteNum); + spriteNum = nextspritestat[spriteNum]; + } + } + while (statNum < MAXSTATUS); + } +} +#endif // POLYMER + + PLAYER gPlayerTemp[kMaxPlayers]; int gHealthTemp[kMaxPlayers]; @@ -917,6 +935,9 @@ void ProcessFrame(void) DoSectorPanning(); actProcessSprites(); actPostProcess(); +#ifdef POLYMER + G_RefreshLights(); +#endif viewCorrectPrediction(); ambProcess(); viewUpdateDelirium(); diff --git a/source/blood/src/db.cpp b/source/blood/src/db.cpp index 190c7d786..502b62142 100644 --- a/source/blood/src/db.cpp +++ b/source/blood/src/db.cpp @@ -46,6 +46,10 @@ SPRITEHIT gSpriteHit[kMaxXSprites]; int xvel[kMaxSprites], yvel[kMaxSprites], zvel[kMaxSprites]; +#ifdef POLYMER +PolymerLight_t gPolymerLight[kMaxSprites]; +#endif + char qsprite_filler[kMaxSprites], qsector_filler[kMaxSectors]; int gVisibility; @@ -60,6 +64,27 @@ void dbCrypt(char *pPtr, int nLength, int nKey) } } +#ifdef POLYMER + +void DeleteLight(int32_t s) +{ + if (gPolymerLight[s].lightId >= 0) + polymer_deletelight(gPolymerLight[s].lightId); + gPolymerLight[s].lightId = -1; + gPolymerLight[s].lightptr = NULL; +} + + +void G_Polymer_UnInit(void) +{ + int32_t i; + + for (i = 0; i < kMaxSprites; i++) + DeleteLight(i); +} +#endif + + void InsertSpriteSect(int nSprite, int nSector) { dassert(nSprite >= 0 && nSprite < kMaxSprites); @@ -190,6 +215,10 @@ int InsertSprite(int nSector, int nStat) pSprite->index = nSprite; xvel[nSprite] = yvel[nSprite] = zvel[nSprite] = 0; +#ifdef POLYMER + gPolymerLight[nSprite].lightId = -1; +#endif + Numsprites++; return nSprite; @@ -202,6 +231,10 @@ int qinsertsprite(short nSector, short nStat) // Replace int DeleteSprite(int nSprite) { +#ifdef POLYMER + if (gPolymerLight[nSprite].lightptr != NULL && videoGetRenderMode() == REND_POLYMER) + DeleteLight(nSprite); +#endif if (sprite[nSprite].extra > 0) { dbDeleteXSprite(sprite[nSprite].extra); diff --git a/source/blood/src/db.h b/source/blood/src/db.h index d0f48c50f..6cd060aa9 100644 --- a/source/blood/src/db.h +++ b/source/blood/src/db.h @@ -324,6 +324,21 @@ template void GetSpriteExtents(T *pSprite, int *top, int *bottom) } } +#ifdef POLYMER +#pragma pack(push, 1) +struct PolymerLight_t { + int16_t lightId, lightmaxrange; + _prlight* lightptr; + uint8_t lightcount; +}; +#pragma pack(pop) + +extern PolymerLight_t gPolymerLight[kMaxSprites]; + +void DeleteLight(int32_t s); + +#endif + void InsertSpriteSect(int nSprite, int nSector); void RemoveSpriteSect(int nSprite); void InsertSpriteStat(int nSprite, int nStat); diff --git a/source/blood/src/loadsave.cpp b/source/blood/src/loadsave.cpp index 085afc05f..5ba194d5c 100644 --- a/source/blood/src/loadsave.cpp +++ b/source/blood/src/loadsave.cpp @@ -176,6 +176,31 @@ bool GameInterface::LoadGame(FSaveGameNode* node) gPaused = 0; gGameStarted = 1; bVanilla = false; + + +#ifdef USE_STRUCT_TRACKERS + Bmemset(sectorchanged, 0, sizeof(sectorchanged)); + Bmemset(spritechanged, 0, sizeof(spritechanged)); + Bmemset(wallchanged, 0, sizeof(wallchanged)); +#endif + +#ifdef USE_OPENGL + Polymost_prepare_loadboard(); +#endif + +#ifdef POLYMER + if (videoGetRenderMode() == REND_POLYMER) + polymer_loadboard(); + + // this light pointer nulling needs to be outside the videoGetRenderMode check + // because we might be loading the savegame using another renderer but + // change to Polymer later + for (int i=0; i