Exemplo n.º 1
0
	bool RenderTranslucentPass::ClipSpriteColumnWithPortals(int x, VisibleSprite *spr)
	{
		RenderPortal *renderportal = Thread->Portal.get();

		// [ZZ] 10.01.2016: don't clip sprites from the root of a skybox.
		if (renderportal->CurrentPortalInSkybox)
			return false;

		for (DrawSegment *seg : portaldrawsegs)
		{
			// ignore segs from other portals
			if (seg->CurrentPortalUniq != renderportal->CurrentPortalUniq)
				continue;

			// (all checks that are already done in R_CollectPortals have been removed for performance reasons.)

			// don't clip if the sprite is in front of the portal
			if (!P_PointOnLineSidePrecise(spr->WorldPos().X, spr->WorldPos().Y, seg->curline->linedef))
				continue;

			// now if current column is covered by this drawseg, we clip it away
			if ((x >= seg->x1) && (x < seg->x2))
				return true;
		}

		return false;
	}
Exemplo n.º 2
0
int HWLinePortal::ClipPoint(const DVector2 &pos)
{
	if (P_PointOnLineSidePrecise(pos, line()))
	{
		return PClip_InFront;
	}
	return PClip_Inside;
}
Exemplo n.º 3
0
int HWLinePortal::ClipSubsector(subsector_t *sub)
{
	// this seg is completely behind the mirror
	for (unsigned int i = 0; i<sub->numlines; i++)
	{
		if (P_PointOnLineSidePrecise(sub->firstline[i].v1->fPos(), line()) == 0) return PClip_Inside;
	}
	return PClip_InFront;
}
Exemplo n.º 4
0
//-----------------------------------------------------------------------------
//
//
//
//-----------------------------------------------------------------------------
void GLLineToLinePortal::DrawContents()
{
	// TODO: Handle recursion more intelligently
	if (renderdepth>r_mirror_recursions) 
	{
		ClearScreen();
		return;
	}

	GLRenderer->mClipPortal = this;

	line_t *origin = glport->lines[0]->mOrigin;
	P_TranslatePortalXY(origin, ViewPos.X, ViewPos.Y);
	P_TranslatePortalAngle(origin, ViewAngle);
	P_TranslatePortalZ(origin, ViewPos.Z);
	P_TranslatePortalXY(origin, ViewPath[0].X, ViewPath[0].Y);
	P_TranslatePortalXY(origin, ViewPath[1].X, ViewPath[1].Y);
	if (!r_showviewer && camera != nullptr && P_PointOnLineSidePrecise(ViewPath[0], glport->lines[0]->mDestination) != P_PointOnLineSidePrecise(ViewPath[1], glport->lines[0]->mDestination))
	{
		double distp = (ViewPath[0] - ViewPath[1]).Length();
		if (distp > EQUAL_EPSILON)
		{
			double dist1 = (ViewPos - ViewPath[0]).Length();
			double dist2 = (ViewPos - ViewPath[1]).Length();

			if (dist1 + dist2 < distp + 1)
			{
				camera->renderflags |= RF_INVISIBLE;
			}
		}
	}


	SaveMapSection();

	for (unsigned i = 0; i < lines.Size(); i++)
	{
		line_t *line = lines[i].seg->linedef->getPortalDestination();
		subsector_t *sub;
		if (line->sidedef[0]->Flags & WALLF_POLYOBJ) 
			sub = R_PointInSubsector(line->v1->fixX(), line->v1->fixY());
		else sub = line->frontsector->subsectors[0];
		int mapsection = sub->mapsection;
		currentmapsection[mapsection >> 3] |= 1 << (mapsection & 7);
	}

	GLRenderer->mViewActor = nullptr;
	GLRenderer->SetupView(ViewPos.X, ViewPos.Y, ViewPos.Z, ViewAngle, !!(MirrorFlag&1), !!(PlaneMirrorFlag&1));

	ClearClipper();
	gl_RenderState.SetClipLine(glport->lines[0]->mDestination);
	gl_RenderState.EnableClipLine(true);
	GLRenderer->DrawScene(DM_PORTAL);
	gl_RenderState.EnableClipLine(false);
	RestoreMapSection();
}
Exemplo n.º 5
0
//-----------------------------------------------------------------------------
//
//
//
//-----------------------------------------------------------------------------
bool HWLineToLinePortal::Setup(HWDrawInfo *di, FRenderState &rstate, Clipper *clipper)
{
	// TODO: Handle recursion more intelligently
	auto &state = mState;
	if (state->renderdepth>r_mirror_recursions)
	{
		return false;
	}
	auto &vp = di->Viewpoint;
	di->mClipPortal = this;

	line_t *origin = glport->lines[0]->mOrigin;
	P_TranslatePortalXY(origin, vp.Pos.X, vp.Pos.Y);
	P_TranslatePortalXY(origin, vp.ActorPos.X, vp.ActorPos.Y);
	P_TranslatePortalAngle(origin, vp.Angles.Yaw);
	P_TranslatePortalZ(origin, vp.Pos.Z);
	P_TranslatePortalXY(origin, vp.Path[0].X, vp.Path[0].Y);
	P_TranslatePortalXY(origin, vp.Path[1].X, vp.Path[1].Y);
	if (!vp.showviewer && vp.camera != nullptr && P_PointOnLineSidePrecise(vp.Path[0], glport->lines[0]->mDestination) != P_PointOnLineSidePrecise(vp.Path[1], glport->lines[0]->mDestination))
	{
		double distp = (vp.Path[0] - vp.Path[1]).Length();
		if (distp > EQUAL_EPSILON)
		{
			double dist1 = (vp.Pos - vp.Path[0]).Length();
			double dist2 = (vp.Pos - vp.Path[1]).Length();

			if (dist1 + dist2 < distp + 1)
			{
				vp.camera->renderflags |= RF_MAYBEINVISIBLE;
			}
		}
	}


	for (unsigned i = 0; i < lines.Size(); i++)
	{
		line_t *line = lines[i].seg->linedef->getPortalDestination();
		subsector_t *sub;
		if (line->sidedef[0]->Flags & WALLF_POLYOBJ)
			sub = di->Level->PointInRenderSubsector(line->v1->fixX(), line->v1->fixY());
		else sub = line->frontsector->subsectors[0];
		di->CurrentMapSections.Set(sub->mapsection);
	}

	vp.ViewActor = nullptr;
	di->SetClipLine(glport->lines[0]->mDestination);
	di->SetupView(rstate, vp.Pos.X, vp.Pos.Y, vp.Pos.Z, !!(state->MirrorFlag & 1), !!(state->PlaneMirrorFlag & 1));

	ClearClipper(di, clipper);
	return true;
}
Exemplo n.º 6
0
static void P_SlopeLineToPoint (int lineid, const DVector3 &pos, bool slopeCeil)
{
	int linenum;

	FLineIdIterator itr(lineid);
	while ((linenum = itr.Next()) >= 0)
	{
		const line_t *line = &lines[linenum];
		sector_t *sec;
		secplane_t *plane;
		
		if (P_PointOnLineSidePrecise (pos, line) == 0)
		{
			sec = line->frontsector;
		}
		else
		{
			sec = line->backsector;
		}
		if (sec == NULL)
		{
			continue;
		}
		if (slopeCeil)
		{
			plane = &sec->ceilingplane;
		}
		else
		{
			plane = &sec->floorplane;
		}

		DVector3 p, v1, v2, cross;

		p[0] = line->v1->fX();
		p[1] = line->v1->fY();
		p[2] = plane->ZatPoint (line->v1);
		v1[0] = line->Delta().X;
		v1[1] = line->Delta().Y;
		v1[2] = plane->ZatPoint (line->v2) - p[2];
		v2[0] = pos.X - p[0];
		v2[1] = pos.Y - p[1];
		v2[2] = pos.Z - p[2];

		cross = v1 ^ v2;
		double len = cross.Length();
		if (len == 0)
		{
			Printf ("Slope thing at (%f,%f) lies directly on its target line.\n", pos.X, pos.Y);
			return;
		}
		cross /= len;
		// Fix backward normals
		if ((cross.Z < 0 && !slopeCeil) || (cross.Z > 0 && slopeCeil))
		{
			cross = -cross;
		}

		double dist = -cross[0] * pos.X - cross[1] * pos.Y - cross[2] * pos.Z;
		plane->set(cross[0], cross[1], cross[2], dist);
	}
}
Exemplo n.º 7
0
static void P_SetSlopesFromVertexHeights(FMapThing *firstmt, FMapThing *lastmt, const int *oldvertextable)
{
	TMap<int, double> vt_heights[2];
	FMapThing *mt;
	bool vt_found = false;

	for (mt = firstmt; mt < lastmt; ++mt)
	{
		if (mt->info != NULL && mt->info->Type == NULL)
		{
			if (mt->info->Special == SMT_VertexFloorZ || mt->info->Special == SMT_VertexCeilingZ)
			{
				for (int i = 0; i < numvertexes; i++)
				{
					if (vertexes[i].fX() == mt->pos.X && vertexes[i].fY() == mt->pos.Y)
					{
						if (mt->info->Special == SMT_VertexFloorZ)
						{
							vt_heights[0][i] = mt->pos.Z;
						}
						else
						{
							vt_heights[1][i] = mt->pos.Z;
						}
						vt_found = true;
					}
				}
				mt->EdNum = 0;
			}
		}
	}

	for(int i = 0; i < numvertexdatas; i++)
	{
		int ii = oldvertextable == NULL ? i : oldvertextable[i];

		if (vertexdatas[i].flags & VERTEXFLAG_ZCeilingEnabled)
		{
			vt_heights[1][ii] = vertexdatas[i].zCeiling;
			vt_found = true;
		}

		if (vertexdatas[i].flags & VERTEXFLAG_ZFloorEnabled)
		{
			vt_heights[0][ii] = vertexdatas[i].zFloor;
			vt_found = true;
		}
	}

	// If vertexdata_t is ever extended for non-slope usage, this will obviously have to be deferred or removed.
	delete[] vertexdatas;
	vertexdatas = NULL;
	numvertexdatas = 0;

	if (vt_found)
	{
		for (int i = 0; i < numsectors; i++)
		{
			sector_t *sec = &sectors[i];
			if (sec->linecount != 3) continue;	// only works with triangular sectors

			DVector3 vt1, vt2, vt3, cross;
			DVector3 vec1, vec2;
			int vi1, vi2, vi3;

			vi1 = int(sec->lines[0]->v1 - vertexes);
			vi2 = int(sec->lines[0]->v2 - vertexes);
			vi3 = (sec->lines[1]->v1 == sec->lines[0]->v1 || sec->lines[1]->v1 == sec->lines[0]->v2)?
				int(sec->lines[1]->v2 - vertexes) : int(sec->lines[1]->v1 - vertexes);

			vt1 = DVector3(vertexes[vi1].fPos(), 0);
			vt2 = DVector3(vertexes[vi2].fPos(), 0);
			vt3 = DVector3(vertexes[vi3].fPos(), 0);

			for(int j=0; j<2; j++)
			{
				double *h1 = vt_heights[j].CheckKey(vi1);
				double *h2 = vt_heights[j].CheckKey(vi2);
				double *h3 = vt_heights[j].CheckKey(vi3);
				if (h1 == NULL && h2 == NULL && h3 == NULL) continue;

				vt1.Z = h1? *h1 : j==0? sec->GetPlaneTexZ(sector_t::floor) : sec->GetPlaneTexZ(sector_t::ceiling);
				vt2.Z = h2? *h2 : j==0? sec->GetPlaneTexZ(sector_t::floor) : sec->GetPlaneTexZ(sector_t::ceiling);
				vt3.Z = h3? *h3 : j==0? sec->GetPlaneTexZ(sector_t::floor) : sec->GetPlaneTexZ(sector_t::ceiling);

				if (P_PointOnLineSidePrecise(vertexes[vi3].fX(), vertexes[vi3].fY(), sec->lines[0]) == 0)
				{
					vec1 = vt2 - vt3;
					vec2 = vt1 - vt3;
				}
				else
				{
					vec1 = vt1 - vt3;
					vec2 = vt2 - vt3;
				}

				DVector3 cross = vec1 ^ vec2;

				double len = cross.Length();
				if (len == 0)
				{
					// Only happens when all vertices in this sector are on the same line.
					// Let's just ignore this case.
					continue;
				}
				cross /= len;

				// Fix backward normals
				if ((cross.Z < 0 && j == 0) || (cross.Z > 0 && j == 1))
				{
					cross = -cross;
				}

				secplane_t *plane = j==0? &sec->floorplane : &sec->ceilingplane;

				double dist = -cross[0] * vertexes[vi3].fX() - cross[1] * vertexes[vi3].fY() - cross[2] * vt3.Z;
				plane->set(cross[0], cross[1], cross[2], dist);
			}
		}
	}
}
Exemplo n.º 8
0
// [RH] Modified to support different source and destination ids.
// [RH] Modified some more to be accurate.
bool EV_SilentLineTeleport (line_t *line, int side, AActor *thing, int id, INTBOOL reverse)
{
	int i;
	line_t *l;

	if (side || thing->flags2 & MF2_NOTELEPORT || !line || line->sidedef[1] == NULL)
		return false;

	FLineIdIterator itr(id);
	while ((i = itr.Next()) >= 0)
	{
		if (line->Index() == i)
			continue;

		if ((l=&level.lines[i]) != line && l->backsector)
		{
			// Get the thing's position along the source linedef
			double pos;
			DVector2 npos;			// offsets from line
			double den;

			den = line->Delta().LengthSquared();
			if (den == 0)
			{
				pos = 0;
				npos.Zero();
			}
			else
			{
				double num = (thing->Pos().XY() - line->v1->fPos()) | line->Delta();
				if (num <= 0)
				{
					pos = 0;
				}
				else if (num >= den)
				{
					pos = 1;
				}
				else
				{
					pos = num / den;
				}
				npos = thing->Pos().XY() - line->v1->fPos() - line->Delta() * pos;
			}

			// Get the angle between the two linedefs, for rotating
			// orientation and velocity. Rotate 180 degrees, and flip
			// the position across the exit linedef, if reversed.
			DAngle angle = l->Delta().Angle() - line->Delta().Angle();

			if (!reverse)
			{
				angle += 180.;
				pos = 1 - pos;
			}

			// Sine, cosine of angle adjustment
			double s = angle.Sin();
			double c = angle.Cos();

			DVector2 p;

			// Rotate position along normal to match exit linedef
			p.X = npos.X*c - npos.Y*s;
			p.Y = npos.Y*c + npos.X*s;

			// Interpolate position across the exit linedef
			p += l->v1->fPos() + pos*l->Delta();

			// Whether this is a player, and if so, a pointer to its player_t.
			// Voodoo dolls are excluded by making sure thing->player->mo==thing.
			player_t *player = thing->player && thing->player->mo == thing ?
				thing->player : NULL;

			// Whether walking towards first side of exit linedef steps down
			bool stepdown = l->frontsector->floorplane.ZatPoint(p) < l->backsector->floorplane.ZatPoint(p);

			// Height of thing above ground
			double z = thing->Z() - thing->floorz;

			// Side to exit the linedef on positionally.
			//
			// Notes:
			//
			// This flag concerns exit position, not momentum. Due to
			// roundoff error, the thing can land on either the left or
			// the right side of the exit linedef, and steps must be
			// taken to make sure it does not end up on the wrong side.
			//
			// Exit momentum is always towards side 1 in a reversed
			// teleporter, and always towards side 0 otherwise.
			//
			// Exiting positionally on side 1 is always safe, as far
			// as avoiding oscillations and stuck-in-wall problems,
			// but may not be optimum for non-reversed teleporters.
			//
			// Exiting on side 0 can cause oscillations if momentum
			// is towards side 1, as it is with reversed teleporters.
			//
			// Exiting on side 1 slightly improves player viewing
			// when going down a step on a non-reversed teleporter.

			// Is this really still necessary with real math instead of imprecise trig tables?
#if 1
			int side = reverse || (player && stepdown);
			int fudge = FUDGEFACTOR;

			double dx = line->Delta().X;
			double dy = line->Delta().Y;
			// Make sure we are on correct side of exit linedef.
			while (P_PointOnLineSidePrecise(p, l) != side && --fudge >= 0)
			{
				if (fabs(dx) > fabs(dy))
					p.Y -= (dx < 0) != side ? -1 : 1;
				else
					p.X += (dy < 0) != side ? -1 : 1;
			}
#endif

			// Adjust z position to be same height above ground as before.
			// Ground level at the exit is measured as the higher of the
			// two floor heights at the exit linedef.
			z = z + l->sidedef[stepdown]->sector->floorplane.ZatPoint(p);

			// Attempt to teleport, aborting if blocked
			if (!P_TeleportMove (thing, DVector3(p, z), false))
			{
				return false;
			}

			if (thing == players[consoleplayer].camera)
			{
				R_ResetViewInterpolation ();
			}

			// Rotate thing's orientation according to difference in linedef angles
			thing->Angles.Yaw += angle;

			// Rotate thing's velocity to come out of exit just like it entered
			p = thing->Vel.XY();
			thing->Vel.X = p.X*c - p.Y*s;
			thing->Vel.Y = p.Y*c + p.X*s;

			// Adjust a player's view, in case there has been a height change
			if (player && player->mo == thing)
			{
				// Adjust player's local copy of velocity
				p = player->Vel;
				player->Vel.X = p.X*c - p.Y*s;
				player->Vel.Y = p.Y*c + p.X*s;

				// Save the current deltaviewheight, used in stepping
				double deltaviewheight = player->deltaviewheight;

				// Clear deltaviewheight, since we don't want any changes now
				player->deltaviewheight = 0;

				// Set player's view according to the newly set parameters
				P_CalcHeight(player);

				// Reset the delta to have the same dynamics as before
				player->deltaviewheight = deltaviewheight;
			}

			return true;
		}
	}
	return false;
}
Exemplo n.º 9
0
	void RenderPortal::RenderLinePortal(PortalDrawseg* pds, int depth)
	{
		auto viewport = Thread->Viewport.get();
		auto &viewpoint = viewport->viewpoint;
		
		// [ZZ] check depth. fill portal with black if it's exceeding the visual recursion limit, and continue like nothing happened.
		if (depth >= r_portal_recursions)
		{
			uint8_t color = (uint8_t)BestColor((uint32_t *)GPalette.BaseColors, 0, 0, 0, 0, 255);
			int spacing = viewport->RenderTarget->GetPitch();
			for (int x = pds->x1; x < pds->x2; x++)
			{
				if (x < 0 || x >= viewport->RenderTarget->GetWidth())
					continue;

				int Ytop = pds->ceilingclip[x - pds->x1];
				int Ybottom = pds->floorclip[x - pds->x1];

				if (viewport->RenderTarget->IsBgra())
				{
					uint32_t *dest = (uint32_t*)viewport->RenderTarget->GetBuffer() + x + Ytop * spacing;

					uint32_t c = GPalette.BaseColors[color].d;
					for (int y = Ytop; y <= Ybottom; y++)
					{
						*dest = c;
						dest += spacing;
					}
				}
				else
				{
					uint8_t *dest = viewport->RenderTarget->GetBuffer() + x + Ytop * spacing;

					for (int y = Ytop; y <= Ybottom; y++)
					{
						*dest = color;
						dest += spacing;
					}
				}
			}

			if (r_highlight_portals)
				RenderLinePortalHighlight(pds);

			return;
		}

		DAngle startang = viewpoint.Angles.Yaw;
		DVector3 startpos = viewpoint.Pos;
		DVector3 savedpath[2] = { viewpoint.Path[0], viewpoint.Path[1] };
		ActorRenderFlags savedvisibility = viewpoint.camera ? viewpoint.camera->renderflags & RF_INVISIBLE : ActorRenderFlags::FromInt(0);
		
		viewpoint.camera->renderflags &= ~RF_INVISIBLE;

		CurrentPortalUniq++;

		unsigned int portalsAtStart = WallPortals.Size();

		if (pds->mirror)
		{
			//vertex_t *v1 = ds->curline->v1;
			vertex_t *v1 = pds->src->v1;

			// Reflect the current view behind the mirror.
			if (pds->src->Delta().X == 0)
			{ // vertical mirror
				viewpoint.Pos.X = v1->fX() - startpos.X + v1->fX();
			}
			else if (pds->src->Delta().Y == 0)
			{ // horizontal mirror
				viewpoint.Pos.Y = v1->fY() - startpos.Y + v1->fY();
			}
			else
			{ // any mirror
				vertex_t *v2 = pds->src->v2;

				double dx = v2->fX() - v1->fX();
				double dy = v2->fY() - v1->fY();
				double x1 = v1->fX();
				double y1 = v1->fY();
				double x = startpos.X;
				double y = startpos.Y;

				// the above two cases catch len == 0
				double r = ((x - x1)*dx + (y - y1)*dy) / (dx*dx + dy*dy);

				viewpoint.Pos.X = (x1 + r * dx) * 2 - x;
				viewpoint.Pos.Y = (y1 + r * dy) * 2 - y;
			}
			viewpoint.Angles.Yaw = pds->src->Delta().Angle() * 2 - startang;
		}
		else
		{
			P_TranslatePortalXY(pds->src, viewpoint.Pos.X, viewpoint.Pos.Y);
			P_TranslatePortalZ(pds->src, viewpoint.Pos.Z);
			P_TranslatePortalAngle(pds->src, viewpoint.Angles.Yaw);
			P_TranslatePortalXY(pds->src, viewpoint.Path[0].X, viewpoint.Path[0].Y);
			P_TranslatePortalXY(pds->src, viewpoint.Path[1].X, viewpoint.Path[1].Y);

			if (!viewpoint.showviewer && viewpoint.camera && P_PointOnLineSidePrecise(viewpoint.Path[0], pds->dst) != P_PointOnLineSidePrecise(viewpoint.Path[1], pds->dst))
			{
				double distp = (viewpoint.Path[0] - viewpoint.Path[1]).Length();
				if (distp > EQUAL_EPSILON)
				{
					double dist1 = (viewpoint.Pos - viewpoint.Path[0]).Length();
					double dist2 = (viewpoint.Pos - viewpoint.Path[1]).Length();

					if (dist1 + dist2 < distp + 1)
					{
						viewpoint.camera->renderflags |= RF_INVISIBLE;
					}
				}
			}
		}

		viewpoint.Sin = viewpoint.Angles.Yaw.Sin();
		viewpoint.Cos = viewpoint.Angles.Yaw.Cos();

		viewpoint.TanSin = Thread->Viewport->viewwindow.FocalTangent * viewpoint.Sin;
		viewpoint.TanCos = Thread->Viewport->viewwindow.FocalTangent * viewpoint.Cos;

		CopyStackedViewParameters();

		validcount++;
		PortalDrawseg* prevpds = CurrentPortal;
		CurrentPortal = pds;

		Thread->PlaneList->ClearKeepFakePlanes();
		Thread->ClipSegments->Clear(pds->x1, pds->x2);

		WindowLeft = pds->x1;
		WindowRight = pds->x2;

		// RF_XFLIP should be removed before calling the root function
		int prevmf = MirrorFlags;
		if (pds->mirror)
		{
			if (MirrorFlags & RF_XFLIP)
				MirrorFlags &= ~RF_XFLIP;
			else MirrorFlags |= RF_XFLIP;
		}

		// some portals have height differences, account for this here
		Thread->Clip3D->EnterSkybox(); // push 3D floor height map
		CurrentPortalInSkybox = false; // first portal in a skybox should set this variable to false for proper clipping in skyboxes.

		// first pass, set clipping
		auto ceilingclip = Thread->OpaquePass->ceilingclip;
		auto floorclip = Thread->OpaquePass->floorclip;
		memcpy(ceilingclip + pds->x1, &pds->ceilingclip[0], pds->len * sizeof(*ceilingclip));
		memcpy(floorclip + pds->x1, &pds->floorclip[0], pds->len * sizeof(*floorclip));

		Thread->OpaquePass->RenderScene();
		Thread->Clip3D->ResetClip(); // reset clips (floor/ceiling)
		if (!savedvisibility && viewpoint.camera) viewpoint.camera->renderflags &= ~RF_INVISIBLE;

		Thread->PlaneList->Render();
		RenderPlanePortals();

		double vzp = viewpoint.Pos.Z;

		int prevuniq = CurrentPortalUniq;
		// depth check is in another place right now
		unsigned int portalsAtEnd = WallPortals.Size();
		for (; portalsAtStart < portalsAtEnd; portalsAtStart++)
		{
			RenderLinePortal(WallPortals[portalsAtStart], depth + 1);
		}
		int prevuniq2 = CurrentPortalUniq;
		CurrentPortalUniq = prevuniq;

		if (Thread->MainThread)
			NetUpdate();

		Thread->TranslucentPass->Render();	  //      this is required since with portals there often will be cases when more than 80% of the view is inside a portal.

		if (Thread->MainThread)
			NetUpdate();

		Thread->Clip3D->LeaveSkybox(); // pop 3D floor height map
		CurrentPortalUniq = prevuniq2;

		// draw a red line around a portal if it's being highlighted
		if (r_highlight_portals)
			RenderLinePortalHighlight(pds);

		CurrentPortal = prevpds;
		MirrorFlags = prevmf;
		viewpoint.Angles.Yaw = startang;
		viewpoint.Pos = startpos;
		viewpoint.Path[0] = savedpath[0];
		viewpoint.Path[1] = savedpath[1];
	}
