static void parseSector(FScanner &sc, TMap<int, EDSector> &EDSectors) { EDSector sec; memset(&sec, 0, sizeof(sec)); sec.Overlayalpha[sector_t::floor] = sec.Overlayalpha[sector_t::ceiling] = 1.; sec.floorterrain = sec.ceilingterrain = -1; sc.MustGetStringName("{"); while (!sc.CheckString("}")) { sc.MustGetString(); if (sc.Compare("recordnum")) { sc.CheckString("="); sc.MustGetNumber(); sec.recordnum = sc.Number; } else if (sc.Compare("flags")) { uint32_t *flagvar = nullptr; if (sc.CheckString(".")) { sc.MustGetString(); if (sc.Compare("add")) { flagvar = &sec.flagsAdd; } else if (sc.Compare("remove")) { flagvar = &sec.flagsRemove; } else { sc.ScriptError("Invalid property 'flags.%s'", sc.String); } } else { sec.flagsSet = true; flagvar = &sec.flags; } sc.CheckString("="); do { sc.MustGetString(); for (const char *tok = strtok(sc.String, ",+ \t"); tok != nullptr; tok = strtok(nullptr, ",+ \t")) { if (!stricmp(tok, "SECRET")) *flagvar |= SECF_SECRET | SECF_WASSECRET; else if (!stricmp(tok, "FRICTION")) *flagvar |= SECF_FRICTION; else if (!stricmp(tok, "PUSH")) *flagvar |= SECF_PUSH; else if (!stricmp(tok, "KILLSOUND")) *flagvar |= SECF_SILENT; else if (!stricmp(tok, "KILLMOVESOUND")) *flagvar |= SECF_SILENTMOVE; else sc.ScriptError("Unknown option '%s'", tok); } } while (sc.CheckString("|")); // Unquoted strings with '|' separator - parse as a separate string in the loop. } else if (sc.Compare("damage")) { sc.CheckString("="); sc.MustGetNumber(); sec.damageamount = sc.Number; } else if (sc.Compare("damagemod")) { sc.CheckString("="); sc.MustGetString(); sec.damagetype = sc.String; } else if (sc.Compare("damagemask")) { sc.CheckString("="); sc.MustGetNumber(); sec.damageinterval = sc.Number; } else if (sc.Compare("damageflags")) { uint32_t *flagvar = nullptr; uint8_t *leakvar = nullptr; if (sc.CheckString(".")) { sc.MustGetString(); if (sc.Compare("add")) { flagvar = &sec.damageflagsAdd; leakvar = &sec.leakyadd; } else if (sc.Compare("remove")) { flagvar = &sec.damageflagsRemove; leakvar = &sec.leakyremove; } else { sc.ScriptError("Invalid property 'flags.%s'", sc.String); } } else { sec.damageflagsSet = true; flagvar = &sec.damageflags; leakvar = &sec.leaky; } sc.CheckString("="); do { sc.MustGetString(); for (const char *tok = strtok(sc.String, ",+ \t"); tok != nullptr; tok = strtok(nullptr, ",+ \t")) { if (!stricmp(tok, "LEAKYSUIT")) *leakvar |= 1; else if (!stricmp(tok, "IGNORESUIT")) *leakvar |= 2; // these 2 bits will be used to set 'leakychance', but this can only be done when the sector gets initialized else if (!stricmp(tok, "ENDGODMODE")) *flagvar |= SECF_ENDGODMODE; else if (!stricmp(tok, "ENDLEVEL")) *flagvar |= SECF_ENDLEVEL; else if (!stricmp(tok, "TERRAINHIT")) *flagvar |= SECF_DMGTERRAINFX; else sc.ScriptError("Unknown option '%s'", tok); } } while (sc.CheckString("|")); // Unquoted strings with '|' separator - parse as a separate string in the loop. } else if (sc.Compare("floorterrain")) { sc.CheckString("="); sc.MustGetString(); sec.floorterrain = P_FindTerrain(sc.String); } else if (sc.Compare("floorangle")) { sc.CheckString("="); sc.MustGetFloat(); sec.angle[sector_t::floor] = sc.Float; } else if (sc.Compare("flooroffsetx")) { sc.CheckString("="); sc.MustGetFloat(); sec.xoffs[sector_t::floor] = sc.Float; } else if (sc.Compare("flooroffsety")) { sc.CheckString("="); sc.MustGetFloat(); sec.yoffs[sector_t::floor] = sc.Float; } else if (sc.Compare("ceilingterrain")) { sc.CheckString("="); sc.MustGetString(); sec.ceilingterrain = P_FindTerrain(sc.String); } else if (sc.Compare("ceilingangle")) { sc.CheckString("="); sc.MustGetFloat(); sec.angle[sector_t::ceiling] = sc.Float; } else if (sc.Compare("ceilingoffsetx")) { sc.CheckString("="); sc.MustGetFloat(); sec.xoffs[sector_t::ceiling] = sc.Float; } else if (sc.Compare("ceilingoffsety")) { sc.CheckString("="); sc.MustGetFloat(); sec.yoffs[sector_t::ceiling] = sc.Float; } else if (sc.Compare("colormaptop") || sc.Compare("colormapbottom")) { sc.CheckString("="); sc.MustGetString(); // these properties are not implemented by ZDoom } else if (sc.Compare("colormapmid")) { sc.CheckString("="); sc.MustGetString(); // Eternity is based on SMMU and uses colormaps differently than all other ports. // The only solution here is to convert the colormap to an RGB value and set it as the sector's color. uint32_t cmap = R_ColormapNumForName(sc.String); if (cmap != 0) { sec.color = R_BlendForColormap(cmap) & 0xff000000; sec.colorSet = true; } } else if (sc.Compare("overlayalpha")) { sc.MustGetStringName("."); sc.MustGetString(); if (sc.Compare("floor")) { sc.MustGetNumber(); if (sc.CheckString("%")) sc.Float = sc.Number / 100.f; else sc.Float = sc.Number / 255.f; sec.Overlayalpha[sector_t::floor] = sc.Float; } else if (sc.Compare("ceiling")) { sc.MustGetFloat(); if (sc.CheckString("%")) sc.Float = sc.Number / 100.f; else sc.Float = sc.Number / 255.f; sec.Overlayalpha[sector_t::floor] = sc.Float; } } else if (sc.Compare("portalflags")) { int dest = 0; sc.MustGetStringName("."); sc.MustGetString(); if (sc.Compare("floor")) dest = sector_t::floor; else if (sc.Compare("ceiling")) dest = sector_t::ceiling; else sc.ScriptError("Unknown portal type '%s'", sc.String); sc.CheckString("="); do { sc.MustGetString(); for (const char *tok = strtok(sc.String, ",+ \t"); tok != nullptr; tok = strtok(nullptr, ",+ \t")) { if (!stricmp(tok, "DISABLED")) sec.portalflags[dest] |= PLANEF_DISABLED; else if (!stricmp(tok, "NORENDER")) sec.portalflags[dest] |= PLANEF_NORENDER; else if (!stricmp(tok, "NOPASS")) sec.portalflags[dest] |= PLANEF_NOPASS; else if (!stricmp(tok, "BLOCKSOUND")) sec.portalflags[dest] |= PLANEF_BLOCKSOUND; else if (!stricmp(tok, "OVERLAY")) sec.portalflags[dest] |= 0; // we do not use this. Alpha is the sole determinant for overlay drawing else if (!stricmp(tok, "ADDITIVE")) sec.portalflags[dest] |= PLANEF_ADDITIVE; else if (!stricmp(tok, "USEGLOBALTEX")) {} // not implemented else sc.ScriptError("Unknown option '%s'", tok); } } while (sc.CheckString("|")); // Unquoted strings with '|' separator - parse as a separate string in the loop. } else { sc.ScriptError("Unknown property '%s'", sc.String); } } EDSectors[sec.recordnum] = sec; }
//========================================================================== // // Draws a blend over the entire view // //========================================================================== void FGLRenderer::DrawBlend(sector_t * viewsector) { float blend[4]={0,0,0,0}; PalEntry blendv=0; float extra_red; float extra_green; float extra_blue; player_t *player = NULL; if (players[consoleplayer].camera != NULL) { player=players[consoleplayer].camera->player; } // don't draw sector based blends when an invulnerability colormap is active if (!gl_fixedcolormap) { if (!viewsector->e->XFloor.ffloors.Size()) { if (viewsector->heightsec && !(viewsector->MoreFlags&SECF_IGNOREHEIGHTSEC)) { switch (in_area) { default: case area_normal: blendv = viewsector->heightsec->midmap; break; case area_above: blendv = viewsector->heightsec->topmap; break; case area_below: blendv = viewsector->heightsec->bottommap; break; } } } else { TArray<lightlist_t> & lightlist = viewsector->e->XFloor.lightlist; for (unsigned int i = 0; i < lightlist.Size(); i++) { double lightbottom; if (i < lightlist.Size() - 1) lightbottom = lightlist[i + 1].plane.ZatPoint(ViewPos); else lightbottom = viewsector->floorplane.ZatPoint(ViewPos); if (lightbottom < ViewPos.Z && (!lightlist[i].caster || !(lightlist[i].caster->flags&FF_FADEWALLS))) { // 3d floor 'fog' is rendered as a blending value blendv = lightlist[i].blend; // If this is the same as the sector's it doesn't apply! if (blendv == viewsector->ColorMap->Fade) blendv = 0; // a little hack to make this work for Legacy maps. if (blendv.a == 0 && blendv != 0) blendv.a = 128; break; } } } if (blendv.a == 0) { blendv = R_BlendForColormap(blendv); if (blendv.a == 255) { // The calculated average is too dark so brighten it according to the palettes's overall brightness int maxcol = MAX<int>(MAX<int>(framebuffer->palette_brightness, blendv.r), MAX<int>(blendv.g, blendv.b)); blendv.r = blendv.r * 255 / maxcol; blendv.g = blendv.g * 255 / maxcol; blendv.b = blendv.b * 255 / maxcol; } } if (blendv.a == 255) { extra_red = blendv.r / 255.0f; extra_green = blendv.g / 255.0f; extra_blue = blendv.b / 255.0f; // If this is a multiplicative blend do it separately and add the additive ones on top of it. blendv = 0; // black multiplicative blends are ignored if (extra_red || extra_green || extra_blue) { gl_RenderState.BlendFunc(GL_DST_COLOR, GL_ZERO); gl_RenderState.SetColor(extra_red, extra_green, extra_blue, 1.0f); gl_FillScreen(); } } else if (blendv.a) { // [Nash] allow user to set blend intensity int cnt = blendv.a; cnt = (int)(cnt * underwater_fade_scalar); V_AddBlend(blendv.r / 255.f, blendv.g / 255.f, blendv.b / 255.f, cnt / 255.0f, blend); } } // This mostly duplicates the code in shared_sbar.cpp // When I was writing this the original was called too late so that I // couldn't get the blend in time. However, since then I made some changes // here that would get lost if I switched back so I won't do it. if (player) { V_AddPlayerBlend(player, blend, 0.5, 175); } if (players[consoleplayer].camera != NULL) { // except for fadeto effects player_t *player = (players[consoleplayer].camera->player != NULL) ? players[consoleplayer].camera->player : &players[consoleplayer]; V_AddBlend (player->BlendR, player->BlendG, player->BlendB, player->BlendA, blend); } gl_RenderState.SetTextureMode(TM_MODULATE); gl_RenderState.BlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA); if (blend[3]>0.0f) { gl_RenderState.SetColor(blend[0], blend[1], blend[2], blend[3]); gl_FillScreen(); } gl_RenderState.ResetColor(); gl_RenderState.EnableTexture(true); }