diff --git a/src/polyrenderer/poly_renderer.cpp b/src/polyrenderer/poly_renderer.cpp index 33f489cb53..a0a0483b33 100644 --- a/src/polyrenderer/poly_renderer.cpp +++ b/src/polyrenderer/poly_renderer.cpp @@ -115,9 +115,9 @@ void PolyRenderer::RenderActorView(AActor *actor, bool dontmaplines) DontMapLines = dontmaplines; + R_SetupFrame(Viewpoint, Viewwindow, actor); P_FindParticleSubsectors(); PO_LinkToSubsectors(); - R_SetupFrame(Viewpoint, Viewwindow, actor); if (APART(R_OldBlend)) NormalLight.Maps = realcolormaps.Maps; else NormalLight.Maps = realcolormaps.Maps + NUMCOLORMAPS * 256 * R_OldBlend; diff --git a/src/polyrenderer/scene/poly_scene.cpp b/src/polyrenderer/scene/poly_scene.cpp index a655ca8458..21ae23fc8c 100644 --- a/src/polyrenderer/scene/poly_scene.cpp +++ b/src/polyrenderer/scene/poly_scene.cpp @@ -111,25 +111,48 @@ void RenderPolyScene::RenderSubsector(subsector_t *sub) uint32_t subsectorDepth = NextSubsectorDepth++; + bool mainBSP = sub->polys == nullptr; + + if (sub->polys) + { + if (sub->BSP == nullptr || sub->BSP->bDirty) + { + sub->BuildPolyBSP(); + + // This is done by the GL renderer, but not the sw renderer. No idea what the purpose is.. + for (unsigned i = 0; i < sub->BSP->Segs.Size(); i++) + { + sub->BSP->Segs[i].Subsector = sub; + sub->BSP->Segs[i].PartnerSeg = nullptr; + } + } + + if (sub->BSP->Nodes.Size() == 0) + { + RenderPolySubsector(&sub->BSP->Subsectors[0], subsectorDepth, frontsector); + } + else + { + RenderPolyNode(&sub->BSP->Nodes.Last(), subsectorDepth, frontsector); + } + } + else + { + for (uint32_t i = 0; i < sub->numlines; i++) + { + seg_t *line = &sub->firstline[i]; + RenderLine(sub, line, frontsector, subsectorDepth); + } + } + if (sub->sector->CenterFloor() != sub->sector->CenterCeiling()) { RenderPolyPlane::RenderPlanes(WorldToClip, PortalPlane, Cull, sub, subsectorDepth, StencilValue, Cull.MaxCeilingHeight, Cull.MinFloorHeight, SectorPortals); } - for (uint32_t i = 0; i < sub->numlines; i++) - { - seg_t *line = &sub->firstline[i]; - if (line->sidedef == nullptr || !(line->sidedef->Flags & WALLF_POLYOBJ)) - { - RenderLine(sub, line, frontsector, subsectorDepth); - } - } - - RenderMemory &memory = PolyRenderer::Instance()->FrameMemory; - - bool mainBSP = ((unsigned int)(sub->Index()) < level.subsectors.Size()); if (mainBSP) { + RenderMemory &memory = PolyRenderer::Instance()->FrameMemory; int subsectorIndex = sub->Index(); for (int i = ParticlesInSubsec[subsectorIndex]; i != NO_PARTICLE; i = Particles[i].snext) { @@ -142,6 +165,73 @@ void RenderPolyScene::RenderSubsector(subsector_t *sub) SubsectorDepths[sub] = subsectorDepth; } +void RenderPolyScene::RenderPolyNode(void *node, uint32_t subsectorDepth, sector_t *frontsector) +{ + while (!((size_t)node & 1)) // Keep going until found a subsector + { + node_t *bsp = (node_t *)node; + + // Decide which side the view point is on. + int side = PointOnSide(PolyRenderer::Instance()->Viewpoint.Pos, bsp); + + // Recursively divide front space (toward the viewer). + RenderPolyNode(bsp->children[side], subsectorDepth, frontsector); + + // Possibly divide back space (away from the viewer). + side ^= 1; + + // Don't bother culling on poly objects + //if (!CheckBBox(bsp->bbox[side])) + // return; + + node = bsp->children[side]; + } + + subsector_t *sub = (subsector_t *)((uint8_t *)node - 1); + RenderPolySubsector(sub, subsectorDepth, frontsector); +} + +void RenderPolyScene::RenderPolySubsector(subsector_t *sub, uint32_t subsectorDepth, sector_t *frontsector) +{ + const auto &viewpoint = PolyRenderer::Instance()->Viewpoint; + + for (uint32_t i = 0; i < sub->numlines; i++) + { + seg_t *line = &sub->firstline[i]; + if (line->linedef) + { + // Reject lines not facing viewer + DVector2 pt1 = line->v1->fPos() - viewpoint.Pos; + DVector2 pt2 = line->v2->fPos() - viewpoint.Pos; + if (pt1.Y * (pt1.X - pt2.X) + pt1.X * (pt2.Y - pt1.Y) >= 0) + continue; + + // Cull wall if not visible + angle_t angle1, angle2; + if (!Cull.GetAnglesForLine(line->v1->fX(), line->v1->fY(), line->v2->fX(), line->v2->fY(), angle1, angle2)) + continue; + + // Tell automap we saw this + if (!PolyRenderer::Instance()->DontMapLines && line->linedef) + { + line->linedef->flags |= ML_MAPPED; + sub->flags |= SSECF_DRAWN; + } + + // Render wall, and update culling info if its an occlusion blocker + if (RenderPolyWall::RenderLine(WorldToClip, PortalPlane, Cull, line, frontsector, subsectorDepth, StencilValue, TranslucentObjects, LinePortals)) + { + Cull.MarkSegmentCulled(angle1, angle2); + } + } + } +} + +int RenderPolyScene::PointOnSide(const DVector2 &pos, const node_t *node) +{ + return DMulScale32(FLOAT2FIXED(pos.Y) - node->y, node->dx, node->x - FLOAT2FIXED(pos.X), node->dy) > 0; +} + void RenderPolyScene::RenderSprite(AActor *thing, double sortDistance, const DVector2 &left, const DVector2 &right) { if (level.nodes.Size() == 0) diff --git a/src/polyrenderer/scene/poly_scene.h b/src/polyrenderer/scene/poly_scene.h index 707ee87a3c..fc89de7cdc 100644 --- a/src/polyrenderer/scene/poly_scene.h +++ b/src/polyrenderer/scene/poly_scene.h @@ -89,6 +89,10 @@ private: void RenderSprite(AActor *thing, double sortDistance, const DVector2 &left, const DVector2 &right); void RenderSprite(AActor *thing, double sortDistance, DVector2 left, DVector2 right, double t1, double t2, void *node); + void RenderPolySubsector(subsector_t *sub, uint32_t subsectorDepth, sector_t *frontsector); + void RenderPolyNode(void *node, uint32_t subsectorDepth, sector_t *frontsector); + static int PointOnSide(const DVector2 &pos, const node_t *node); + TriMatrix WorldToClip; PolyClipPlane PortalPlane; uint32_t StencilValue = 0; diff --git a/src/polyrenderer/scene/poly_sky.cpp b/src/polyrenderer/scene/poly_sky.cpp index c30dca34e6..4fa4e7889c 100644 --- a/src/polyrenderer/scene/poly_sky.cpp +++ b/src/polyrenderer/scene/poly_sky.cpp @@ -61,7 +61,7 @@ void PolySkyDome::Render(const TriMatrix &worldToClip) float scaleFrontU = frameSetup.frontcyl / (float)frameSetup.frontskytex->GetWidth(); float scaleFrontV = (float)frameSetup.frontskytex->Scale.Y * scaleBaseV; - float offsetFrontU = (float)(frameSetup.frontpos / 65536.0 / frameSetup.frontskytex->GetWidth()); + float offsetFrontU = (float)((frameSetup.frontpos / 65536.0 + frameSetup.frontcyl / 2) / frameSetup.frontskytex->GetWidth()); float offsetFrontV = (float)((frameSetup.skymid / frameSetup.frontskytex->GetHeight() + offsetBaseV) * scaleBaseV); unsigned int count = mVertices.Size(); diff --git a/src/sound/oalsound.cpp b/src/sound/oalsound.cpp index 77068cf96d..6a0c9ff1c7 100644 --- a/src/sound/oalsound.cpp +++ b/src/sound/oalsound.cpp @@ -285,6 +285,8 @@ class OpenALSoundStream : public SoundStream } if(Renderer->AL.EXT_SOURCE_RADIUS) alSourcef(Source, AL_SOURCE_RADIUS, 0.f); + if(Renderer->AL.SOFT_source_spatialize) + alSourcei(Source, AL_SOURCE_SPATIALIZE_SOFT, AL_AUTO_SOFT); alGenBuffers(BufferCount, Buffers); return (getALError() == AL_NO_ERROR); @@ -816,6 +818,7 @@ OpenALSoundRenderer::OpenALSoundRenderer() AL.SOFT_deferred_updates = !!alIsExtensionPresent("AL_SOFT_deferred_updates"); AL.SOFT_loop_points = !!alIsExtensionPresent("AL_SOFT_loop_points"); AL.SOFT_source_resampler = !!alIsExtensionPresent("AL_SOFT_source_resampler"); + AL.SOFT_source_spatialize = !!alIsExtensionPresent("AL_SOFT_source_spatialize"); alDopplerFactor(0.5f); alSpeedOfSound(343.3f * 96.0f); @@ -1177,6 +1180,9 @@ std::pair OpenALSoundRenderer::LoadSoundRaw(uint8_t *sfxdata, if(length == 0) return std::make_pair(retval, true); + /* Only downmix to mono if we can't spatialize multi-channel sounds. */ + monoize = monoize && !AL.SOFT_source_spatialize; + if(bits == -8) { // Simple signed->unsigned conversion @@ -1264,7 +1270,7 @@ std::pair OpenALSoundRenderer::LoadSoundRaw(uint8_t *sfxdata, } retval.data = MAKE_PTRID(buffer); - return std::make_pair(retval, channels==1); + return std::make_pair(retval, AL.SOFT_source_spatialize || channels==1); } void FindLoopTags(FileReader *fr, uint32_t *start, bool *startass, uint32_t *end, bool *endass); @@ -1280,6 +1286,9 @@ std::pair OpenALSoundRenderer::LoadSound(uint8_t *sfxdata, int uint32_t loop_start = 0, loop_end = ~0u; bool startass = false, endass = false; + /* Only downmix to mono if we can't spatialize multi-channel sounds. */ + monoize = monoize && !AL.SOFT_source_spatialize; + if (!memcmp(sfxdata, "OggS", 4) || !memcmp(sfxdata, "FLAC", 4)) { MemoryReader mr((char*)sfxdata, length); @@ -1377,7 +1386,7 @@ std::pair OpenALSoundRenderer::LoadSound(uint8_t *sfxdata, int pBuffer->type = type; pBuffer->srate = srate; } - return std::make_pair(retval, (chans == ChannelConfig_Mono || monoize)); + return std::make_pair(retval, AL.SOFT_source_spatialize || chans == ChannelConfig_Mono || monoize); } std::pair OpenALSoundRenderer::LoadSoundBuffered(FSoundLoadBuffer *pBuffer, bool monoize) @@ -1389,6 +1398,9 @@ std::pair OpenALSoundRenderer::LoadSoundBuffered(FSoundLoadBu auto chans = pBuffer->chans; uint32_t loop_start = pBuffer->loop_start, loop_end = pBuffer->loop_end; + /* Only downmix to mono if we can't spatialize multi-channel sounds. */ + monoize = monoize && !AL.SOFT_source_spatialize; + if (chans == ChannelConfig_Mono || monoize) { if (type == SampleType_UInt8) format = AL_FORMAT_MONO8; @@ -1461,7 +1473,7 @@ std::pair OpenALSoundRenderer::LoadSoundBuffered(FSoundLoadBu } retval.data = MAKE_PTRID(buffer); - return std::make_pair(retval, (chans == ChannelConfig_Mono || monoize)); + return std::make_pair(retval, AL.SOFT_source_spatialize || chans == ChannelConfig_Mono || monoize); } void OpenALSoundRenderer::UnloadSound(SoundHandle sfx) @@ -1560,6 +1572,8 @@ FISoundChannel *OpenALSoundRenderer::StartSound(SoundHandle sfx, float vol, int alSourcef(source, AL_GAIN, SfxVolume*vol); if(AL.EXT_SOURCE_RADIUS) alSourcef(source, AL_SOURCE_RADIUS, 0.f); + if(AL.SOFT_source_spatialize) + alSourcei(source, AL_SOURCE_SPATIALIZE_SOFT, AL_AUTO_SOFT); if(EnvSlot) { @@ -1768,6 +1782,8 @@ FISoundChannel *OpenALSoundRenderer::StartSound3D(SoundHandle sfx, SoundListener alSourcef(source, AL_MAX_GAIN, SfxVolume); alSourcef(source, AL_GAIN, SfxVolume*vol); + if(AL.SOFT_source_spatialize) + alSourcei(source, AL_SOURCE_SPATIALIZE_SOFT, AL_TRUE); if(EnvSlot) { diff --git a/src/sound/oalsound.h b/src/sound/oalsound.h index 6c79707bfb..7a1ed2a23f 100644 --- a/src/sound/oalsound.h +++ b/src/sound/oalsound.h @@ -109,6 +109,12 @@ AL_API const ALchar* AL_APIENTRY alGetStringiSOFT(ALenum pname, ALsizei index); #endif #endif +#ifndef AL_SOFT_source_spatialize +#define AL_SOFT_source_spatialize +#define AL_SOURCE_SPATIALIZE_SOFT 0x1214 +#define AL_AUTO_SOFT 0x0002 +#endif + class OpenALSoundStream; @@ -184,6 +190,7 @@ private: bool SOFT_deferred_updates; bool SOFT_loop_points; bool SOFT_source_resampler; + bool SOFT_source_spatialize; } AL; // EFX Extension function pointer variables. Loaded after context creation diff --git a/wadsrc/static/iwadinfo.txt b/wadsrc/static/iwadinfo.txt index 526c41c5a0..458e846c36 100644 --- a/wadsrc/static/iwadinfo.txt +++ b/wadsrc/static/iwadinfo.txt @@ -395,17 +395,22 @@ IWad Names { "doom_complete.pk3" - "bfgdoom2.wad" - "doom2bfg.wad" - "doom2f.wad" "doom2.wad" "plutonia.wad" "tnt.wad" - "bfgdoom.wad" - "doombfg.wad" "doomu.wad" "doom.wad" "doom1.wad" + "bfgdoom2.wad" + "doom2bfg.wad" + "bfgdoom.wad" + "doombfg.wad" + "doom2f.wad" + "freedoom1.wad" + "freedoom2.wad" + "freedoomu.wad" + "freedoom.wad" + "freedm.wad" "heretic.wad" "hereticsr.wad" "heretic1.wad" @@ -413,15 +418,10 @@ Names "hexdd.wad" "hexendemo.wad" "hexdemo.wad" - "sve.wad" "strife1.wad" + "sve.wad" "strife0.wad" "strife.wad" - "freedoom1.wad" - "freedoom2.wad" - "freedoomu.wad" - "freedoom.wad" - "freedm.wad" "blasphem.wad" "blasphemer.wad" "chex.wad"