From 7ed031122102700e01bdeb42bcda7a2a6a4ccd17 Mon Sep 17 00:00:00 2001 From: Randy Heit Date: Wed, 2 Jul 2008 03:50:17 +0000 Subject: [PATCH] - Polyobject sounds now play from their lines, similar to the way sector sounds are handled. - Why do polyobjects have a 3D start spot? Flattened it to 2D. - Moved the sector sound origin calculation out of fmodsound.cpp and into s_sound.cpp so that the near sound limiting will use the correct sound location for deciding on neighbors. SVN r1061 (trunk) --- docs/rh-log.txt | 8 ++ src/p_local.h | 1 + src/p_saveg.cpp | 7 +- src/po_man.cpp | 69 ++++++++++++++ src/r_defs.h | 2 +- src/s_sound.cpp | 201 ++++++++++++++++++++-------------------- src/sound/fmodsound.cpp | 46 +-------- src/version.h | 2 +- 8 files changed, 185 insertions(+), 151 deletions(-) diff --git a/docs/rh-log.txt b/docs/rh-log.txt index 25b09a9ab..aa6f81b50 100644 --- a/docs/rh-log.txt +++ b/docs/rh-log.txt @@ -1,3 +1,11 @@ +July 1, 2008 +- Polyobject sounds now play from their lines, similar to the way sector + sounds are handled. +- Why do polyobjects have a 3D start spot? Flattened it to 2D. +- Moved the sector sound origin calculation out of fmodsound.cpp and into + s_sound.cpp so that the near sound limiting will use the correct sound + location for deciding on neighbors. + June 30, 2008 - Removed the S_Sound() variant that allows for pointing the origin at an arbitrary point. It has been replaced with a variant that takes a polyobject diff --git a/src/p_local.h b/src/p_local.h index 34d7369db..559cdbbc4 100644 --- a/src/p_local.h +++ b/src/p_local.h @@ -496,6 +496,7 @@ bool PO_MovePolyobj (int num, int x, int y, bool force=false); bool PO_RotatePolyobj (int num, angle_t angle); void PO_Init (); bool PO_Busy (int polyobj); +void PO_ClosestPoint(const FPolyObj *poly, fixed_t ox, fixed_t oy, fixed_t &x, fixed_t &y, seg_t **seg); // // P_SPEC diff --git a/src/p_saveg.cpp b/src/p_saveg.cpp index 49d7ea8ad..682d6963f 100644 --- a/src/p_saveg.cpp +++ b/src/p_saveg.cpp @@ -474,14 +474,14 @@ void P_SerializePolyobjs (FArchive &arc) for(i = 0, po = polyobjs; i < po_NumPolyobjs; i++, po++) { arc << po->tag << po->angle << po->startSpot[0] << - po->startSpot[1] << po->startSpot[2] << po->interpolation; + po->startSpot[1] << po->interpolation; } } else { int data; angle_t angle; - fixed_t deltaX, deltaY, deltaZ; + fixed_t deltaX, deltaY; arc << data; if (data != ASEG_POLYOBJS) @@ -501,10 +501,9 @@ void P_SerializePolyobjs (FArchive &arc) } arc << angle; PO_RotatePolyobj (po->tag, angle); - arc << deltaX << deltaY << deltaZ << po->interpolation; + arc << deltaX << deltaY << po->interpolation; deltaX -= po->startSpot[0]; deltaY -= po->startSpot[1]; - deltaZ -= po->startSpot[2]; PO_MovePolyobj (po->tag, deltaX, deltaY, true); } } diff --git a/src/po_man.cpp b/src/po_man.cpp index 226682ae8..6a090b475 100644 --- a/src/po_man.cpp +++ b/src/po_man.cpp @@ -1671,6 +1671,75 @@ bool PO_Busy (int polyobj) } } +//=========================================================================== +// +// PO_ClosestPoint +// +// Given a point (x,y), returns the point (ox,oy) on the polyobject's walls +// that is nearest to (x,y). Also returns the seg this point came from. +// +//=========================================================================== + +void PO_ClosestPoint(const FPolyObj *poly, fixed_t fx, fixed_t fy, fixed_t &ox, fixed_t &oy, seg_t **seg) +{ + int i; + double x = fx, y = fy; + double bestdist = HUGE_VAL; + double bestx = 0, besty = 0; + seg_t *bestseg = NULL; + + for (i = 0; i < poly->numsegs; ++i) + { + vertex_t *v1 = poly->segs[i]->v1; + vertex_t *v2 = poly->segs[i]->v2; + double a = v2->x - v1->x; + double b = v2->y - v1->y; + double den = a*a + b*b; + double ix, iy, dist; + + if (den == 0) + { // Line is actually a point! + ix = v1->x; + iy = v1->y; + } + else + { + double num = (x - v1->x) * a + (y - v1->y) * b; + double u = num / den; + if (u <= 0) + { + ix = v1->x; + iy = v1->y; + } + else if (u >= 1) + { + ix = v2->x; + iy = v2->y; + } + else + { + ix = v1->x + u * a; + iy = v1->y + u * b; + } + } + a = (ix - x); + b = (iy - y); + dist = a*a + b*b; + if (dist < bestdist) + { + bestdist = dist; + bestx = ix; + besty = iy; + bestseg = poly->segs[i]; + } + } + ox = fixed_t(bestx); + oy = fixed_t(besty); + if (seg != NULL) + { + *seg = bestseg; + } +} FPolyObj::~FPolyObj() { diff --git a/src/r_defs.h b/src/r_defs.h index 15b878032..510d50f20 100644 --- a/src/r_defs.h +++ b/src/r_defs.h @@ -769,7 +769,7 @@ struct FPolyObj line_t **lines; int numvertices; vertex_t **vertices; - fixed_t startSpot[3]; + fixed_t startSpot[2]; vertex_t *originalPts; // used as the base for the rotations vertex_t *prevPts; // use to restore the old point values angle_t angle; diff --git a/src/s_sound.cpp b/src/s_sound.cpp index d816cad29..d990342a5 100644 --- a/src/s_sound.cpp +++ b/src/s_sound.cpp @@ -104,7 +104,9 @@ static bool S_CheckSoundLimit(sfxinfo_t *sfx, const FVector3 &pos, int near_limi static void S_ActivatePlayList(bool goBack); static void CalcPosVel(const FSoundChan *chan, FVector3 *pos, FVector3 *vel); static void CalcPosVel(int type, const AActor *actor, const sector_t *sector, const FPolyObj *poly, - const FVector3 *pt, int constz, FVector3 *pos, FVector3 *vel); + const float pt[3], int channel, int chanflags, FVector3 *pos, FVector3 *vel); +static void CalcSectorSoundOrg(const sector_t *sec, int channum, fixed_t *x, fixed_t *y, fixed_t *z); +static void CalcPolyobjSoundOrg(const FPolyObj *poly, fixed_t *x, fixed_t *y, fixed_t *z); static FSoundChan *S_StartSound(AActor *mover, const sector_t *sec, const FPolyObj *poly, const FVector3 *pt, int channel, FSoundID sound_id, float volume, float attenuation); static sfxinfo_t *S_LoadSound(sfxinfo_t *sfx); @@ -212,7 +214,6 @@ void S_NoiseDebug (void) // Distance if (chan->DistanceScale > 0) { - origin /= FRACUNIT; sprintf (temp, "%.0f", (origin - listener).Length()); screen->DrawText (color, 260, y, temp, TAG_DONE); } @@ -606,78 +607,10 @@ void S_LinkChannel(FSoundChan *chan, FSoundChan **head) // //========================================================================= -void CalcPosVel(const FSoundChan *chan, FVector3 *pos, FVector3 *vel) +static void CalcPosVel(const FSoundChan *chan, FVector3 *pos, FVector3 *vel) { - if (pos != NULL) - { - fixed_t x, y, z; - - switch (chan->SourceType) - { - case SOURCE_None: - default: - if (players[consoleplayer].camera != NULL) - { - x = players[consoleplayer].camera->x; - y = players[consoleplayer].camera->z; - z = players[consoleplayer].camera->y; - } - else - { - z = y = x = 0; - } - break; - - case SOURCE_Actor: - x = chan->Actor->x; - y = chan->Actor->z; - z = chan->Actor->y; - break; - - case SOURCE_Sector: - x = chan->Sector->soundorg[0]; - y = players[consoleplayer].camera != NULL ? players[consoleplayer].camera->z : 0; - z = chan->Sector->soundorg[1]; - break; - - case SOURCE_Polyobj: - x = chan->Poly->startSpot[0]; - y = chan->Poly->startSpot[2]; - z = chan->Poly->startSpot[1]; - break; - - case SOURCE_Unattached: - pos->X = chan->Point[0]; - pos->Y = !(chan->ChanFlags & CHAN_LISTENERZ) ? chan->Point[1] - : FIXED2FLOAT(players[consoleplayer].camera->z); - pos->Z = chan->Point[2]; - break; - } - if (chan->SourceType != SOURCE_Unattached) - { - if (chan->ChanFlags & CHAN_LISTENERZ) - { - y = players[consoleplayer].camera != NULL ? players[consoleplayer].camera->z : 0; - } - pos->X = FIXED2FLOAT(x); - pos->Y = FIXED2FLOAT(y); - pos->Z = FIXED2FLOAT(z); - } - } - if (vel != NULL) - { - // Only actors maintain velocity information. - if (chan->SourceType == SOURCE_Actor) - { - vel->X = FIXED2FLOAT(chan->Actor->momx) * TICRATE; - vel->Y = FIXED2FLOAT(chan->Actor->momz) * TICRATE; - vel->Z = FIXED2FLOAT(chan->Actor->momy) * TICRATE; - } - else - { - vel->Zero(); - } - } + CalcPosVel(chan->SourceType, chan->Actor, chan->Sector, chan->Poly, chan->Point, + chan->EntChannel, chan->ChanFlags, pos, vel); } //========================================================================= @@ -689,26 +622,27 @@ void CalcPosVel(const FSoundChan *chan, FVector3 *pos, FVector3 *vel) //========================================================================= static void CalcPosVel(int type, const AActor *actor, const sector_t *sector, - const FPolyObj *poly, const FVector3 *pt, int constz, FVector3 *pos, FVector3 *vel) + const FPolyObj *poly, const float pt[3], int channum, int chanflags, FVector3 *pos, FVector3 *vel) { if (pos != NULL) { fixed_t x, y, z; + if (players[consoleplayer].camera != NULL) + { + x = players[consoleplayer].camera->x; + y = players[consoleplayer].camera->z; + z = players[consoleplayer].camera->y; + } + else + { + z = y = x = 0; + } + switch (type) { case SOURCE_None: default: - if (players[consoleplayer].camera != NULL) - { - x = players[consoleplayer].camera->x; - y = players[consoleplayer].camera->z; - z = players[consoleplayer].camera->y; - } - else - { - z = y = x = 0; - } break; case SOURCE_Actor: @@ -718,26 +652,31 @@ static void CalcPosVel(int type, const AActor *actor, const sector_t *sector, break; case SOURCE_Sector: - x = sector->soundorg[0]; - y = players[consoleplayer].camera != NULL ? players[consoleplayer].camera->z : 0; - z = sector->soundorg[1]; + if (chanflags & CHAN_AREA) + { + CalcSectorSoundOrg(sector, channum, &x, &z, &y); + } + else + { + x = sector->soundorg[0]; + z = sector->soundorg[1]; + chanflags |= CHAN_LISTENERZ; + } break; case SOURCE_Polyobj: - x = poly->startSpot[0]; - y = poly->startSpot[2]; - z = poly->startSpot[1]; + CalcPolyobjSoundOrg(poly, &x, &z, &y); break; case SOURCE_Unattached: - pos->X = pt->X; - pos->Y = !constz ? pt->Y : FIXED2FLOAT(players[consoleplayer].camera->z); - pos->Z = pt->Z; + pos->X = pt[0]; + pos->Y = !(chanflags & CHAN_LISTENERZ) ? pt[1] : FIXED2FLOAT(players[consoleplayer].camera->z); + pos->Z = pt[2]; break; } if (type != SOURCE_Unattached) { - if (constz) + if (chanflags & CHAN_LISTENERZ) { y = players[consoleplayer].camera != NULL ? players[consoleplayer].camera->z : 0; } @@ -762,6 +701,67 @@ static void CalcPosVel(int type, const AActor *actor, const sector_t *sector, } } +//========================================================================== +// +// CalcSectorSoundOrg +// +// Returns the perceived sound origin for a sector. If the listener is +// inside the sector, then the origin is their location. Otherwise, the +// origin is from the nearest wall on the sector. +// +//========================================================================== + +static void CalcSectorSoundOrg(const sector_t *sec, int channum, fixed_t *x, fixed_t *y, fixed_t *z) +{ + // Are we inside the sector? If yes, the closest point is the one we're on. + if (P_PointInSector(*x, *y) == sec) + { + *x = players[consoleplayer].camera->x; + *y = players[consoleplayer].camera->y; + } + else + { + // Find the closest point on the sector's boundary lines and use + // that as the perceived origin of the sound. + sec->ClosestPoint(*x, *y, *x, *y); + } + + // Set sound vertical position based on channel. + if (channum == CHAN_FLOOR) + { + *z = MIN(sec->floorplane.ZatPoint(*x, *y), *z); + } + else if (channum == CHAN_CEILING) + { + *z = MAX(sec->ceilingplane.ZatPoint(*x, *y), *z); + } + else if (channum == CHAN_INTERIOR) + { + *z = clamp(*z, sec->floorplane.ZatPoint(*x, *y), sec->ceilingplane.ZatPoint(*x, *y)); + } +} + +//========================================================================== +// +// CalcPolySoundOrg +// +// Returns the perceived sound origin for a polyobject. This is similar to +// CalcSectorSoundOrg, except there is no special case for being "inside" +// a polyobject, so the sound literally comes from the polyobject's walls. +// Vertical position of the sound always comes from the visible wall. +// +//========================================================================== + +static void CalcPolyobjSoundOrg(const FPolyObj *poly, fixed_t *x, fixed_t *y, fixed_t *z) +{ + seg_t *seg; + sector_t *sec; + + PO_ClosestPoint(poly, *x, *y, *x, *y, &seg); + sec = seg->frontsector; + *z = clamp(*z, sec->floorplane.ZatPoint(*x, *y), sec->ceilingplane.ZatPoint(*x, *y)); +} + //========================================================================== // // S_StartSound @@ -811,23 +811,20 @@ static FSoundChan *S_StartSound(AActor *actor, const sector_t *sec, const FPolyO org_id = sound_id; chanflags = channel & ~7; + channel &= 7; - CalcPosVel(type, actor, sec, poly, pt, chanflags & CHAN_LISTENERZ, &pos, &vel); + CalcPosVel(type, actor, sec, poly, &pt->X, channel, chanflags, &pos, &vel); if (i_compatflags & COMPATF_MAGICSILENCE) { // For people who just can't play without a silent BFG. channel = CHAN_WEAPON; } - else + else if ((chanflags & CHAN_MAYBE_LOCAL) && (i_compatflags & COMPATF_SILENTPICKUP)) { - if ((channel & CHAN_MAYBE_LOCAL) && (i_compatflags & COMPATF_SILENTPICKUP)) + if (actor != NULL && actor != players[consoleplayer].camera) { - if (actor != NULL && actor != players[consoleplayer].camera) - { - return NULL; - } + return NULL; } - channel &= 7; } sfx = &S_sfx[sound_id]; diff --git a/src/sound/fmodsound.cpp b/src/sound/fmodsound.cpp index be961ad05..cf231b5f2 100644 --- a/src/sound/fmodsound.cpp +++ b/src/sound/fmodsound.cpp @@ -1554,55 +1554,15 @@ FMOD_MODE FMODSoundRenderer::SetChanHeadSettings(FMOD::Channel *chan, sfxinfo_t cpos.X = FIXED2FLOAT(players[consoleplayer].camera->x); cpos.Y = FIXED2FLOAT(players[consoleplayer].camera->z); cpos.Z = FIXED2FLOAT(players[consoleplayer].camera->y); - mpos = pos; - if ((chanflags & CHAN_AREA) && sec != NULL) + if (chanflags & CHAN_AREA) { - fixed_t ox = fixed_t(pos[0] * 65536); - fixed_t oy = fixed_t(pos[1] * 65536); - fixed_t cx, cy, cz; float level, old_level; - // Are we inside the sector? If yes, the closest point is the one we're on. - if (P_PointInSector(players[consoleplayer].camera->x, players[consoleplayer].camera->y) == sec) - { - mpos[0] = cpos[0]; - mpos[2] = cpos[2]; - cx = players[consoleplayer].camera->x; - cy = players[consoleplayer].camera->y; - } - else - { - // Find the closest point on the sector's boundary lines and use - // that as the perceived origin of the sound. - sec->ClosestPoint(players[consoleplayer].camera->x, players[consoleplayer].camera->y, cx, cy); - mpos[0] = FIXED2FLOAT(cx); - mpos[2] = FIXED2FLOAT(cy); - } - // Set sound height based on channel. - if (channum == CHAN_FLOOR) - { - cz = MIN(sec->floorplane.ZatPoint(cx, cy), players[consoleplayer].camera->z); - } - else if (channum == CHAN_CEILING) - { - cz = MAX(sec->ceilingplane.ZatPoint(cx, cy), players[consoleplayer].camera->z); - } - else if (channum == CHAN_INTERIOR) - { - cz = clamp(players[consoleplayer].camera->z, sec->floorplane.ZatPoint(cx, cy), - sec->ceilingplane.ZatPoint(cx, cy)); - } - else - { - cz = players[consoleplayer].camera->z; - } - mpos[1] = FIXED2FLOAT(cz); - // How far are we from the perceived sound origin? Within a certain // short distance, we interpolate between 2D panning and full 3D panning. const double interp_range = 32.0; - double dist_sqr = (cpos - mpos).LengthSquared(); + double dist_sqr = (cpos - pos).LengthSquared(); if (dist_sqr == 0) { @@ -1628,7 +1588,7 @@ FMOD_MODE FMODSoundRenderer::SetChanHeadSettings(FMOD::Channel *chan, sfxinfo_t } return oldmode; } - else if (cpos == mpos) + else if (cpos == pos) { // Head relative return (oldmode & ~FMOD_3D) | FMOD_2D; } diff --git a/src/version.h b/src/version.h index 56d83e54b..187e23072 100644 --- a/src/version.h +++ b/src/version.h @@ -75,7 +75,7 @@ // SAVESIG should match SAVEVER. // MINSAVEVER is the minimum level snapshot version that can be loaded. -#define MINSAVEVER 1059 +#define MINSAVEVER 1061 #if SVN_REVISION_NUMBER < MINSAVEVER // Never write a savegame with a version lower than what we need