Exemplo n.º 10
0
//
// A_PainShootSkull
// Spawn a lost soul and launch it at the target
//
void A_PainShootSkull (AActor *self, angle_t angle, PClassActor *spawntype, int flags = 0, int limit = -1)
{
	AActor *other;
	int prestep;

	if (spawntype == NULL) return;
	if (self->DamageType == NAME_Massacre) return;

	// [RH] check to make sure it's not too close to the ceiling
	if (self->Top() + 8*FRACUNIT > self->ceilingz)
	{
		if (self->flags & MF_FLOAT)
		{
			self->velz -= 2*FRACUNIT;
			self->flags |= MF_INFLOAT;
			self->flags4 |= MF4_VFRICTION;
		}
		return;
	}

	// [RH] make this optional
	if (limit == -1 && (i_compatflags & COMPATF_LIMITPAIN))
		limit = 21;

	if (limit)
	{
		// count total number of skulls currently on the level
		// if there are already 21 skulls on the level, don't spit another one
		int count = limit;
		FThinkerIterator iterator (spawntype);
		DThinker *othink;

		while ( (othink = iterator.Next ()) )
		{
			if (--count == 0)
				return;
		}
	}

	// okay, there's room for another one
	prestep = 4*FRACUNIT +
		3*(self->radius + GetDefaultByType(spawntype)->radius)/2;

	// NOTE: The following code contains some advance work for line-to-line portals which is currenty inactive.

	fixedvec2 dist = Vec2Angle(prestep, angle);
	fixedvec3 pos = self->Vec3Offset(dist.x, dist.y, 8 * FRACUNIT, true);
	fixedvec3 src = self->Pos();

	for (int i = 0; i < 2; i++)
	{
		// Check whether the Lost Soul is being fired through a 1-sided	// phares
		// wall or an impassible line, or a "monsters can't cross" line.//   |
		// If it is, then we don't allow the spawn.						//   V

		FBoundingBox box(MIN(src.x, pos.x), MIN(src.y, pos.y), MAX(src.x, pos.x), MAX(src.y, pos.y));
		FBlockLinesIterator it(box);
		line_t *ld;
		bool inportal = false;

		while ((ld = it.Next()))
		{
			if (ld->isLinePortal() && i == 0)
			{
				if (P_PointOnLineSidePrecise(src.x, src.y, ld) == 0 &&
					P_PointOnLineSidePrecise(pos.x, pos.y, ld) == 1)
				{
					// crossed a portal line from front to back, we need to repeat the check on the other side as well.
					inportal = true;
				}
			}
			else if (!(ld->flags & ML_TWOSIDED) ||
				(ld->flags & (ML_BLOCKING | ML_BLOCKMONSTERS | ML_BLOCKEVERYTHING)))
			{
				if (!(box.Left() > ld->bbox[BOXRIGHT] ||
					box.Right() < ld->bbox[BOXLEFT] ||
					box.Top() < ld->bbox[BOXBOTTOM] ||
					box.Bottom() > ld->bbox[BOXTOP]))
				{
					if (P_PointOnLineSidePrecise(src.x, src.y, ld) != P_PointOnLineSidePrecise(pos.x, pos.y, ld))
						return;  // line blocks trajectory				//   ^
				}
			}
		}
		if (!inportal) break;

		// recalculate position and redo the check on the other side of the portal
		pos = self->Vec3Offset(dist.x, dist.y, 8 * FRACUNIT, false);
		src.x = pos.x - dist.x;
		src.y = pos.y - dist.y;

	}

	other = Spawn (spawntype, pos.x, pos.y, pos.z, ALLOW_REPLACE);

	// Check to see if the new Lost Soul's z value is above the
	// ceiling of its new sector, or below the floor. If so, kill it.

	if ((other->Z() >
         (other->Sector->HighestCeiling(other) - other->height)) ||
        (other->Z() < other->Sector->LowestFloor(other)))
	{
		// kill it immediately
		P_DamageMobj (other, self, self, TELEFRAG_DAMAGE, NAME_None);//  ^
		return;														//   |
	}																// phares

	// Check for movements.

	if (!P_CheckPosition (other, other->Pos()))
	{
		// kill it immediately
		P_DamageMobj (other, self, self, TELEFRAG_DAMAGE, NAME_None);		
		return;
	}

	// [RH] Lost souls hate the same things as their pain elementals
	other->CopyFriendliness (self, !(flags & PAF_NOTARGET));

	if (!(flags & PAF_NOSKULLATTACK))
		A_SkullAttack(other, SKULLSPEED);
}
Exemplo n.º 11
0
bool FTraceInfo::TraceTraverse (int ptflags)
{
	// Do a 3D floor check in the starting sector
	Setup3DFloors();

	FPathTraverse it(Start.X, Start.Y, Vec.X * MaxDist, Vec.Y * MaxDist, ptflags | PT_DELTA, startfrac);
	intercept_t *in;
	int lastsplashsector = -1;

	while ((in = it.Next()))
	{
		// Deal with splashes in 3D floors (but only run once per sector, not each iteration - and stop if something was found.)
		if (Results->Crossed3DWater == NULL && lastsplashsector != CurSector->sectornum)
		{
			for (auto rover : CurSector->e->XFloor.ffloors)
			{
				if ((rover->flags & FF_EXISTS) && (rover->flags&FF_SWIMMABLE))
				{
					if (Check3DFloorPlane(rover, false))
					{
						// only consider if the plane is above the actual floor.
						if (rover->top.plane->ZatPoint(Results->HitPos) > CurSector->floorplane.ZatPoint(Results->HitPos))
						{
							Results->Crossed3DWater = rover;
							Results->Crossed3DWaterPos = Results->HitPos;
							Results->Distance = 0;
						}
					}
				}
			}
			lastsplashsector = CurSector->sectornum;
		}

		double dist = MaxDist * in->frac;
		DVector3 hit = Start + Vec * dist;

		// Crossed a floor portal? 
		if (Vec.Z < 0 && !CurSector->PortalBlocksMovement(sector_t::floor))
		{
			// calculate position where the portal is crossed
			double portz = CurSector->GetPortalPlaneZ(sector_t::floor);
			if (hit.Z < portz && limitz > portz)
			{
				limitz = portz;
				EnterSectorPortal(it, sector_t::floor, (portz - Start.Z) / (Vec.Z * MaxDist), CurSector);
				continue;
			}
		}
		// ... or a ceiling portal?
		else if (Vec.Z > 0 && !CurSector->PortalBlocksMovement(sector_t::ceiling))
		{
			// calculate position where the portal is crossed
			double portz = CurSector->GetPortalPlaneZ(sector_t::ceiling);
			if (hit.Z > portz && limitz < portz)
			{
				limitz = portz;
				EnterSectorPortal(it, sector_t::ceiling, (portz - Start.Z) / (Vec.Z * MaxDist), CurSector);
				continue;
			}
		}

		if (in->isaline)
		{
			if (in->d.line->isLinePortal() && P_PointOnLineSidePrecise(Start, in->d.line) == 0)
			{
				sector_t *entersector = in->d.line->backsector;
				if (entersector == NULL || (hit.Z >= entersector->floorplane.ZatPoint(hit) && hit.Z <= entersector->ceilingplane.ZatPoint(hit)))
				{
					FLinePortal *port = in->d.line->getPortal();
					// The caller cannot handle portals without global offset.
					if (port->mType == PORTT_LINKED || !(TraceFlags & TRACE_PortalRestrict))
					{
						EnterLinePortal(it, in);
						continue;
					}
				}
			}
			if (!LineCheck(in, dist, hit)) break;
		}
		else if ((in->d.thing->flags & ActorMask) && in->d.thing != IgnoreThis)
		{
			if (!ThingCheck(in, dist, hit)) break;
		}
	}

	if (Results->HitType == TRACE_HitNone)
	{
		if (CurSector->PortalBlocksMovement(sector_t::floor) && CheckSectorPlane(CurSector, true))
		{
			Results->HitType = TRACE_HitFloor;
			Results->HitTexture = CurSector->GetTexture(sector_t::floor);
		}
		else if (CurSector->PortalBlocksMovement(sector_t::ceiling) && CheckSectorPlane(CurSector, false))
		{
			Results->HitType = TRACE_HitCeiling;
			Results->HitTexture = CurSector->GetTexture(sector_t::ceiling);
		}
	}

	// check for intersection with floor/ceiling
	Results->Sector = &level.sectors[CurSector->sectornum];

	if (Results->CrossedWater == NULL &&
		CurSector->heightsec != NULL &&
		CurSector->heightsec->floorplane.ZatPoint(Start) < Start.Z &&
		CurSector->heightsec->floorplane.ZatPoint(Results->HitPos) >= Results->HitPos.Z)
	{
		// Save the result so that the water check doesn't destroy it.
		FTraceResults *res = Results;
		FTraceResults hsecResult;
		Results = &hsecResult;

		if (CheckSectorPlane(CurSector->heightsec, true))
		{
			Results->CrossedWater = &level.sectors[CurSector->sectornum];
			Results->CrossedWaterPos = Results->HitPos;
			Results->Distance = 0;
		}
		Results = res;
	}
	if (Results->HitType == TRACE_HitNone && Results->Distance == 0)
	{
		Results->HitPos = Start + Vec * MaxDist;
		SetSourcePosition();
		Results->Distance = MaxDist;
		Results->Fraction = 1.;
	}
	return Results->HitType != TRACE_HitNone;
}