예제 #1
0
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);
	}
}
예제 #2
0
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();
		}
	}
}
예제 #3
0
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);
}
예제 #4
0
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);
}
예제 #5
0
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);
}
예제 #6
0
//==========================================================================
//
//
//
//==========================================================================
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;
}
예제 #7
0
//==========================================================================
//
//
//
//==========================================================================
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;
}
예제 #8
0
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);
        }
    }
}
예제 #9
0
//==========================================================================
//
// 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();
}
예제 #10
0
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();
}
예제 #11
0
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();
}
예제 #12
0
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;
}