void HWScenePortalBase::ClearClipper(HWDrawInfo *di, Clipper *clipper) { auto outer_di = di->outer; DAngle angleOffset = deltaangle(outer_di->Viewpoint.Angles.Yaw, di->Viewpoint.Angles.Yaw); clipper->Clear(); // Set the clipper to the minimal visible area clipper->SafeAddClipRange(0, 0xffffffff); for (unsigned int i = 0; i < lines.Size(); i++) { DAngle startAngle = (DVector2(lines[i].glseg.x2, lines[i].glseg.y2) - outer_di->Viewpoint.Pos).Angle() + angleOffset; DAngle endAngle = (DVector2(lines[i].glseg.x1, lines[i].glseg.y1) - outer_di->Viewpoint.Pos).Angle() + angleOffset; if (deltaangle(endAngle, startAngle) < 0) { clipper->SafeRemoveClipRangeRealAngles(startAngle.BAMs(), endAngle.BAMs()); } } // and finally clip it to the visible area angle_t a1 = di->FrustumAngle(); if (a1 < ANGLE_180) clipper->SafeAddClipRangeRealAngles(di->Viewpoint.Angles.Yaw.BAMs() + a1, di->Viewpoint.Angles.Yaw.BAMs() - a1); // lock the parts that have just been clipped out. clipper->SetSilhouette(); }
AActor *P_SpawnSubMissile (AActor *source, PClassActor *type, AActor *target) { AActor *other = Spawn (type, source->Pos(), ALLOW_REPLACE); if (other == NULL) { return NULL; } other->target = target; other->Angles.Yaw = source->Angles.Yaw; other->VelFromAngle(); if (other->flags4 & MF4_SPECTRAL) { if (source->flags & MF_MISSILE && source->flags4 & MF4_SPECTRAL) { other->FriendPlayer = source->FriendPlayer; } else { other->SetFriendPlayer(target->player); } } if (P_CheckMissileSpawn (other, source->radius)) { DAngle pitch = P_AimLineAttack (source, source->Angles.Yaw, 1024.); other->Vel.Z = -other->Speed * pitch.Sin(); return other; } return NULL; }
void P_DrawSplash (FLevelLocals *Level, int count, const DVector3 &pos, DAngle angle, int kind) { int color1, color2; switch (kind) { case 1: // Spark color1 = orange; color2 = yorange; break; default: return; } for (; count; count--) { FParticle *p = JitterParticle (Level, 10); if (!p) break; p->size = 2; p->color = M_Random() & 0x80 ? color1 : color2; p->Vel.Z -= M_Random () / 128.; p->Acc.Z -= 1./8; p->Acc.X += (M_Random () - 128) / 8192.; p->Acc.Y += (M_Random () - 128) / 8192.; p->Pos.Z = pos.Z - M_Random () / 64.; angle += M_Random() * (45./256); p->Pos.X = pos.X + (M_Random() & 15)*angle.Cos(); p->Pos.Y = pos.Y + (M_Random() & 15)*angle.Sin(); } }
inline void GLPortal::ClearClipper() { DAngle angleOffset = deltaangle(savedAngle, ViewAngle); clipper.Clear(); static int call=0; // Set the clipper to the minimal visible area clipper.SafeAddClipRange(0,0xffffffff); for (unsigned int i = 0; i < lines.Size(); i++) { DAngle startAngle = (DVector2(lines[i].glseg.x2, lines[i].glseg.y2) - savedViewPos).Angle() + angleOffset; DAngle endAngle = (DVector2(lines[i].glseg.x1, lines[i].glseg.y1) - savedViewPos).Angle() + angleOffset; if (deltaangle(endAngle, startAngle) < 0) { clipper.SafeRemoveClipRangeRealAngles(startAngle.BAMs(), endAngle.BAMs()); } } // and finally clip it to the visible area angle_t a1 = GLRenderer->FrustumAngle(); if (a1 < ANGLE_180) clipper.SafeAddClipRangeRealAngles(ViewAngle.BAMs() + a1, ViewAngle.BAMs() - a1); // lock the parts that have just been clipped out. clipper.SetSilhouette(); }
void P_DrawSplash2 (FLevelLocals *Level, int count, const DVector3 &pos, DAngle angle, int updown, int kind) { int color1, color2, zadd; double zvel, zspread; switch (kind) { case 0: // Blood color1 = blood1; color2 = blood2; break; case 1: // Gunshot color1 = grey3; color2 = grey5; break; case 2: // Smoke color1 = grey3; color2 = grey1; break; default: // colorized blood color1 = ParticleColor(kind); color2 = ParticleColor(RPART(kind)/3, GPART(kind)/3, BPART(kind)/3); break; } zvel = -1./512.; zspread = updown ? -6000 / 65536. : 6000 / 65536.; zadd = (updown == 2) ? -128 : 0; for (; count; count--) { FParticle *p = NewParticle (Level); DAngle an; if (!p) break; p->ttl = 12; p->fadestep = FADEFROMTTL(12); p->alpha = 1.f; p->size = 4; p->color = M_Random() & 0x80 ? color1 : color2; p->Vel.Z = M_Random() * zvel; p->Acc.Z = -1 / 22.; if (kind) { an = angle + ((M_Random() - 128) * (180 / 256.)); p->Vel.X = M_Random() * an.Cos() / 2048.; p->Vel.Y = M_Random() * an.Sin() / 2048.; p->Acc.X = p->Vel.X / 16.; p->Acc.Y = p->Vel.Y / 16.; } an = angle + ((M_Random() - 128) * (90 / 256.)); p->Pos.X = pos.X + ((M_Random() & 31) - 15) * an.Cos(); p->Pos.Y = pos.Y + ((M_Random() & 31) - 15) * an.Sin(); p->Pos.Z = pos.Z + (M_Random() + zadd - 128) * zspread; p->renderstyle = STYLE_Translucent; } }
static bool DoGroupForOne (AActor *victim, AActor *source, AActor *dest, bool floorz, bool fog) { DAngle an = dest->Angles.Yaw - source->Angles.Yaw; DVector2 off = victim->Pos() - source->Pos(); DAngle offAngle = victim->Angles.Yaw - source->Angles.Yaw; DVector2 newp = { off.X * an.Cos() - off.Y * an.Sin(), off.X * an.Sin() + off.Y * an.Cos() }; double z = floorz ? ONFLOORZ : dest->Z() + victim->Z() - source->Z(); bool res = P_Teleport (victim, DVector3(dest->Pos().XY() + newp, z), 0., fog ? (TELF_DESTFOG | TELF_SOURCEFOG) : TELF_KEEPORIENTATION); // P_Teleport only changes angle if fog is true victim->Angles.Yaw = (dest->Angles.Yaw + victim->Angles.Yaw - source->Angles.Yaw).Normalized360(); return res; }
void FGLRenderer::FillSimplePoly(FTexture *texture, FVector2 *points, int npoints, double originx, double originy, double scalex, double scaley, DAngle rotation, FDynamicColormap *colormap, int lightlevel) { if (npoints < 3) { // This is no polygon. return; } FMaterial *gltexture = FMaterial::ValidateTexture(texture); if (gltexture == NULL) { return; } FColormap cm; cm = colormap; lightlevel = gl_CalcLightLevel(lightlevel, 0, true); PalEntry pe = gl_CalcLightColor(lightlevel, cm.LightColor, cm.blendfactor, true); glColor3ub(pe.r, pe.g, pe.b); gltexture->Bind(cm.colormap); int i; bool dorotate = rotation != 0; float cosrot = cos(rotation.Radians()); float sinrot = sin(rotation.Radians()); //float yoffs = GatheringWipeScreen ? 0 : LBOffset; float uscale = float(1.f / (texture->GetScaledWidth() * scalex)); float vscale = float(1.f / (texture->GetScaledHeight() * scaley)); if (gltexture->tex->bHasCanvas) { vscale = 0 - vscale; } float ox = float(originx); float oy = float(originy); gl_RenderState.Apply(); glBegin(GL_TRIANGLE_FAN); for (i = 0; i < npoints; ++i) { float u = points[i].X - 0.5f - ox; float v = points[i].Y - 0.5f - oy; if (dorotate) { float t = u; u = t * cosrot - v * sinrot; v = v * cosrot + t * sinrot; } glTexCoord2f(u * uscale, v * vscale); glVertex3f(points[i].X, points[i].Y /* + yoffs */, 0); } glEnd(); }
DEFINE_ACTION_FUNCTION_PARAMS(AActor, A_FireGrenade) { PARAM_ACTION_PROLOGUE; PARAM_CLASS(grenadetype, AActor); PARAM_ANGLE(angleofs); PARAM_STATE(flash) player_t *player = self->player; AActor *grenade; DAngle an; AWeapon *weapon; if (player == nullptr || grenadetype == nullptr) return 0; if ((weapon = player->ReadyWeapon) == nullptr) return 0; if (!weapon->DepleteAmmo (weapon->bAltFire)) return 0; P_SetPsprite (player, PSP_FLASH, flash, true); if (grenadetype != nullptr) { self->AddZ(32); grenade = P_SpawnSubMissile (self, grenadetype, self); self->AddZ(-32); if (grenade == nullptr) return 0; if (grenade->SeeSound != 0) { S_Sound (grenade, CHAN_VOICE, grenade->SeeSound, 1, ATTN_NORM); } grenade->Vel.Z = (-self->Angles.Pitch.TanClamped()) * grenade->Speed + 8; DVector2 offset = self->Angles.Yaw.ToVector(self->radius + grenade->radius); DAngle an = self->Angles.Yaw + angleofs; offset += an.ToVector(15); grenade->SetOrigin(grenade->Vec3Offset(offset.X, offset.Y, 0.), false); } return 0; }
//========================================================================== // // // //========================================================================== void ADynamicLight::UpdateLocation() { double oldx= X(); double oldy= Y(); double oldradius= radius; float intensity; if (IsActive()) { if (target) { DAngle angle = target->Angles.Yaw; double s = angle.Sin(); double c = angle.Cos(); DVector3 pos = target->Vec3Offset(m_off.X * c + m_off.Y * s, m_off.X * s - m_off.Y * c, m_off.Z + target->GetBobOffset()); SetXYZ(pos); // attached lights do not need to go into the regular blockmap Prev = target->Pos(); subsector = R_PointInSubsector(Prev); Sector = subsector->sector; } // The radius being used here is always the maximum possible with the // current settings. This avoids constant relinking of flickering lights if (lighttype == FlickerLight || lighttype == RandomFlickerLight || lighttype == PulseLight) { intensity = float(MAX(m_Radius[0], m_Radius[1])); } else { intensity = m_currentRadius; } radius = intensity * 2.0f * gl_lights_size; if (X() != oldx || Y() != oldy || radius != oldradius) { //Update the light lists LinkLight(); } } }
void P_SetSlope (secplane_t *plane, bool setCeil, int xyangi, int zangi, const DVector3 &pos) { DAngle xyang; DAngle zang; if (zangi >= 180) { zang = 179.; } else if (zangi <= 0) { zang = 1.; } else { zang = (double)zangi; } if (setCeil) { zang += 180.; } xyang = (double)xyangi; DVector3 norm; if (ib_compatflags & BCOMPATF_SETSLOPEOVERFLOW) { // We have to consider an integer multiplication overflow here. norm[0] = FixedToFloat(FloatToFixed(zang.Cos()) * FloatToFixed(xyang.Cos())); norm[1] = FixedToFloat(FloatToFixed(zang.Cos()) * FloatToFixed(xyang.Sin())); } else { norm[0] = zang.Cos() * xyang.Cos(); norm[1] = zang.Cos() * xyang.Sin(); } norm[2] = zang.Sin(); norm.MakeUnit(); double dist = -norm[0] * pos.X - norm[1] * pos.Y - norm[2] * pos.Z; plane->set(norm[0], norm[1], norm[2], dist); }
// [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; }
bool EV_Teleport (int tid, int tag, line_t *line, int side, AActor *thing, int flags) { AActor *searcher; double z; DAngle angle = 0.; double s = 0, c = 0; double vx = 0, vy = 0; DAngle badangle = 0.; if (thing == NULL) { // Teleport function called with an invalid actor return false; } bool predicting = (thing->player && (thing->player->cheats & CF_PREDICTING)); if (thing->flags2 & MF2_NOTELEPORT) { return false; } if (side != 0) { // Don't teleport if hit back of line, so you can get out of teleporter. return 0; } searcher = SelectTeleDest(tid, tag, predicting); if (searcher == NULL) { return false; } // [RH] Lee Killough's changes for silent teleporters from BOOM if ((flags & (TELF_ROTATEBOOM|TELF_ROTATEBOOMINVERSE)) && line) { // Get the angle between the exit thing and source linedef. // Rotate 90 degrees, so that walking perpendicularly across // teleporter linedef causes thing to exit in the direction // indicated by the exit thing. angle = line->Delta().Angle() - searcher->Angles.Yaw + 90.; if (flags & TELF_ROTATEBOOMINVERSE) angle = -angle; // Sine, cosine of angle adjustment s = angle.Sin(); c = angle.Cos(); // Velocity of thing crossing teleporter linedef vx = thing->Vel.X; vy = thing->Vel.Y; z = searcher->Z(); } else if (searcher->IsKindOf (PClass::FindClass(NAME_TeleportDest2))) { z = searcher->Z(); } else { z = ONFLOORZ; } if ((i_compatflags2 & COMPATF2_BADANGLES) && (thing->player != NULL)) { badangle = 0.01; } if (P_Teleport (thing, DVector3(searcher->Pos(), z), searcher->Angles.Yaw + badangle, flags)) { // [RH] Lee Killough's changes for silent teleporters from BOOM if (line) { if (flags & (TELF_ROTATEBOOM| TELF_ROTATEBOOMINVERSE)) { // Rotate thing according to difference in angles (or not - Boom got the direction wrong here.) thing->Angles.Yaw += angle; // Rotate thing's velocity to come out of exit just like it entered thing->Vel.X = vx*c - vy*s; thing->Vel.Y = vy*c + vx*s; } } if (vx == 0 && vy == 0 && thing->player != NULL && thing->player->mo == thing && !predicting) { thing->player->mo->PlayIdle (); } return true; } return false; }
void FGLRenderer::FillSimplePoly(FTexture *texture, FVector2 *points, int npoints, double originx, double originy, double scalex, double scaley, DAngle rotation, FDynamicColormap *colormap, int lightlevel) { if (npoints < 3) { // This is no polygon. return; } FMaterial *gltexture = FMaterial::ValidateTexture(texture, false); if (gltexture == NULL) { return; } FColormap cm; cm = colormap; // We cannot use the software light mode here because it doesn't properly calculate the light for 2D rendering. SBYTE savedlightmode = glset.lightmode; if (glset.lightmode == 8) glset.lightmode = 0; gl_SetColor(lightlevel, 0, cm, 1.f); glset.lightmode = savedlightmode; gl_RenderState.SetMaterial(gltexture, CLAMP_NONE, 0, -1, false); int i; bool dorotate = rotation != 0; float cosrot = cos(rotation.Radians()); float sinrot = sin(rotation.Radians()); //float yoffs = GatheringWipeScreen ? 0 : LBOffset; float uscale = float(1.f / (texture->GetScaledWidth() * scalex)); float vscale = float(1.f / (texture->GetScaledHeight() * scaley)); if (gltexture->tex->bHasCanvas) { vscale = 0 - vscale; } float ox = float(originx); float oy = float(originy); gl_RenderState.Apply(); FFlatVertex *ptr = GLRenderer->mVBO->GetBuffer(); for (i = 0; i < npoints; ++i) { float u = points[i].X - 0.5f - ox; float v = points[i].Y - 0.5f - oy; if (dorotate) { float t = u; u = t * cosrot - v * sinrot; v = v * cosrot + t * sinrot; } ptr->Set(points[i].X, points[i].Y, 0, u*uscale, v*vscale); ptr++; } GLRenderer->mVBO->RenderCurrent(ptr, GL_TRIANGLE_FAN); }
int P_Thing_Warp(AActor *caller, AActor *reference, double xofs, double yofs, double zofs, DAngle angle, int flags, double heightoffset, double radiusoffset, DAngle pitch) { if (flags & WARPF_MOVEPTR) { AActor *temp = reference; reference = caller; caller = temp; } DVector3 old = caller->Pos(); int oldpgroup = caller->Sector->PortalGroup; zofs += reference->Height * heightoffset; if (!(flags & WARPF_ABSOLUTEANGLE)) { angle += (flags & WARPF_USECALLERANGLE) ? caller->Angles.Yaw: reference->Angles.Yaw; } const double rad = radiusoffset * reference->radius; const double s = angle.Sin(); const double c = angle.Cos(); if (!(flags & WARPF_ABSOLUTEPOSITION)) { if (!(flags & WARPF_ABSOLUTEOFFSET)) { double xofs1 = xofs; // (borrowed from A_SpawnItemEx, assumed workable) // in relative mode negative y values mean 'left' and positive ones mean 'right' // This is the inverse orientation of the absolute mode! xofs = xofs1 * c + yofs * s; yofs = xofs1 * s - yofs * c; } if (flags & WARPF_TOFLOOR) { // set correct xy // now the caller's floorz should be appropriate for the assigned xy-position // assigning position again with. // extra unlink, link and environment calculation caller->SetOrigin(reference->Vec3Offset(xofs + rad * c, yofs + rad * s, 0.), true); // The two-step process is important. caller->SetZ(caller->floorz + zofs); } else { caller->SetOrigin(reference->Vec3Offset(xofs + rad * c, yofs + rad * s, zofs), true); } } else // [MC] The idea behind "absolute" is meant to be "absolute". Override everything, just like A_SpawnItemEx's. { caller->SetOrigin(xofs + rad * c, yofs + rad * s, zofs, true); if (flags & WARPF_TOFLOOR) { caller->SetZ(caller->floorz + zofs); } } if ((flags & WARPF_NOCHECKPOSITION) || P_TestMobjLocation(caller)) { if (flags & WARPF_TESTONLY) { caller->SetOrigin(old, true); } else { caller->Angles.Yaw = angle; if (flags & WARPF_COPYPITCH) caller->SetPitch(reference->Angles.Pitch, false); if (pitch != 0) caller->SetPitch(caller->Angles.Pitch + pitch, false); if (flags & WARPF_COPYVELOCITY) { caller->Vel = reference->Vel; } if (flags & WARPF_STOP) { caller->Vel.Zero(); } // this is no fun with line portals if (flags & WARPF_WARPINTERPOLATION) { // This just translates the movement but doesn't change the vector DVector3 displacedold = old + Displacements.getOffset(oldpgroup, caller->Sector->PortalGroup); caller->Prev += caller->Pos() - displacedold; caller->PrevPortalGroup = caller->Sector->PortalGroup; } else if (flags & WARPF_COPYINTERPOLATION) { // Map both positions of the reference actor to the current portal group DVector3 displacedold = old + Displacements.getOffset(reference->PrevPortalGroup, caller->Sector->PortalGroup); DVector3 displacedref = old + Displacements.getOffset(reference->Sector->PortalGroup, caller->Sector->PortalGroup); caller->Prev = caller->Pos() + displacedold - displacedref; caller->PrevPortalGroup = caller->Sector->PortalGroup; } else if (!(flags & WARPF_INTERPOLATE)) { caller->ClearInterpolation(); } if ((flags & WARPF_BOB) && (reference->flags2 & MF2_FLOATBOB)) { caller->AddZ(reference->GetBobOffset()); } } return true; } caller->SetOrigin(old, true); return false; }
void RenderPolyWallSprite::Render(const TriMatrix &worldToClip, AActor *thing, subsector_t *sub, uint32_t subsectorDepth) { if (RenderPolySprite::IsThingCulled(thing)) return; DVector3 pos = thing->InterpolatedPosition(r_TicFracF); pos.Z += thing->GetBobOffset(r_TicFracF); bool flipTextureX = false; FTexture *tex = RenderPolySprite::GetSpriteTexture(thing, flipTextureX); if (tex == nullptr) return; DVector2 spriteScale = thing->Scale; double thingxscalemul = spriteScale.X / tex->Scale.X; double thingyscalemul = spriteScale.Y / tex->Scale.Y; double spriteHeight = thingyscalemul * tex->GetHeight(); DAngle ang = thing->Angles.Yaw + 90; double angcos = ang.Cos(); double angsin = ang.Sin(); // Determine left and right edges of sprite. The sprite's angle is its normal, // so the edges are 90 degrees each side of it. double x2 = tex->GetScaledWidth() * spriteScale.X; double x1 = tex->GetScaledLeftOffset() * spriteScale.X; DVector2 left, right; left.X = pos.X - x1 * angcos; left.Y = pos.Y - x1 * angsin; right.X = left.X + x2 * angcos; right.Y = right.Y + x2 * angsin; //int scaled_to = tex->GetScaledTopOffset(); //int scaled_bo = scaled_to - tex->GetScaledHeight(); //gzt = pos.Z + scale.Y * scaled_to; //gzb = pos.Z + scale.Y * scaled_bo; DVector2 points[2] = { left, right }; TriVertex *vertices = PolyVertexBuffer::GetVertices(4); if (!vertices) return; bool foggy = false; int actualextralight = foggy ? 0 : extralight << 4; std::pair<float, float> offsets[4] = { { 0.0f, 1.0f }, { 1.0f, 1.0f }, { 1.0f, 0.0f }, { 0.0f, 0.0f }, }; for (int i = 0; i < 4; i++) { auto &p = (i == 0 || i == 3) ? points[0] : points[1]; vertices[i].x = (float)p.X; vertices[i].y = (float)p.Y; vertices[i].z = (float)(pos.Z + spriteHeight * offsets[i].second); vertices[i].w = 1.0f; vertices[i].varying[0] = (float)(offsets[i].first * tex->Scale.X); vertices[i].varying[1] = (float)((1.0f - offsets[i].second) * tex->Scale.Y); if (flipTextureX) vertices[i].varying[0] = 1.0f - vertices[i].varying[0]; } bool fullbrightSprite = ((thing->renderflags & RF_FULLBRIGHT) || (thing->flags5 & MF5_BRIGHT)); TriUniforms uniforms; if (fullbrightSprite || fixedlightlev >= 0 || fixedcolormap) { uniforms.light = 256; uniforms.flags = TriUniforms::fixed_light; } else { uniforms.light = (uint32_t)((thing->Sector->lightlevel + actualextralight) / 255.0f * 256.0f); uniforms.flags = 0; } uniforms.subsectorDepth = subsectorDepth; PolyDrawArgs args; args.uniforms = uniforms; args.objectToClip = &worldToClip; args.vinput = vertices; args.vcount = 4; args.mode = TriangleDrawMode::Fan; args.ccw = true; args.stenciltestvalue = 0; args.stencilwritevalue = 1; args.SetTexture(tex); args.SetColormap(sub->sector->ColorMap); PolyTriangleDrawer::draw(args, TriDrawVariant::DrawSubsector, TriBlendMode::AlphaBlend); }
void P_RunEffect (AActor *actor, int effects) { DAngle moveangle = actor->Vel.Angle(); FParticle *particle; int i; if ((effects & FX_ROCKET) && (cl_rockettrails & 1)) { // Rocket trail double backx = -actor->radius * 2 * moveangle.Cos(); double backy = -actor->radius * 2 * moveangle.Sin(); double backz = actor->Height * ((2. / 3) - actor->Vel.Z / 8); DAngle an = moveangle + 90.; double speed; particle = JitterParticle (actor->Level, 3 + (M_Random() & 31)); if (particle) { double pathdist = M_Random() / 256.; DVector3 pos = actor->Vec3Offset( backx - actor->Vel.X * pathdist, backy - actor->Vel.Y * pathdist, backz - actor->Vel.Z * pathdist); particle->Pos = pos; speed = (M_Random () - 128) * (1./200); particle->Vel.X += speed * an.Cos(); particle->Vel.Y += speed * an.Sin(); particle->Vel.Z -= 1./36; particle->Acc.Z -= 1./20; particle->color = yellow; particle->size = 2; } for (i = 6; i; i--) { FParticle *particle = JitterParticle (actor->Level, 3 + (M_Random() & 31)); if (particle) { double pathdist = M_Random() / 256.; DVector3 pos = actor->Vec3Offset( backx - actor->Vel.X * pathdist, backy - actor->Vel.Y * pathdist, backz - actor->Vel.Z * pathdist + (M_Random() / 64.)); particle->Pos = pos; speed = (M_Random () - 128) * (1./200); particle->Vel.X += speed * an.Cos(); particle->Vel.Y += speed * an.Sin(); particle->Vel.Z += 1. / 80; particle->Acc.Z += 1. / 40; if (M_Random () & 7) particle->color = grey2; else particle->color = grey1; particle->size = 3; } else break; } } if ((effects & FX_GRENADE) && (cl_rockettrails & 1)) { // Grenade trail DVector3 pos = actor->Vec3Angle(-actor->radius * 2, moveangle, -actor->Height * actor->Vel.Z / 8 + actor->Height * (2. / 3)); P_DrawSplash2 (actor->Level, 6, pos, moveangle + 180, 2, 2); } if (actor->fountaincolor) { // Particle fountain static const int *fountainColors[16] = { &black, &black, &red, &red1, &green, &green1, &blue, &blue1, &yellow, &yellow1, &purple, &purple1, &black, &grey3, &grey4, &white }; int color = actor->fountaincolor*2; MakeFountain (actor, *fountainColors[color], *fountainColors[color+1]); } if (effects & FX_RESPAWNINVUL) { // Respawn protection static const int *protectColors[2] = { &yellow1, &white }; for (i = 3; i > 0; i--) { particle = JitterParticle (actor->Level, 16); if (particle != NULL) { DAngle ang = M_Random() * (360 / 256.); DVector3 pos = actor->Vec3Angle(actor->radius, ang, 0); particle->Pos = pos; particle->color = *protectColors[M_Random() & 1]; particle->Vel.Z = 1; particle->Acc.Z = M_Random () / 512.; particle->size = 1; if (M_Random () < 128) { // make particle fall from top of actor particle->Pos.Z += actor->Height; particle->Vel.Z = -particle->Vel.Z; particle->Acc.Z = -particle->Acc.Z; } } } } }
bool P_Teleport (AActor *thing, DVector3 pos, DAngle angle, int flags) { bool predicting = (thing->player && (thing->player->cheats & CF_PREDICTING)); DVector3 old; double aboveFloor; player_t *player; sector_t *destsect; bool resetpitch = false; double floorheight, ceilingheight; double missilespeed = 0; old = thing->Pos(); aboveFloor = thing->Z() - thing->floorz; destsect = P_PointInSector (pos); // killough 5/12/98: exclude voodoo dolls: player = thing->player; if (player && player->mo != thing) player = NULL; floorheight = destsect->floorplane.ZatPoint (pos); ceilingheight = destsect->ceilingplane.ZatPoint (pos); if (thing->flags & MF_MISSILE) { // We don't measure z velocity, because it doesn't change. missilespeed = thing->VelXYToSpeed(); } if (flags & TELF_KEEPHEIGHT) { pos.Z = floorheight + aboveFloor; } else if (pos.Z == ONFLOORZ) { if (player) { if (thing->flags & MF_NOGRAVITY && aboveFloor) { pos.Z = floorheight + aboveFloor; if (pos.Z + thing->Height > ceilingheight) { pos.Z = ceilingheight - thing->Height; } } else { pos.Z = floorheight; if (!(flags & TELF_KEEPORIENTATION)) { resetpitch = false; } } } else if (thing->flags & MF_MISSILE) { pos.Z = floorheight + aboveFloor; if (pos.Z + thing->Height > ceilingheight) { pos.Z = ceilingheight - thing->Height; } } else { pos.Z = floorheight; } } if (!P_TeleportMove (thing, pos, false)) { return false; } if (player) { player->viewz = thing->Z() + player->viewheight; if (resetpitch) { player->mo->Angles.Pitch = 0.; } } if (!(flags & TELF_KEEPORIENTATION)) { thing->Angles.Yaw = angle; } else { angle = thing->Angles.Yaw; } // Spawn teleport fog at source and destination if ((flags & TELF_SOURCEFOG) && !predicting) { P_SpawnTeleportFog(thing, old, true, true); //Passes the actor through which then pulls the TeleFog metadata types based on properties. } if (flags & TELF_DESTFOG) { if (!predicting) { DVector2 vector = angle.ToVector(20); DVector2 fogpos = P_GetOffsetPosition(pos.X, pos.Y, vector.X, vector.Y); P_SpawnTeleportFog(thing, DVector3(fogpos, thing->Z()), false, true); } if (thing->player) { // [RH] Zoom player's field of vision // [BC] && bHaltVelocity. if (telezoom && thing->player->mo == thing && !(flags & TELF_KEEPVELOCITY)) thing->player->FOV = MIN (175.f, thing->player->DesiredFOV + 45.f); } } // [BC] && bHaltVelocity. if (thing->player && ((flags & TELF_DESTFOG) || !(flags & TELF_KEEPORIENTATION)) && !(flags & TELF_KEEPVELOCITY)) { // Freeze player for about .5 sec if (thing->Inventory == NULL || !thing->Inventory->GetNoTeleportFreeze()) thing->reactiontime = 18; } if (thing->flags & MF_MISSILE) { thing->VelFromAngle(missilespeed); } // [BC] && bHaltVelocity. else if (!(flags & TELF_KEEPORIENTATION) && !(flags & TELF_KEEPVELOCITY)) { // no fog doesn't alter the player's momentum thing->Vel.Zero(); // killough 10/98: kill all bobbing velocity too if (player) player->Vel.Zero(); } return true; }
void RenderWallSprite::Project(RenderThread *thread, AActor *thing, const DVector3 &pos, FTexture *pic, const DVector2 &scale, int renderflags, int spriteshade, bool foggy, FDynamicColormap *basecolormap) { FWallCoords wallc; double x1, x2; DVector2 left, right; double gzb, gzt, tz; DAngle ang = thing->Angles.Yaw + 90; double angcos = ang.Cos(); double angsin = ang.Sin(); // Determine left and right edges of sprite. The sprite's angle is its normal, // so the edges are 90 degrees each side of it. x2 = pic->GetScaledWidth(); x1 = pic->GetScaledLeftOffsetSW(); x1 *= scale.X; x2 *= scale.X; left.X = pos.X - x1 * angcos - thread->Viewport->viewpoint.Pos.X; left.Y = pos.Y - x1 * angsin - thread->Viewport->viewpoint.Pos.Y; right.X = left.X + x2 * angcos; right.Y = left.Y + x2 * angsin; // Is it off-screen? if (wallc.Init(thread, left, right, TOO_CLOSE_Z)) return; RenderPortal *renderportal = thread->Portal.get(); if (wallc.sx1 >= renderportal->WindowRight || wallc.sx2 <= renderportal->WindowLeft) return; // Sprite sorting should probably treat these as walls, not sprites, // but right now, I just want to get them drawing. tz = (pos.X - thread->Viewport->viewpoint.Pos.X) * thread->Viewport->viewpoint.TanCos + (pos.Y - thread->Viewport->viewpoint.Pos.Y) * thread->Viewport->viewpoint.TanSin; int scaled_to = pic->GetScaledTopOffsetSW(); int scaled_bo = scaled_to - pic->GetScaledHeight(); gzt = pos.Z + scale.Y * scaled_to; gzb = pos.Z + scale.Y * scaled_bo; RenderWallSprite *vis = thread->FrameMemory->NewObject<RenderWallSprite>(); vis->CurrentPortalUniq = renderportal->CurrentPortalUniq; vis->x1 = wallc.sx1 < renderportal->WindowLeft ? renderportal->WindowLeft : wallc.sx1; vis->x2 = wallc.sx2 >= renderportal->WindowRight ? renderportal->WindowRight : wallc.sx2; vis->yscale = (float)scale.Y; vis->idepth = float(1 / tz); vis->depth = (float)tz; vis->sector = thing->Sector; vis->heightsec = NULL; vis->gpos = { (float)pos.X, (float)pos.Y, (float)pos.Z }; vis->gzb = (float)gzb; vis->gzt = (float)gzt; vis->deltax = float(pos.X - thread->Viewport->viewpoint.Pos.X); vis->deltay = float(pos.Y - thread->Viewport->viewpoint.Pos.Y); vis->renderflags = renderflags; if (thing->flags5 & MF5_BRIGHT) vis->renderflags |= RF_FULLBRIGHT; // kg3D vis->RenderStyle = thing->RenderStyle; vis->FillColor = thing->fillcolor; vis->Translation = thing->Translation; vis->FakeFlatStat = WaterFakeSide::Center; vis->Alpha = float(thing->Alpha); vis->fakefloor = NULL; vis->fakeceiling = NULL; //vis->bInMirror = renderportal->MirrorFlags & RF_XFLIP; vis->pic = pic; vis->wallc = wallc; vis->foggy = foggy; vis->Light.SetColormap(thread->Light->SpriteGlobVis(foggy) / MAX(tz, MINZ), spriteshade, basecolormap, false, false, false); thread->SpriteList->Push(vis); }
void RenderPolyWallSprite::Render(const TriMatrix &worldToClip, const PolyClipPlane &clipPlane, AActor *thing, subsector_t *sub, uint32_t subsectorDepth, uint32_t stencilValue) { if (RenderPolySprite::IsThingCulled(thing)) return; const auto &viewpoint = PolyRenderer::Instance()->Viewpoint; DVector3 pos = thing->InterpolatedPosition(viewpoint.TicFrac); pos.Z += thing->GetBobOffset(viewpoint.TicFrac); bool flipTextureX = false; FTexture *tex = RenderPolySprite::GetSpriteTexture(thing, flipTextureX); if (tex == nullptr || tex->UseType == FTexture::TEX_Null) return; DVector2 spriteScale = thing->Scale; double thingxscalemul = spriteScale.X / tex->Scale.X; double thingyscalemul = spriteScale.Y / tex->Scale.Y; double spriteHeight = thingyscalemul * tex->GetHeight(); DAngle ang = thing->Angles.Yaw + 90; double angcos = ang.Cos(); double angsin = ang.Sin(); // Determine left and right edges of sprite. The sprite's angle is its normal, // so the edges are 90 degrees each side of it. double x2 = tex->GetScaledWidth() * spriteScale.X; double x1 = tex->GetScaledLeftOffset() * spriteScale.X; DVector2 left, right; left.X = pos.X - x1 * angcos; left.Y = pos.Y - x1 * angsin; right.X = left.X + x2 * angcos; right.Y = left.Y + x2 * angsin; //int scaled_to = tex->GetScaledTopOffset(); //int scaled_bo = scaled_to - tex->GetScaledHeight(); //gzt = pos.Z + scale.Y * scaled_to; //gzb = pos.Z + scale.Y * scaled_bo; DVector2 points[2] = { left, right }; TriVertex *vertices = PolyRenderer::Instance()->FrameMemory.AllocMemory<TriVertex>(4); bool foggy = false; int actualextralight = foggy ? 0 : viewpoint.extralight << 4; std::pair<float, float> offsets[4] = { { 0.0f, 1.0f }, { 1.0f, 1.0f }, { 1.0f, 0.0f }, { 0.0f, 0.0f }, }; for (int i = 0; i < 4; i++) { auto &p = (i == 0 || i == 3) ? points[0] : points[1]; vertices[i].x = (float)p.X; vertices[i].y = (float)p.Y; vertices[i].z = (float)(pos.Z + spriteHeight * offsets[i].second); vertices[i].w = 1.0f; vertices[i].u = (float)(offsets[i].first * tex->Scale.X); vertices[i].v = (float)((1.0f - offsets[i].second) * tex->Scale.Y); if (flipTextureX) vertices[i].u = 1.0f - vertices[i].u; } bool fullbrightSprite = ((thing->renderflags & RF_FULLBRIGHT) || (thing->flags5 & MF5_BRIGHT)); int lightlevel = fullbrightSprite ? 255 : thing->Sector->lightlevel + actualextralight; PolyDrawArgs args; args.SetLight(GetColorTable(sub->sector->Colormap, sub->sector->SpecialColors[sector_t::sprites], true), lightlevel, PolyRenderer::Instance()->Light.WallGlobVis(foggy), fullbrightSprite); args.SetTransform(&worldToClip); args.SetFaceCullCCW(true); args.SetStencilTestValue(stencilValue); args.SetTexture(tex); args.SetClipPlane(clipPlane); args.SetSubsectorDepthTest(true); args.SetWriteSubsectorDepth(false); args.SetWriteStencil(false); args.SetStyle(TriBlendMode::TextureMasked); args.DrawArray(vertices, 4, PolyDrawMode::TriangleFan); }
void HWDrawInfo::GetDynSpriteLight(AActor *self, float x, float y, float z, FLightNode *node, int portalgroup, float *out) { FDynamicLight *light; float frac, lr, lg, lb; float radius; out[0] = out[1] = out[2] = 0.f; // Go through both light lists while (node) { light=node->lightsource; if (light->ShouldLightActor(self)) { float dist; FVector3 L; // This is a performance critical section of code where we cannot afford to let the compiler decide whether to inline the function or not. // This will do the calculations explicitly rather than calling one of AActor's utility functions. if (Level->Displacements.size > 0) { int fromgroup = light->Sector->PortalGroup; int togroup = portalgroup; if (fromgroup == togroup || fromgroup == 0 || togroup == 0) goto direct; DVector2 offset = Level->Displacements.getOffset(fromgroup, togroup); L = FVector3(x - (float)(light->X() + offset.X), y - (float)(light->Y() + offset.Y), z - (float)light->Z()); } else { direct: L = FVector3(x - (float)light->X(), y - (float)light->Y(), z - (float)light->Z()); } dist = (float)L.LengthSquared(); radius = light->GetRadius(); if (dist < radius * radius) { dist = sqrtf(dist); // only calculate the square root if we really need it. frac = 1.0f - (dist / radius); if (light->IsSpot()) { L *= -1.0f / dist; DAngle negPitch = -*light->pPitch; DAngle Angle = light->target->Angles.Yaw; double xyLen = negPitch.Cos(); double spotDirX = -Angle.Cos() * xyLen; double spotDirY = -Angle.Sin() * xyLen; double spotDirZ = -negPitch.Sin(); double cosDir = L.X * spotDirX + L.Y * spotDirY + L.Z * spotDirZ; frac *= (float)smoothstep(light->pSpotOuterAngle->Cos(), light->pSpotInnerAngle->Cos(), cosDir); } if (frac > 0 && (!light->shadowmapped || screen->mShadowMap.ShadowTest(light, { x, y, z }))) { lr = light->GetRed() / 255.0f; lg = light->GetGreen() / 255.0f; lb = light->GetBlue() / 255.0f; if (light->IsSubtractive()) { float bright = (float)FVector3(lr, lg, lb).Length(); FVector3 lightColor(lr, lg, lb); lr = (bright - lr) * -1; lg = (bright - lg) * -1; lb = (bright - lb) * -1; } out[0] += lr * frac; out[1] += lg * frac; out[2] += lb * frac; } } } node = node->nextLight; } }