void gl_RenderMissingLines() { for(int i=firstmissingseg;i<numsegs;i++) { seg_t * seg = &segs[i]; // This line has already been processed if (seg->linedef->validcount==validcount) continue; // Don't draw lines facing away from the viewer divline_t dl = { seg->v1->x, seg->v1->y, seg->v2->x-seg->v1->x, seg->v2->y-seg->v1->y }; if (P_PointOnDivlineSide(viewx, viewy, &dl)) continue; // Unfortunately there is no simple means to exclude lines here so we have // to draw them all. sector_t ffakesec, bfakesec; sector_t * sector = gl_FakeFlat(seg->frontsector, &ffakesec, false); sector_t * backsector; if (seg->frontsector == seg->backsector) backsector=sector; else if (!seg->backsector) backsector=NULL; else backsector = gl_FakeFlat(seg->backsector, &bfakesec, true); GLWall wall; SetupWall.Start(true); wall.Process(seg, sector, backsector, NULL); rendered_lines++; SetupWall.Stop(true); } }
static void DoSubsector(subsector_t * sub) { int i; sector_t * sector; sector_t * fakesector; sector_t fake; GLFlat glflat; GLSprite glsprite; // check for visibility of this entire subsector! This requires GL nodes! if (!clipper.CheckBox(sub->bbox)) return; #ifdef _MSC_VER #ifdef _DEBUG if (sub->sector-sectors==931) { __asm nop } #endif #endif sector=sub->sector; if (!sector) return; sector->MoreFlags |= SECF_DRAWN; fakesector=gl_FakeFlat(sector, &fake, false); // [RH] Add particles //int shade = LIGHT2SHADE((floorlightlevel + ceilinglightlevel)/2 + r_actualextralight); for (i = ParticlesInSubsec[sub-subsectors]; i != NO_PARTICLE; i = Particles[i].snext) { glsprite.ProcessParticle(Particles + i, fakesector);//, 0, 0); } AddLines(sub, fakesector); RenderThings(sub, fakesector); // Subsectors with only 2 lines cannot have any area! if (sub->numlines>2 || (sub->hacked&1)) { // Exclude the case when it tries to render a sector with a heightsec // but undetermined heightsec state. This can only happen if the // subsector is obstructed but not excluded due to a large bounding box. // Due to the way a BSP works such a subsector can never be visible if (!sector->heightsec || sector->heightsec->MoreFlags & SECF_IGNOREHEIGHTSEC || in_area!=area_default) { if (sector != sub->render_sector) { sector = sub->render_sector; // the planes of this subsector are faked to belong to another sector // This means we need the heightsec parts and light info of the render sector, not the actual one! fakesector = gl_FakeFlat(sector, &fake, false); } SetupFlat.Clock(); glflat.ProcessSector(fakesector, sub); SetupFlat.Unclock(); } } }
void FDrawInfo::FloodLowerGap(seg_t * seg) { wallseg ws; sector_t ffake, bfake; sector_t * fakefsector = gl_FakeFlat(seg->frontsector, &ffake, true); sector_t * fakebsector = gl_FakeFlat(seg->backsector, &bfake, false); vertex_t * v1, * v2; // Although the plane can be sloped this code will only be called // when the edge itself is not. fixed_t backz = fakebsector->floorplane.ZatPoint(seg->v1); fixed_t frontz = fakefsector->floorplane.ZatPoint(seg->v1); if (fakebsector->GetTexture(sector_t::floor) == skyflatnum) return; if (fakebsector->GetPlaneTexZ(sector_t::floor) > viewz) return; if (seg->sidedef == seg->linedef->sidedef[0]) { v1=seg->linedef->v1; v2=seg->linedef->v2; } else { v1=seg->linedef->v2; v2=seg->linedef->v1; } ws.x1= FIXED2FLOAT(v1->x); ws.y1= FIXED2FLOAT(v1->y); ws.x2= FIXED2FLOAT(v2->x); ws.y2= FIXED2FLOAT(v2->y); ws.z2= FIXED2FLOAT(frontz); ws.z1= FIXED2FLOAT(backz); // Step1: Draw a stencil into the gap SetupFloodStencil(&ws); // Step2: Project the ceiling plane into the gap DrawFloodedPlane(&ws, ws.z1, fakebsector, false); // Step3: Delete the stencil ClearFloodStencil(&ws); }
void FDrawInfo::FloodUpperGap(seg_t * seg) { wallseg ws; sector_t ffake, bfake; sector_t * fakefsector = gl_FakeFlat(seg->frontsector, &ffake, true); sector_t * fakebsector = gl_FakeFlat(seg->backsector, &bfake, false); vertex_t * v1, * v2; // Although the plane can be sloped this code will only be called // when the edge itself is not. double backz = fakebsector->ceilingplane.ZatPoint(seg->v1); double frontz = fakefsector->ceilingplane.ZatPoint(seg->v1); if (fakebsector->GetTexture(sector_t::ceiling)==skyflatnum) return; if (backz < ViewPos.Z) return; if (seg->sidedef == seg->linedef->sidedef[0]) { v1=seg->linedef->v1; v2=seg->linedef->v2; } else { v1=seg->linedef->v2; v2=seg->linedef->v1; } ws.x1 = v1->fX(); ws.y1 = v1->fY(); ws.x2 = v2->fX(); ws.y2 = v2->fY(); ws.z1= frontz; ws.z2= backz; // Step1: Draw a stencil into the gap SetupFloodStencil(&ws); // Step2: Project the ceiling plane into the gap DrawFloodedPlane(&ws, ws.z2, fakebsector, true); // Step3: Delete the stencil ClearFloodStencil(&ws); }
sector_t *FGLInterface::FakeFlat(sector_t *sec, sector_t *tempsec, int *floorlightlevel, int *ceilinglightlevel, bool back) { if (floorlightlevel != NULL) { *floorlightlevel = sec->GetFloorLight (); } if (ceilinglightlevel != NULL) { *ceilinglightlevel = sec->GetCeilingLight (); } return gl_FakeFlat(sec, tempsec, back); }
//========================================================================== // // // //========================================================================== bool FDrawInfo::DoOneSectorLower(subsector_t * subsec, fixed_t planez) { // Is there a one-sided wall in this subsector? // Do this first to avoid unnecessary recursion for(DWORD i=0; i< subsec->numlines; i++) { if (subsec->firstline[i].backsector == NULL) return false; if (subsec->firstline[i].PartnerSeg == NULL) return false; } for(DWORD i=0; i< subsec->numlines; i++) { seg_t * seg = subsec->firstline + i; subsector_t * backsub = seg->PartnerSeg->Subsector; // already checked? if (backsub->validcount == validcount) continue; backsub->validcount=validcount; if (seg->frontsector != seg->backsector && seg->linedef) { // Note: if this is a real line between sectors // we can be sure that render_sector is the real sector! sector_t * sec = gl_FakeFlat(seg->backsector, &fakesec, true); // Don't bother with slopes if (sec->floorplane.a!=0 || sec->floorplane.b!=0) return false; // Is the neighboring floor higher than the desired height? if (sec->GetPlaneTexZ(sector_t::floor)>planez) { // todo: check for missing textures. return false; } // This is an exact height match which means we don't have to do any further checks for this sector if (sec->GetPlaneTexZ(sector_t::floor)==planez) { // If there's a texture abort FTexture * tex = TexMan[seg->sidedef->GetTexture(side_t::bottom)]; if (!tex || tex->UseType==FTexture::TEX_Null) continue; else return false; } } if (!DoOneSectorLower(backsub, planez)) return false; } // all checked ok. This sector is part of the current fake plane HandledSubsectors.Push(subsec); return 1; }
//========================================================================== // // // //========================================================================== bool FDrawInfo::DoFakeCeilingBridge(subsector_t * subsec, fixed_t planez) { // Is there a one-sided wall in this sector? // Do this first to avoid unnecessary recursion for(DWORD i=0; i< subsec->numlines; i++) { if (subsec->firstline[i].backsector == NULL) return false; if (subsec->firstline[i].PartnerSeg == NULL) return false; } for(DWORD i=0; i< subsec->numlines; i++) { seg_t * seg = subsec->firstline + i; subsector_t * backsub = seg->PartnerSeg->Subsector; // already checked? if (backsub->validcount == validcount) continue; backsub->validcount=validcount; if (seg->frontsector != seg->backsector && seg->linedef) { // Note: if this is a real line between sectors // we can be sure that render_sector is the real sector! sector_t * sec = gl_FakeFlat(seg->backsector, &fakesec, true); // Don't bother with slopes if (sec->ceilingplane.a!=0 || sec->ceilingplane.b!=0) return false; // Is the neighboring ceiling higher than the desired height? if (sec->GetPlaneTexZ(sector_t::ceiling)>planez) { // todo: check for missing textures. return false; } // This is an exact height match which means we don't have to do any further checks for this sector // No texture checks though! if (sec->GetPlaneTexZ(sector_t::ceiling)==planez) continue; } if (!DoFakeCeilingBridge(backsub, planez)) return false; } // all checked ok. This sector is part of the current fake plane HandledSubsectors.Push(subsec); return 1; }
void FDrawInfo::CollectSectorStacksCeiling(subsector_t * sub, sector_t * anchor) { sector_t fake; // mark it checked sub->validcount=validcount; // Has a sector stack or skybox itself! if (sub->render_sector->CeilingSkyBox && sub->render_sector->CeilingSkyBox->bAlways) return; // Don't bother processing unrendered subsectors if (sub->numlines>2 && !(ss_renderflags[DWORD(sub-subsectors)]&SSRF_PROCESSED)) return; // Must be the exact same visplane sector_t * me = gl_FakeFlat(sub->render_sector, &fake, false); if (me->GetTexture(sector_t::ceiling) != anchor->GetTexture(sector_t::ceiling) || me->ceilingplane != anchor->ceilingplane || GetCeilingLight(me) != GetCeilingLight(anchor) || me->ColorMap != anchor->ColorMap || me->GetXOffset(sector_t::ceiling) != anchor->GetXOffset(sector_t::ceiling) || me->GetYOffset(sector_t::ceiling) != anchor->GetYOffset(sector_t::ceiling) || me->GetXScale(sector_t::ceiling) != anchor->GetXScale(sector_t::ceiling) || me->GetYScale(sector_t::ceiling) != anchor->GetYScale(sector_t::ceiling) || me->GetAngle(sector_t::ceiling) != anchor->GetAngle(sector_t::ceiling)) { // different visplane so it can't belong to this stack return; } HandledSubsectors.Push (sub); for(DWORD j=0; j<sub->numlines; j++) { seg_t * seg = sub->firstline + j; if (seg->PartnerSeg) { subsector_t * backsub = seg->PartnerSeg->Subsector; if (backsub->validcount!=validcount) CollectSectorStacksCeiling (backsub, anchor); } } }
//========================================================================== // // Draws the fake planes // //========================================================================== void FDrawInfo::HandleMissingTextures() { sector_t fake; totalms.Clock(); totalupper=MissingUpperTextures.Size(); totallower=MissingLowerTextures.Size(); for(unsigned int i=0; i<MissingUpperTextures.Size(); i++) { if (!MissingUpperTextures[i].seg) continue; HandledSubsectors.Clear(); validcount++; if (MissingUpperTextures[i].planez > viewz) { // close the hole only if all neighboring sectors are an exact height match // Otherwise just fill in the missing textures. MissingUpperTextures[i].sub->validcount=validcount; if (DoOneSectorUpper(MissingUpperTextures[i].sub, MissingUpperTextures[i].planez)) { sector_t * sec = MissingUpperTextures[i].seg->backsector; // The mere fact that this seg has been added to the list means that the back sector // will be rendered so we can safely assume that it is already in the render list for(unsigned int j=0; j<HandledSubsectors.Size(); j++) { gl_subsectorrendernode * node = SSR_List.GetNew(); node->sub = HandledSubsectors[j]; AddOtherCeilingPlane(sec->sectornum, node); } if (HandledSubsectors.Size()!=1) { // mark all subsectors in the missing list that got processed by this for(unsigned int j=0; j<HandledSubsectors.Size(); j++) { for(unsigned int k=0; k<MissingUpperTextures.Size(); k++) { if (MissingUpperTextures[k].sub==HandledSubsectors[j]) { MissingUpperTextures[k].seg=NULL; } } } } else MissingUpperTextures[i].seg=NULL; continue; } } if (!MissingUpperTextures[i].seg->PartnerSeg) continue; if (!MissingUpperTextures[i].seg->PartnerSeg->Subsector) continue; validcount++; HandledSubsectors.Clear(); { // It isn't a hole. Now check whether it might be a fake bridge sector_t * fakesector = gl_FakeFlat(MissingUpperTextures[i].seg->frontsector, &fake, false); fixed_t planez = fakesector->GetPlaneTexZ(sector_t::ceiling); MissingUpperTextures[i].seg->PartnerSeg->Subsector->validcount=validcount; if (DoFakeCeilingBridge(MissingUpperTextures[i].seg->PartnerSeg->Subsector, planez)) { // The mere fact that this seg has been added to the list means that the back sector // will be rendered so we can safely assume that it is already in the render list for(unsigned int j=0; j<HandledSubsectors.Size(); j++) { gl_subsectorrendernode * node = SSR_List.GetNew(); node->sub = HandledSubsectors[j]; AddOtherCeilingPlane(fakesector->sectornum, node); } } continue; } } for(unsigned int i=0; i<MissingLowerTextures.Size(); i++) { if (!MissingLowerTextures[i].seg) continue; HandledSubsectors.Clear(); validcount++; if (MissingLowerTextures[i].planez < viewz) { // close the hole only if all neighboring sectors are an exact height match // Otherwise just fill in the missing textures. MissingLowerTextures[i].sub->validcount=validcount; if (DoOneSectorLower(MissingLowerTextures[i].sub, MissingLowerTextures[i].planez)) { sector_t * sec = MissingLowerTextures[i].seg->backsector; // The mere fact that this seg has been added to the list means that the back sector // will be rendered so we can safely assume that it is already in the render list for(unsigned int j=0; j<HandledSubsectors.Size(); j++) { gl_subsectorrendernode * node = SSR_List.GetNew(); node->sub = HandledSubsectors[j]; AddOtherFloorPlane(sec->sectornum, node); } if (HandledSubsectors.Size()!=1) { // mark all subsectors in the missing list that got processed by this for(unsigned int j=0; j<HandledSubsectors.Size(); j++) { for(unsigned int k=0; k<MissingLowerTextures.Size(); k++) { if (MissingLowerTextures[k].sub==HandledSubsectors[j]) { MissingLowerTextures[k].seg=NULL; } } } } else MissingLowerTextures[i].seg=NULL; continue; } } if (!MissingLowerTextures[i].seg->PartnerSeg) continue; if (!MissingLowerTextures[i].seg->PartnerSeg->Subsector) continue; validcount++; HandledSubsectors.Clear(); { // It isn't a hole. Now check whether it might be a fake bridge sector_t * fakesector = gl_FakeFlat(MissingLowerTextures[i].seg->frontsector, &fake, false); fixed_t planez = fakesector->GetPlaneTexZ(sector_t::floor); MissingLowerTextures[i].seg->PartnerSeg->Subsector->validcount=validcount; if (DoFakeBridge(MissingLowerTextures[i].seg->PartnerSeg->Subsector, planez)) { // The mere fact that this seg has been added to the list means that the back sector // will be rendered so we can safely assume that it is already in the render list for(unsigned int j=0; j<HandledSubsectors.Size(); j++) { gl_subsectorrendernode * node = SSR_List.GetNew(); node->sub = HandledSubsectors[j]; AddOtherFloorPlane(fakesector->sectornum, node); } } continue; } } totalms.Unclock(); showtotalms=totalms; totalms.Reset(); }
void FDrawInfo::ProcessSectorStacks() { unsigned int i; sector_t fake; validcount++; for (i=0;i<CeilingStacks.Size (); i++) { sector_t *sec = gl_FakeFlat(CeilingStacks[i], &fake, false); FPortal *portal = sec->portals[sector_t::ceiling]; if (portal != NULL) for(int k=0;k<sec->subsectorcount;k++) { subsector_t * sub = sec->subsectors[k]; if (ss_renderflags[sub-subsectors] & SSRF_PROCESSED) { HandledSubsectors.Clear(); for(DWORD j=0;j<sub->numlines;j++) { seg_t * seg = sub->firstline + j; if (seg->PartnerSeg) { subsector_t * backsub = seg->PartnerSeg->Subsector; if (backsub->validcount!=validcount) CollectSectorStacksCeiling (backsub, sec); } } for(unsigned int j=0;j<HandledSubsectors.Size();j++) { subsector_t *sub = HandledSubsectors[j]; ss_renderflags[DWORD(sub-subsectors)] &= ~SSRF_RENDERCEILING; if (sub->portalcoverage[sector_t::ceiling].subsectors == NULL) { gl_BuildPortalCoverage(&sub->portalcoverage[sector_t::ceiling], sub, portal); } portal->GetGLPortal()->AddSubsector(sub); if (sec->GetAlpha(sector_t::ceiling) != 0 && sec->GetTexture(sector_t::ceiling) != skyflatnum) { gl_subsectorrendernode * node = SSR_List.GetNew(); node->sub = sub; AddOtherCeilingPlane(sec->sectornum, node); } } } } } validcount++; for (i=0;i<FloorStacks.Size (); i++) { sector_t *sec = gl_FakeFlat(FloorStacks[i], &fake, false); FPortal *portal = sec->portals[sector_t::floor]; if (portal != NULL) for(int k=0;k<sec->subsectorcount;k++) { subsector_t * sub = sec->subsectors[k]; if (ss_renderflags[sub-subsectors] & SSRF_PROCESSED) { HandledSubsectors.Clear(); for(DWORD j=0;j<sub->numlines;j++) { seg_t * seg = sub->firstline + j; if (seg->PartnerSeg) { subsector_t * backsub = seg->PartnerSeg->Subsector; if (backsub->validcount!=validcount) CollectSectorStacksFloor (backsub, sec); } } for(unsigned int j=0;j<HandledSubsectors.Size();j++) { subsector_t *sub = HandledSubsectors[j]; ss_renderflags[DWORD(sub-subsectors)] &= ~SSRF_RENDERFLOOR; if (sub->portalcoverage[sector_t::floor].subsectors == NULL) { gl_BuildPortalCoverage(&sub->portalcoverage[sector_t::floor], sub, portal); } GLSectorStackPortal *glportal = portal->GetGLPortal(); glportal->AddSubsector(sub); if (sec->GetAlpha(sector_t::floor) != 0 && sec->GetTexture(sector_t::floor) != skyflatnum) { gl_subsectorrendernode * node = SSR_List.GetNew(); node->sub = sub; AddOtherFloorPlane(sec->sectornum, node); } } } } } FloorStacks.Clear(); CeilingStacks.Clear(); }
static void AddLine (seg_t *seg,sector_t * sector,subsector_t * polysub) { angle_t startAngle, endAngle; sector_t * backsector = NULL; sector_t bs; ClipWall.Clock(); if (GLPortal::mirrorline) { // this seg is completely behind the mirror! if (P_PointOnLineSide(seg->v1->x, seg->v1->y, GLPortal::mirrorline) && P_PointOnLineSide(seg->v2->x, seg->v2->y, GLPortal::mirrorline)) { ClipWall.Unclock(); return; } } startAngle = seg->v2->GetViewAngle(); endAngle = seg->v1->GetViewAngle(); // Back side, i.e. backface culling - read: endAngle >= startAngle! if (startAngle-endAngle<ANGLE_180 || !seg->linedef) { ClipWall.Unclock(); return; } if (!clipper.SafeCheckRange(startAngle, endAngle)) { ClipWall.Unclock(); return; } if (!seg->backsector) { clipper.SafeAddClipRange(startAngle, endAngle); } else if (!polysub) // Two-sided polyobjects never obstruct the view { if (sector->sectornum == seg->backsector->sectornum) { FTexture * tex = TexMan(seg->sidedef->GetTexture(side_t::mid)); if (!tex || tex->UseType==FTexture::TEX_Null) { // nothing to do here! ClipWall.Unclock(); seg->linedef->validcount=validcount; return; } backsector=sector; } else { // clipping checks are only needed when the backsector is not the same as the front sector gl_CheckViewArea(seg->v1, seg->v2, seg->frontsector, seg->backsector); backsector = gl_FakeFlat(seg->backsector, &bs, true); if (gl_CheckClip(seg->sidedef, sector, backsector)) { clipper.SafeAddClipRange(startAngle, endAngle); } } } else { // Backsector for polyobj segs is always the containing sector itself backsector = sector; } seg->linedef->flags |= ML_MAPPED; ClipWall.Unclock(); if (!gl_render_segs) { // rendering per linedef as opposed per seg is significantly more efficient // so mark the linedef as rendered here and render it completely. if (seg->linedef->validcount!=validcount) seg->linedef->validcount=validcount; else return; } GLWall wall; SetupWall.Clock(); wall.Process(seg, sector, backsector, polysub, gl_render_segs); rendered_lines++; SetupWall.Unclock(); }
void FGLRenderer::DrawPlayerSprites(sector_t * viewsector, bool hudModelStep) { bool brightflash = false; unsigned int i; int lightlevel=0; FColormap cm; sector_t * fakesec, fs; AActor * playermo=players[consoleplayer].camera; player_t * player=playermo->player; // this is the same as the software renderer if (!player || !r_drawplayersprites || !camera->player || (player->cheats & CF_CHASECAM) || (r_deathcamera && camera->health <= 0)) return; float bobx, boby, wx, wy; DPSprite *weapon; P_BobWeapon(camera->player, &bobx, &boby, r_TicFracF); // Interpolate the main weapon layer once so as to be able to add it to other layers. if ((weapon = camera->player->FindPSprite(PSP_WEAPON)) != nullptr) { if (weapon->firstTic) { wx = weapon->x; wy = weapon->y; } else { wx = weapon->oldx + (weapon->x - weapon->oldx) * r_TicFracF; wy = weapon->oldy + (weapon->y - weapon->oldy) * r_TicFracF; } } else { wx = 0; wy = 0; } if (gl_fixedcolormap) { lightlevel=255; cm.Clear(); fakesec = viewsector; } else { fakesec = gl_FakeFlat(viewsector, &fs, false); // calculate light level for weapon sprites lightlevel = gl_ClampLight(fakesec->lightlevel); // calculate colormap for weapon sprites if (viewsector->e->XFloor.ffloors.Size() && !glset.nocoloredspritelighting) { TArray<lightlist_t> & lightlist = viewsector->e->XFloor.lightlist; for(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<player->viewz) { cm = lightlist[i].extra_colormap; lightlevel = gl_ClampLight(*lightlist[i].p_lightlevel); break; } } } else { cm=fakesec->ColorMap; if (glset.nocoloredspritelighting) cm.ClearColor(); } lightlevel = gl_CalcLightLevel(lightlevel, getExtraLight(), true); if (glset.lightmode == 8) { // Korshun: the way based on max possible light level for sector like in software renderer. float min_L = 36.0 / 31.0 - ((lightlevel / 255.0) * (63.0 / 31.0)); // Lightlevel in range 0-63 if (min_L < 0) min_L = 0; else if (min_L > 1.0) min_L = 1.0; lightlevel = (1.0 - min_L) * 255; } else { lightlevel = (2 * lightlevel + 255) / 3; } lightlevel = gl_CheckSpriteGlow(viewsector, lightlevel, playermo->Pos()); } // Korshun: fullbright fog in opengl, render weapon sprites fullbright (but don't cancel out the light color!) if (glset.brightfog && ((level.flags&LEVEL_HASFADETABLE) || cm.FadeColor != 0)) { lightlevel = 255; } PalEntry ThingColor = (playermo->RenderStyle.Flags & STYLEF_ColorIsFixed) ? playermo->fillcolor : 0xffffff; ThingColor.a = 255; visstyle_t vis; vis.RenderStyle=playermo->RenderStyle; vis.Alpha=playermo->Alpha; vis.colormap = NULL; if (playermo->Inventory) { playermo->Inventory->AlterWeaponSprite(&vis); if (vis.colormap >= SpecialColormaps[0].Colormap && vis.colormap < SpecialColormaps[SpecialColormaps.Size()].Colormap && gl_fixedcolormap == CM_DEFAULT) { // this only happens for Strife's inverted weapon sprite vis.RenderStyle.Flags |= STYLEF_InvertSource; } } // Set the render parameters int OverrideShader = -1; float trans = 0.f; if (vis.RenderStyle.BlendOp >= STYLEOP_Fuzz && vis.RenderStyle.BlendOp <= STYLEOP_FuzzOrRevSub) { vis.RenderStyle.CheckFuzz(); if (vis.RenderStyle.BlendOp == STYLEOP_Fuzz) { if (gl_fuzztype != 0) { // Todo: implement shader selection here vis.RenderStyle = LegacyRenderStyles[STYLE_Translucent]; OverrideShader = gl_fuzztype + 4; trans = 0.99f; // trans may not be 1 here } else { vis.RenderStyle.BlendOp = STYLEOP_Shadow; } } } gl_SetRenderStyle(vis.RenderStyle, false, false); if (vis.RenderStyle.Flags & STYLEF_TransSoulsAlpha) { trans = transsouls; } else if (vis.RenderStyle.Flags & STYLEF_Alpha1) { trans = 1.f; } else if (trans == 0.f) { trans = vis.Alpha; } // now draw the different layers of the weapon gl_RenderState.EnableBrightmap(true); gl_RenderState.SetObjectColor(ThingColor); gl_RenderState.BlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA); gl_RenderState.AlphaFunc(GL_GEQUAL, gl_mask_sprite_threshold); gl_RenderState.BlendEquation(GL_FUNC_ADD); // hack alert! Rather than changing everything in the underlying lighting code let's just temporarily change // light mode here to draw the weapon sprite. int oldlightmode = glset.lightmode; if (glset.lightmode == 8) glset.lightmode = 2; for(DPSprite *psp = player->psprites; psp != nullptr && psp->GetID() < PSP_TARGETCENTER; psp = psp->GetNext()) { if (psp->GetState() != nullptr) { FColormap cmc = cm; int ll = lightlevel; if (isBright(psp)) { if (fakesec == viewsector || in_area != area_below) { cmc.LightColor.r= cmc.LightColor.g= cmc.LightColor.b=0xff; } else { // under water areas keep most of their color for fullbright objects cmc.LightColor.r = (3 * cmc.LightColor.r + 0xff) / 4; cmc.LightColor.g = (3*cmc.LightColor.g + 0xff)/4; cmc.LightColor.b = (3*cmc.LightColor.b + 0xff)/4; } ll = 255; } // set the lighting parameters if (vis.RenderStyle.BlendOp == STYLEOP_Shadow) { gl_RenderState.SetColor(0.2f, 0.2f, 0.2f, 0.33f, cmc.desaturation); } else { if (gl_lights && GLRenderer->mLightCount && !gl_fixedcolormap && gl_light_sprites) { gl_SetDynSpriteLight(playermo, NULL); } gl_SetColor(ll, 0, cmc, trans, true); } if (psp->firstTic) { // Can't interpolate the first tic. psp->firstTic = false; psp->oldx = psp->x; psp->oldy = psp->y; } float sx = psp->oldx + (psp->x - psp->oldx) * r_TicFracF; float sy = psp->oldy + (psp->y - psp->oldy) * r_TicFracF; if (psp->Flags & PSPF_ADDBOB) { sx += bobx; sy += boby; } if (psp->Flags & PSPF_ADDWEAPON && psp->GetID() != PSP_WEAPON) { sx += wx; sy += wy; } DrawPSprite(player, psp, sx, sy, hudModelStep, OverrideShader, !!(vis.RenderStyle.Flags & STYLEF_RedIsAlpha)); } } gl_RenderState.SetObjectColor(0xffffffff); gl_RenderState.SetDynLight(0, 0, 0); gl_RenderState.EnableBrightmap(false); glset.lightmode = oldlightmode; }