mirror of
https://github.com/ZDoom/qzdoom.git
synced 2024-11-10 14:51:51 +00:00
Merge remote-tracking branch 'gzdoom/modern' into hw_postprocess
This commit is contained in:
commit
32d837cdf1
164 changed files with 23467 additions and 13025 deletions
|
@ -638,8 +638,8 @@ add_definitions(-DOPNMIDI_USE_LEGACY_EMULATOR)
|
|||
add_definitions(-DADLMIDI_DISABLE_MUS_SUPPORT -DADLMIDI_DISABLE_XMI_SUPPORT -DADLMIDI_DISABLE_MIDI_SEQUENCER)
|
||||
add_definitions(-DOPNMIDI_DISABLE_MUS_SUPPORT -DOPNMIDI_DISABLE_XMI_SUPPORT -DOPNMIDI_DISABLE_MIDI_SEQUENCER)
|
||||
|
||||
# Disable ADLMIDI's MIDI Sequencer, MUS and XMI converters
|
||||
add_definitions(-DADLMIDI_DISABLE_MUS_SUPPORT -DADLMIDI_DISABLE_XMI_SUPPORT -DADLMIDI_DISABLE_MIDI_SEQUENCER)
|
||||
# Disable OPNMIDI's experimental yet emulator (using of it has some issues and missing notes in playback)
|
||||
add_definitions(-DOPNMIDI_DISABLE_GX_EMULATOR)
|
||||
|
||||
# Project files should be aware of the header files. We can GLOB these since
|
||||
# there's generally a new cpp for every header so this file will get changed
|
||||
|
@ -705,7 +705,6 @@ file( GLOB HEADER_FILES
|
|||
gl/models/*.h
|
||||
gl/renderer/*.h
|
||||
gl/scene/*.h
|
||||
gl/stereo3d/*.h
|
||||
gl/shaders/*.h
|
||||
gl/system/*.h
|
||||
gl/textures/*.h
|
||||
|
@ -837,9 +836,11 @@ set( FASTMATH_SOURCES
|
|||
hwrenderer/scene/hw_bsp.cpp
|
||||
hwrenderer/scene/hw_fakeflat.cpp
|
||||
hwrenderer/scene/hw_decal.cpp
|
||||
hwrenderer/scene/hw_drawinfo.cpp
|
||||
hwrenderer/scene/hw_drawlist.cpp
|
||||
hwrenderer/scene/hw_clipper.cpp
|
||||
hwrenderer/scene/hw_flats.cpp
|
||||
hwrenderer/scene/hw_portal.cpp
|
||||
hwrenderer/scene/hw_renderhacks.cpp
|
||||
hwrenderer/scene/hw_sky.cpp
|
||||
hwrenderer/scene/hw_sprites.cpp
|
||||
|
@ -855,14 +856,25 @@ set( FASTMATH_SOURCES
|
|||
sound/adlmidi/adlmidi_midiplay.cpp
|
||||
sound/adlmidi/adlmidi_opl3.cpp
|
||||
sound/adlmidi/adlmidi_private.cpp
|
||||
sound/adlmidi/dbopl.cpp
|
||||
sound/adlmidi/nukedopl3.c
|
||||
sound/adlmidi/chips/dosbox/dbopl.cpp
|
||||
sound/adlmidi/chips/dosbox_opl3.cpp
|
||||
sound/adlmidi/chips/nuked/nukedopl3_174.c
|
||||
sound/adlmidi/chips/nuked/nukedopl3.c
|
||||
sound/adlmidi/chips/nuked_opl3.cpp
|
||||
sound/adlmidi/chips/nuked_opl3_v174.cpp
|
||||
sound/adlmidi/wopl/wopl_file.c
|
||||
sound/opnmidi/chips/gens_opn2.cpp
|
||||
sound/opnmidi/chips/gens/Ym2612_Emu.cpp
|
||||
sound/opnmidi/chips/mame/mame_ym2612fm.c
|
||||
sound/opnmidi/chips/mame_opn2.cpp
|
||||
sound/opnmidi/chips/nuked_opn2.cpp
|
||||
sound/opnmidi/chips/nuked/ym3438.c
|
||||
sound/opnmidi/opnmidi.cpp
|
||||
sound/opnmidi/opnmidi_load.cpp
|
||||
sound/opnmidi/opnmidi_midiplay.cpp
|
||||
sound/opnmidi/opnmidi_opn2.cpp
|
||||
sound/opnmidi/opnmidi_private.cpp
|
||||
sound/opnmidi/Ym2612_ChipEmu.cpp
|
||||
|
||||
)
|
||||
|
||||
set (PCH_SOURCES
|
||||
|
@ -1041,16 +1053,10 @@ set (PCH_SOURCES
|
|||
gl/renderer/gl_lightdata.cpp
|
||||
gl/renderer/gl_postprocess.cpp
|
||||
gl/renderer/gl_postprocessstate.cpp
|
||||
gl/renderer/gl_stereo3d.cpp
|
||||
gl/shaders/gl_shader.cpp
|
||||
gl/shaders/gl_shaderprogram.cpp
|
||||
gl/shaders/gl_postprocessshader.cpp
|
||||
gl/stereo3d/gl_stereo3d.cpp
|
||||
gl/stereo3d/gl_stereo_cvars.cpp
|
||||
gl/stereo3d/gl_stereo_leftright.cpp
|
||||
gl/stereo3d/gl_anaglyph.cpp
|
||||
gl/stereo3d/gl_quadstereo.cpp
|
||||
gl/stereo3d/gl_sidebyside3d.cpp
|
||||
gl/stereo3d/gl_interleaved3d.cpp
|
||||
gl_load/gl_interface.cpp
|
||||
gl/system/gl_framebuffer.cpp
|
||||
gl/system/gl_debug.cpp
|
||||
|
@ -1074,6 +1080,7 @@ set (PCH_SOURCES
|
|||
hwrenderer/utility/hw_cvars.cpp
|
||||
hwrenderer/utility/hw_lighting.cpp
|
||||
hwrenderer/utility/hw_shaderpatcher.cpp
|
||||
hwrenderer/utility/hw_vrmodes.cpp
|
||||
|
||||
menu/joystickmenu.cpp
|
||||
menu/loadsavemenu.cpp
|
||||
|
@ -1404,7 +1411,6 @@ source_group("Hardware Renderer\\Models" REGULAR_EXPRESSION "^${CMAKE_CURRENT_SO
|
|||
source_group("Hardware Renderer\\Postprocessing" REGULAR_EXPRESSION "^${CMAKE_CURRENT_SOURCE_DIR}/hwrenderer/postprocessing/.+")
|
||||
source_group("Hardware Renderer\\Renderer" REGULAR_EXPRESSION "^${CMAKE_CURRENT_SOURCE_DIR}/hwrenderer/renderer/.+")
|
||||
source_group("Hardware Renderer\\Scene" REGULAR_EXPRESSION "^${CMAKE_CURRENT_SOURCE_DIR}/hwrenderer/scene/.+")
|
||||
source_group("Hardware Renderer\\Stereo3D" REGULAR_EXPRESSION "^${CMAKE_CURRENT_SOURCE_DIR}/hwrenderer/stereo3d/.+")
|
||||
source_group("Hardware Renderer\\Shaders" REGULAR_EXPRESSION "^${CMAKE_CURRENT_SOURCE_DIR}/hwrenderer/shaders/.+")
|
||||
source_group("Hardware Renderer\\System" REGULAR_EXPRESSION "^${CMAKE_CURRENT_SOURCE_DIR}/hwrenderer/system/.+")
|
||||
source_group("Hardware Renderer\\Textures" REGULAR_EXPRESSION "^${CMAKE_CURRENT_SOURCE_DIR}/hwrenderer/textures/.+")
|
||||
|
@ -1416,7 +1422,6 @@ source_group("OpenGL Renderer\\Dynamic Lights" REGULAR_EXPRESSION "^${CMAKE_CURR
|
|||
source_group("OpenGL Renderer\\Models" REGULAR_EXPRESSION "^${CMAKE_CURRENT_SOURCE_DIR}/gl/models/.+")
|
||||
source_group("OpenGL Renderer\\Renderer" REGULAR_EXPRESSION "^${CMAKE_CURRENT_SOURCE_DIR}/gl/renderer/.+")
|
||||
source_group("OpenGL Renderer\\Scene" REGULAR_EXPRESSION "^${CMAKE_CURRENT_SOURCE_DIR}/gl/scene/.+")
|
||||
source_group("OpenGL Renderer\\Stereo3D" REGULAR_EXPRESSION "^${CMAKE_CURRENT_SOURCE_DIR}/gl/stereo3d/.+")
|
||||
source_group("OpenGL Renderer\\Shaders" REGULAR_EXPRESSION "^${CMAKE_CURRENT_SOURCE_DIR}/gl/shaders/.+")
|
||||
source_group("OpenGL Renderer\\System" REGULAR_EXPRESSION "^${CMAKE_CURRENT_SOURCE_DIR}/gl/system/.+")
|
||||
source_group("OpenGL Renderer\\Textures" REGULAR_EXPRESSION "^${CMAKE_CURRENT_SOURCE_DIR}/gl/textures/.+")
|
||||
|
|
|
@ -2123,13 +2123,14 @@ void AM_drawSubsectors()
|
|||
double secx;
|
||||
double secy;
|
||||
double seczb, seczt;
|
||||
double cmpz = r_viewpoint.Pos.Z;
|
||||
auto &vp = r_viewpoint;
|
||||
double cmpz = vp.Pos.Z;
|
||||
|
||||
if (players[consoleplayer].camera && sec == players[consoleplayer].camera->Sector)
|
||||
{
|
||||
// For the actual camera sector use the current viewpoint as reference.
|
||||
secx = r_viewpoint.Pos.X;
|
||||
secy = r_viewpoint.Pos.Y;
|
||||
secx = vp.Pos.X;
|
||||
secy = vp.Pos.Y;
|
||||
}
|
||||
else
|
||||
{
|
||||
|
|
|
@ -104,6 +104,7 @@
|
|||
|
||||
EXTERN_CVAR(Bool, hud_althud)
|
||||
EXTERN_CVAR(Bool, fullscreen)
|
||||
EXTERN_CVAR(Int, vr_mode)
|
||||
void DrawHUD();
|
||||
void D_DoAnonStats();
|
||||
|
||||
|
@ -662,6 +663,7 @@ void D_Display ()
|
|||
players[consoleplayer].camera = players[consoleplayer].mo;
|
||||
}
|
||||
|
||||
auto &vp = r_viewpoint;
|
||||
if (viewactive)
|
||||
{
|
||||
DAngle fov = 90.f;
|
||||
|
@ -672,7 +674,7 @@ void D_Display ()
|
|||
fov = cam->player->FOV;
|
||||
else fov = cam->CameraFOV;
|
||||
}
|
||||
R_SetFOV(r_viewpoint, fov);
|
||||
R_SetFOV(vp, fov);
|
||||
}
|
||||
|
||||
// fullscreen toggle has been requested
|
||||
|
@ -681,7 +683,7 @@ void D_Display ()
|
|||
screen->ToggleFullscreen(fullscreen);
|
||||
V_OutputResized(screen->GetWidth(), screen->GetHeight());
|
||||
setmodeneeded = false;
|
||||
}
|
||||
}
|
||||
|
||||
// change the view size if needed
|
||||
if (setsizeneeded)
|
||||
|
@ -694,8 +696,8 @@ void D_Display ()
|
|||
}
|
||||
else
|
||||
{
|
||||
R_ExecuteSetViewSize (r_viewpoint, r_viewwindow);
|
||||
}
|
||||
R_ExecuteSetViewSize (vp, r_viewwindow);
|
||||
}
|
||||
}
|
||||
|
||||
// [RH] Allow temporarily disabling wipes
|
||||
|
@ -705,7 +707,8 @@ void D_Display ()
|
|||
wipe = false;
|
||||
wipegamestate = gamestate;
|
||||
}
|
||||
else if (gamestate != wipegamestate && gamestate != GS_FULLCONSOLE && gamestate != GS_TITLELEVEL)
|
||||
// No wipes when in a stereo3D VR mode
|
||||
else if (gamestate != wipegamestate && gamestate != GS_FULLCONSOLE && gamestate != GS_TITLELEVEL && (vr_mode == 0 || vid_rendermode != 4))
|
||||
{ // save the current screen if about to wipe
|
||||
switch (wipegamestate)
|
||||
{
|
||||
|
@ -793,7 +796,7 @@ void D_Display ()
|
|||
{
|
||||
StatusBar->DrawCrosshair();
|
||||
}
|
||||
StatusBar->CallDraw (HUD_AltHud);
|
||||
StatusBar->CallDraw (HUD_AltHud, vp.TicFrac);
|
||||
StatusBar->DrawTopStuff (HUD_AltHud);
|
||||
}
|
||||
else
|
||||
|
@ -801,13 +804,13 @@ void D_Display ()
|
|||
{
|
||||
EHudState state = DrawFSHUD ? HUD_Fullscreen : HUD_None;
|
||||
StatusBar->DrawBottomStuff (state);
|
||||
StatusBar->CallDraw (state);
|
||||
StatusBar->CallDraw (state, vp.TicFrac);
|
||||
StatusBar->DrawTopStuff (state);
|
||||
}
|
||||
else
|
||||
{
|
||||
StatusBar->DrawBottomStuff (HUD_StatusBar);
|
||||
StatusBar->CallDraw (HUD_StatusBar);
|
||||
StatusBar->CallDraw (HUD_StatusBar, vp.TicFrac);
|
||||
StatusBar->DrawTopStuff (HUD_StatusBar);
|
||||
}
|
||||
//stb.Unclock();
|
||||
|
|
|
@ -857,12 +857,13 @@ void DStaticEventHandler::WorldTick()
|
|||
static FRenderEvent E_SetupRenderEvent()
|
||||
{
|
||||
FRenderEvent e;
|
||||
e.ViewPos = r_viewpoint.Pos;
|
||||
e.ViewAngle = r_viewpoint.Angles.Yaw;
|
||||
e.ViewPitch = r_viewpoint.Angles.Pitch;
|
||||
e.ViewRoll = r_viewpoint.Angles.Roll;
|
||||
e.FracTic = r_viewpoint.TicFrac;
|
||||
e.Camera = r_viewpoint.camera;
|
||||
auto &vp = r_viewpoint;
|
||||
e.ViewPos = vp.Pos;
|
||||
e.ViewAngle = vp.Angles.Yaw;
|
||||
e.ViewPitch = vp.Angles.Pitch;
|
||||
e.ViewRoll = vp.Angles.Roll;
|
||||
e.FracTic = vp.TicFrac;
|
||||
e.Camera = vp.camera;
|
||||
return e;
|
||||
}
|
||||
|
||||
|
|
|
@ -177,9 +177,9 @@ void DEarthquake::Tick ()
|
|||
//
|
||||
//==========================================================================
|
||||
|
||||
double DEarthquake::GetModWave(double waveMultiplier) const
|
||||
double DEarthquake::GetModWave(double ticFrac, double waveMultiplier) const
|
||||
{
|
||||
double time = m_Countdown - r_viewpoint.TicFrac;
|
||||
double time = m_Countdown - ticFrac;
|
||||
return g_sin(waveMultiplier * time * (M_PI * 2 / TICRATE));
|
||||
}
|
||||
|
||||
|
@ -292,7 +292,7 @@ double DEarthquake::GetFalloff(double dist) const
|
|||
//
|
||||
//==========================================================================
|
||||
|
||||
int DEarthquake::StaticGetQuakeIntensities(AActor *victim, FQuakeJiggers &jiggers)
|
||||
int DEarthquake::StaticGetQuakeIntensities(double ticFrac, AActor *victim, FQuakeJiggers &jiggers)
|
||||
{
|
||||
if (victim->player != NULL && (victim->player->cheats & CF_NOCLIP))
|
||||
{
|
||||
|
@ -339,12 +339,12 @@ int DEarthquake::StaticGetQuakeIntensities(AActor *victim, FQuakeJiggers &jigger
|
|||
}
|
||||
else
|
||||
{
|
||||
jiggers.RollWave = r * quake->GetModWave(quake->m_RollWave) * falloff * strength;
|
||||
jiggers.RollWave = r * quake->GetModWave(ticFrac, quake->m_RollWave) * falloff * strength;
|
||||
|
||||
|
||||
intensity.X *= quake->GetModWave(quake->m_WaveSpeed.X);
|
||||
intensity.Y *= quake->GetModWave(quake->m_WaveSpeed.Y);
|
||||
intensity.Z *= quake->GetModWave(quake->m_WaveSpeed.Z);
|
||||
intensity.X *= quake->GetModWave(ticFrac, quake->m_WaveSpeed.X);
|
||||
intensity.Y *= quake->GetModWave(ticFrac, quake->m_WaveSpeed.Y);
|
||||
intensity.Z *= quake->GetModWave(ticFrac, quake->m_WaveSpeed.Z);
|
||||
intensity *= strength * falloff;
|
||||
|
||||
// [RH] This only gives effect to the last sine quake. I would
|
||||
|
|
|
@ -145,10 +145,10 @@ public:
|
|||
double m_RollIntensity, m_RollWave;
|
||||
|
||||
double GetModIntensity(double intensity, bool fake = false) const;
|
||||
double GetModWave(double waveMultiplier) const;
|
||||
double GetModWave(double ticFrac, double waveMultiplier) const;
|
||||
double GetFalloff(double dist) const;
|
||||
|
||||
static int StaticGetQuakeIntensities(AActor *viewer, FQuakeJiggers &jiggers);
|
||||
static int StaticGetQuakeIntensities(double ticFrac, AActor *viewer, FQuakeJiggers &jiggers);
|
||||
|
||||
private:
|
||||
DEarthquake ();
|
||||
|
|
|
@ -397,10 +397,10 @@ public:
|
|||
void SetScale();
|
||||
virtual void Tick ();
|
||||
void CallTick();
|
||||
virtual void Draw (EHudState state);
|
||||
void CallDraw(EHudState state);
|
||||
void DrawBottomStuff (EHudState state);
|
||||
void DrawTopStuff (EHudState state);
|
||||
virtual void Draw (EHudState state, double ticFrac);
|
||||
void CallDraw(EHudState state, double ticFrac);
|
||||
void DrawBottomStuff (EHudState state);
|
||||
void DrawTopStuff (EHudState state);
|
||||
void FlashItem (const PClass *itemtype);
|
||||
void AttachToPlayer(player_t *player);
|
||||
DVector2 GetHUDScale() const;
|
||||
|
|
|
@ -1006,7 +1006,7 @@ void DBaseStatusBar::DrawMessages (int layer, int bottom)
|
|||
//
|
||||
//---------------------------------------------------------------------------
|
||||
|
||||
void DBaseStatusBar::Draw (EHudState state)
|
||||
void DBaseStatusBar::Draw (EHudState state, double ticFrac)
|
||||
{
|
||||
// HUD_AltHud state is for popups only
|
||||
if (state == HUD_AltHud)
|
||||
|
@ -1048,18 +1048,19 @@ DEFINE_ACTION_FUNCTION(DBaseStatusBar, Draw)
|
|||
{
|
||||
PARAM_SELF_PROLOGUE(DBaseStatusBar);
|
||||
PARAM_INT(state);
|
||||
self->Draw((EHudState)state);
|
||||
PARAM_FLOAT(ticFrac);
|
||||
self->Draw((EHudState)state, ticFrac);
|
||||
return 0;
|
||||
}
|
||||
|
||||
void DBaseStatusBar::CallDraw(EHudState state)
|
||||
void DBaseStatusBar::CallDraw(EHudState state, double ticFrac)
|
||||
{
|
||||
IFVIRTUAL(DBaseStatusBar, Draw)
|
||||
{
|
||||
VMValue params[] = { (DObject*)this, state, r_viewpoint.TicFrac };
|
||||
VMValue params[] = { (DObject*)this, state, ticFrac };
|
||||
VMCall(func, params, countof(params), nullptr, 0);
|
||||
}
|
||||
else Draw(state);
|
||||
else Draw(state, ticFrac);
|
||||
screen->ClearClipRect(); // make sure the scripts don't leave a valid clipping rect behind.
|
||||
BeginStatusBar(BaseSBarHorizontalResolution, BaseSBarVerticalResolution, BaseRelTop, false);
|
||||
}
|
||||
|
|
|
@ -50,7 +50,7 @@ CVAR(Bool, gl_light_models, true, CVAR_ARCHIVE)
|
|||
VSMatrix FGLModelRenderer::GetViewToWorldMatrix()
|
||||
{
|
||||
VSMatrix objectToWorldMatrix;
|
||||
gl_RenderState.mViewMatrix.inverseMatrix(objectToWorldMatrix);
|
||||
di->VPUniforms.mViewMatrix.inverseMatrix(objectToWorldMatrix);
|
||||
return objectToWorldMatrix;
|
||||
}
|
||||
|
||||
|
@ -65,7 +65,7 @@ void FGLModelRenderer::BeginDrawModel(AActor *actor, FSpriteModelFrame *smf, con
|
|||
if (!(actor->RenderStyle == LegacyRenderStyles[STYLE_Normal]) && !(smf->flags & MDL_DONTCULLBACKFACES))
|
||||
{
|
||||
glEnable(GL_CULL_FACE);
|
||||
glFrontFace((mirrored ^ GLPortal::isMirrored()) ? GL_CCW : GL_CW);
|
||||
glFrontFace((mirrored ^ GLRenderer->mPortalState.isMirrored()) ? GL_CCW : GL_CW);
|
||||
}
|
||||
|
||||
gl_RenderState.mModelMatrix = objectToWorldMatrix;
|
||||
|
@ -91,7 +91,7 @@ void FGLModelRenderer::BeginDrawHUDModel(AActor *actor, const VSMatrix &objectTo
|
|||
if (!(actor->RenderStyle == LegacyRenderStyles[STYLE_Normal]))
|
||||
{
|
||||
glEnable(GL_CULL_FACE);
|
||||
glFrontFace((mirrored ^ GLPortal::isMirrored()) ? GL_CW : GL_CCW);
|
||||
glFrontFace((mirrored ^ GLRenderer->mPortalState.isMirrored()) ? GL_CW : GL_CCW);
|
||||
}
|
||||
|
||||
gl_RenderState.mModelMatrix = objectToWorldMatrix;
|
||||
|
@ -314,27 +314,3 @@ void FModelVertexBuffer::SetupFrame(FModelRenderer *renderer, unsigned int frame
|
|||
}
|
||||
}
|
||||
}
|
||||
|
||||
//===========================================================================
|
||||
//
|
||||
// gl_RenderModel
|
||||
//
|
||||
//===========================================================================
|
||||
|
||||
void gl_RenderModel(GLSprite * spr, int mli)
|
||||
{
|
||||
FGLModelRenderer renderer(mli);
|
||||
renderer.RenderModel(spr->x, spr->y, spr->z, spr->modelframe, spr->actor);
|
||||
}
|
||||
|
||||
//===========================================================================
|
||||
//
|
||||
// gl_RenderHUDModel
|
||||
//
|
||||
//===========================================================================
|
||||
|
||||
void gl_RenderHUDModel(DPSprite *psp, float ofsX, float ofsY, int mli)
|
||||
{
|
||||
FGLModelRenderer renderer(mli);
|
||||
renderer.RenderHUDModel(psp, ofsX, ofsY);
|
||||
}
|
||||
|
|
|
@ -29,12 +29,14 @@
|
|||
#include "r_data/models/models.h"
|
||||
|
||||
class GLSprite;
|
||||
struct FDrawInfo;
|
||||
|
||||
class FGLModelRenderer : public FModelRenderer
|
||||
{
|
||||
int modellightindex = -1;
|
||||
FDrawInfo *di;
|
||||
public:
|
||||
FGLModelRenderer(int mli) : modellightindex(mli)
|
||||
FGLModelRenderer(FDrawInfo *d, int mli) : modellightindex(mli), di(d)
|
||||
{}
|
||||
ModelRendererType GetType() const override { return GLModelRendererType; }
|
||||
void BeginDrawModel(AActor *actor, FSpriteModelFrame *smf, const VSMatrix &objectToWorldMatrix, bool mirrored) override;
|
||||
|
@ -51,5 +53,3 @@ public:
|
|||
void DrawElements(int numIndices, size_t offset) override;
|
||||
};
|
||||
|
||||
void gl_RenderModel(GLSprite * spr, int mli);
|
||||
void gl_RenderHUDModel(DPSprite *psp, float ofsx, float ofsy, int mli);
|
||||
|
|
|
@ -173,7 +173,7 @@ void gl_SetFog(int lightlevel, int rellight, bool fullbright, const FColormap *c
|
|||
}
|
||||
|
||||
// Make fog a little denser when inside a skybox
|
||||
if (GLPortal::inskybox) fogdensity+=fogdensity/2;
|
||||
if (GLRenderer->mPortalState.inskybox) fogdensity+=fogdensity/2;
|
||||
|
||||
|
||||
// no fog in enhanced vision modes!
|
||||
|
|
|
@ -2,7 +2,7 @@
|
|||
#define __GL_LIGHTDATA
|
||||
|
||||
#include "v_palette.h"
|
||||
#include "p_3dfloors.h"
|
||||
#include "r_defs.h"
|
||||
#include "r_data/renderstyle.h"
|
||||
#include "hwrenderer/utility/hw_lighting.h"
|
||||
#include "r_data/colormaps.h"
|
||||
|
|
|
@ -43,8 +43,8 @@
|
|||
#include "hwrenderer/postprocessing/hw_presentshader.h"
|
||||
#include "hwrenderer/postprocessing/hw_postprocess.h"
|
||||
#include "hwrenderer/postprocessing/hw_postprocess_cvars.h"
|
||||
#include "hwrenderer/utility/hw_vrmodes.h"
|
||||
#include "gl/shaders/gl_postprocessshaderinstance.h"
|
||||
#include "gl/stereo3d/gl_stereo3d.h"
|
||||
#include "gl/textures/gl_hwtexture.h"
|
||||
#include "r_videoscale.h"
|
||||
|
||||
|
@ -239,7 +239,7 @@ void FGLRenderBuffers::RenderEffect(const FString &name)
|
|||
//
|
||||
//-----------------------------------------------------------------------------
|
||||
|
||||
void FGLRenderer::AmbientOccludeScene()
|
||||
void FGLRenderer::AmbientOccludeScene(float m5)
|
||||
{
|
||||
FGLDebug::PushGroup("AmbientOccludeScene");
|
||||
|
||||
|
@ -252,7 +252,7 @@ void FGLRenderer::AmbientOccludeScene()
|
|||
float aoStrength = gl_ssao_strength;
|
||||
|
||||
//float tanHalfFovy = tan(fovy * (M_PI / 360.0f));
|
||||
float tanHalfFovy = 1.0f / gl_RenderState.mProjectionMatrix.get()[5];
|
||||
float tanHalfFovy = 1.0f / m5;
|
||||
float invFocalLenX = tanHalfFovy * (mBuffers->GetSceneWidth() / (float)mBuffers->GetSceneHeight());
|
||||
float invFocalLenY = tanHalfFovy;
|
||||
float nDotVBias = clamp(bias, 0.0f, 1.0f);
|
||||
|
@ -272,8 +272,8 @@ void FGLRenderer::AmbientOccludeScene()
|
|||
mBuffers->BindSceneColorTexture(1);
|
||||
mLinearDepthShader->Bind(NOQUEUE);
|
||||
if (gl_multisample > 1) mLinearDepthShader->Uniforms->SampleIndex = 0;
|
||||
mLinearDepthShader->Uniforms->LinearizeDepthA = 1.0f / GetZFar() - 1.0f / GetZNear();
|
||||
mLinearDepthShader->Uniforms->LinearizeDepthB = MAX(1.0f / GetZNear(), 1.e-8f);
|
||||
mLinearDepthShader->Uniforms->LinearizeDepthA = 1.0f / screen->GetZFar() - 1.0f / screen->GetZNear();
|
||||
mLinearDepthShader->Uniforms->LinearizeDepthB = MAX(1.0f / screen->GetZNear(), 1.e-8f);
|
||||
mLinearDepthShader->Uniforms->InverseDepthRangeA = 1.0f;
|
||||
mLinearDepthShader->Uniforms->InverseDepthRangeB = 0.0f;
|
||||
mLinearDepthShader->Uniforms->Scale = sceneScale;
|
||||
|
@ -424,18 +424,18 @@ void FGLRenderer::ApplyFXAA()
|
|||
|
||||
void FGLRenderer::Flush()
|
||||
{
|
||||
const s3d::Stereo3DMode& stereo3dMode = s3d::Stereo3DMode::getCurrentMode();
|
||||
auto vrmode = VRMode::GetVRMode(true);
|
||||
const auto &mSceneViewport = screen->mSceneViewport;
|
||||
const auto &mScreenViewport = screen->mScreenViewport;
|
||||
|
||||
if (stereo3dMode.IsMono())
|
||||
if (vrmode->mEyeCount == 1)
|
||||
{
|
||||
CopyToBackbuffer(nullptr, true);
|
||||
}
|
||||
else
|
||||
{
|
||||
// Render 2D to eye textures
|
||||
for (int eye_ix = 0; eye_ix < stereo3dMode.eye_count(); ++eye_ix)
|
||||
for (int eye_ix = 0; eye_ix < vrmode->mEyeCount; ++eye_ix)
|
||||
{
|
||||
FGLDebug::PushGroup("Eye2D");
|
||||
mBuffers->BindEyeFB(eye_ix);
|
||||
|
@ -448,7 +448,9 @@ void FGLRenderer::Flush()
|
|||
|
||||
FGLPostProcessState savedState;
|
||||
FGLDebug::PushGroup("PresentEyes");
|
||||
stereo3dMode.Present();
|
||||
// Note: This here is the ONLY place in the entire engine where the OpenGL dependent parts of the Stereo3D code need to be dealt with.
|
||||
// There's absolutely no need to create a overly complex class hierarchy for just this.
|
||||
GLRenderer->PresentStereo();
|
||||
FGLDebug::PopGroup();
|
||||
}
|
||||
}
|
||||
|
|
|
@ -42,6 +42,7 @@
|
|||
#include "gl_load/gl_interface.h"
|
||||
#include "gl/system/gl_framebuffer.h"
|
||||
#include "hwrenderer/utility/hw_cvars.h"
|
||||
#include "gl/scene/gl_portal.h"
|
||||
#include "gl/system/gl_debug.h"
|
||||
#include "gl/renderer/gl_renderer.h"
|
||||
#include "gl/renderer/gl_lightdata.h"
|
||||
|
@ -49,13 +50,11 @@
|
|||
#include "gl/renderer/gl_renderbuffers.h"
|
||||
#include "gl/data/gl_vertexbuffer.h"
|
||||
#include "gl/scene/gl_drawinfo.h"
|
||||
#include "gl/scene/gl_scenedrawer.h"
|
||||
#include "hwrenderer/postprocessing/hw_ambientshader.h"
|
||||
#include "hwrenderer/postprocessing/hw_presentshader.h"
|
||||
#include "hwrenderer/postprocessing/hw_present3dRowshader.h"
|
||||
#include "hwrenderer/postprocessing/hw_shadowmapshader.h"
|
||||
#include "gl/shaders/gl_postprocessshaderinstance.h"
|
||||
#include "gl/stereo3d/gl_stereo3d.h"
|
||||
#include "gl/textures/gl_samplers.h"
|
||||
#include "gl/dynlights/gl_lightbuffer.h"
|
||||
#include "r_videoscale.h"
|
||||
|
@ -80,11 +79,8 @@ extern bool NoInterpolateView;
|
|||
FGLRenderer::FGLRenderer(OpenGLFrameBuffer *fb)
|
||||
{
|
||||
framebuffer = fb;
|
||||
mCurrentPortal = nullptr;
|
||||
mMirrorCount = 0;
|
||||
mPlaneMirrorCount = 0;
|
||||
mAngles = FRotator(0.f, 0.f, 0.f);
|
||||
mViewVector = FVector2(0,0);
|
||||
mVBO = nullptr;
|
||||
mSkyVBO = nullptr;
|
||||
mShaderManager = nullptr;
|
||||
|
@ -121,6 +117,8 @@ void FGLRenderer::Initialize(int width, int height)
|
|||
mCustomPostProcessShaders = new FCustomPostProcessShaders();
|
||||
|
||||
// needed for the core profile, because someone decided it was a good idea to remove the default VAO.
|
||||
glGenQueries(1, &PortalQueryObject);
|
||||
|
||||
glGenVertexArrays(1, &mVAOID);
|
||||
glBindVertexArray(mVAOID);
|
||||
FGLDebug::LabelObject(GL_VERTEX_ARRAY, mVAOID, "FGLRenderer.mVAOID");
|
||||
|
@ -135,14 +133,10 @@ void FGLRenderer::Initialize(int width, int height)
|
|||
SetupLevel();
|
||||
mShaderManager = new FShaderManager;
|
||||
mSamplerManager = new FSamplerManager;
|
||||
|
||||
GLPortal::Initialize();
|
||||
}
|
||||
|
||||
FGLRenderer::~FGLRenderer()
|
||||
{
|
||||
GLPortal::Shutdown();
|
||||
|
||||
FlushModels();
|
||||
AActor::DeleteAllAttachedLights();
|
||||
FMaterial::FlushAll();
|
||||
|
@ -157,6 +151,8 @@ FGLRenderer::~FGLRenderer()
|
|||
glBindVertexArray(0);
|
||||
glDeleteVertexArrays(1, &mVAOID);
|
||||
}
|
||||
if (PortalQueryObject != 0) glDeleteQueries(1, &PortalQueryObject);
|
||||
|
||||
if (swdrawer) delete swdrawer;
|
||||
if (mBuffers) delete mBuffers;
|
||||
if (mPresentShader) delete mPresentShader;
|
||||
|
@ -195,17 +191,6 @@ void FGLRenderer::SetupLevel()
|
|||
//
|
||||
//===========================================================================
|
||||
|
||||
void FGLRenderer::FlushTextures()
|
||||
{
|
||||
FMaterial::FlushAll();
|
||||
}
|
||||
|
||||
//===========================================================================
|
||||
//
|
||||
//
|
||||
//
|
||||
//===========================================================================
|
||||
|
||||
bool FGLRenderer::StartOffscreen()
|
||||
{
|
||||
bool firstBind = (mFBID == 0);
|
||||
|
@ -281,10 +266,8 @@ sector_t *FGLRenderer::RenderView(player_t* player)
|
|||
fovratio = ratio;
|
||||
}
|
||||
|
||||
GLSceneDrawer drawer;
|
||||
|
||||
mShadowMap.Update();
|
||||
retsec = drawer.RenderViewpoint(player->camera, NULL, r_viewpoint.FieldOfView.Degrees, ratio, fovratio, true, true);
|
||||
retsec = RenderViewpoint(r_viewpoint, player->camera, NULL, r_viewpoint.FieldOfView.Degrees, ratio, fovratio, true, true);
|
||||
}
|
||||
All.Unclock();
|
||||
return retsec;
|
||||
|
@ -311,27 +294,70 @@ void FGLRenderer::RenderTextureView(FCanvasTexture *tex, AActor *Viewpoint, doub
|
|||
bounds.width = FHardwareTexture::GetTexDimension(gltex->GetWidth());
|
||||
bounds.height = FHardwareTexture::GetTexDimension(gltex->GetHeight());
|
||||
|
||||
GLSceneDrawer drawer;
|
||||
drawer.RenderViewpoint(Viewpoint, &bounds, FOV, (float)width / height, (float)width / height, false, false);
|
||||
FRenderViewpoint texvp;
|
||||
RenderViewpoint(texvp, Viewpoint, &bounds, FOV, (float)width / height, (float)width / height, false, false);
|
||||
|
||||
EndOffscreen();
|
||||
|
||||
tex->SetUpdated();
|
||||
}
|
||||
|
||||
void FGLRenderer::WriteSavePic(player_t *player, FileWriter *file, int width, int height)
|
||||
//===========================================================================
|
||||
//
|
||||
// Render the view to a savegame picture
|
||||
//
|
||||
//===========================================================================
|
||||
|
||||
void FGLRenderer::WriteSavePic (player_t *player, FileWriter *file, int width, int height)
|
||||
{
|
||||
// Todo: This needs to call the software renderer and process the returned image, if so desired.
|
||||
// This also needs to take out parts of the scene drawer so they can be shared between renderers.
|
||||
GLSceneDrawer drawer;
|
||||
drawer.WriteSavePic(player, file, width, height);
|
||||
IntRect bounds;
|
||||
bounds.left = 0;
|
||||
bounds.top = 0;
|
||||
bounds.width = width;
|
||||
bounds.height = height;
|
||||
|
||||
// if mVBO is persistently mapped we must be sure the GPU finished reading from it before we fill it with new data.
|
||||
glFinish();
|
||||
|
||||
// Switch to render buffers dimensioned for the savepic
|
||||
mBuffers = mSaveBuffers;
|
||||
|
||||
P_FindParticleSubsectors(); // make sure that all recently spawned particles have a valid subsector.
|
||||
gl_RenderState.SetVertexBuffer(mVBO);
|
||||
mVBO->Reset();
|
||||
mLights->Clear();
|
||||
|
||||
// This shouldn't overwrite the global viewpoint even for a short time.
|
||||
FRenderViewpoint savevp;
|
||||
sector_t *viewsector = RenderViewpoint(savevp, players[consoleplayer].camera, &bounds, r_viewpoint.FieldOfView.Degrees, 1.6f, 1.6f, true, false);
|
||||
glDisable(GL_STENCIL_TEST);
|
||||
gl_RenderState.SetSoftLightLevel(-1);
|
||||
CopyToBackbuffer(&bounds, false);
|
||||
|
||||
// strictly speaking not needed as the glReadPixels should block until the scene is rendered, but this is to safeguard against shitty drivers
|
||||
glFinish();
|
||||
|
||||
uint8_t * scr = (uint8_t *)M_Malloc(width * height * 3);
|
||||
glReadPixels(0,0,width, height,GL_RGB,GL_UNSIGNED_BYTE,scr);
|
||||
M_CreatePNG (file, scr + ((height-1) * width * 3), NULL, SS_RGB, width, height, -width * 3, Gamma);
|
||||
M_Free(scr);
|
||||
|
||||
// Switch back the screen render buffers
|
||||
screen->SetViewportRects(nullptr);
|
||||
mBuffers = mScreenBuffers;
|
||||
}
|
||||
|
||||
//===========================================================================
|
||||
//
|
||||
//
|
||||
//
|
||||
//===========================================================================
|
||||
|
||||
void FGLRenderer::BeginFrame()
|
||||
{
|
||||
buffersActive = GLRenderer->mScreenBuffers->Setup(screen->mScreenViewport.width, screen->mScreenViewport.height, screen->mSceneViewport.width, screen->mSceneViewport.height);
|
||||
buffersActive = mScreenBuffers->Setup(screen->mScreenViewport.width, screen->mScreenViewport.height, screen->mSceneViewport.width, screen->mSceneViewport.height);
|
||||
if (buffersActive)
|
||||
buffersActive = GLRenderer->mSaveBuffers->Setup(SAVEPICWIDTH, SAVEPICHEIGHT, SAVEPICWIDTH, SAVEPICHEIGHT);
|
||||
buffersActive = mSaveBuffers->Setup(SAVEPICWIDTH, SAVEPICHEIGHT, SAVEPICWIDTH, SAVEPICHEIGHT);
|
||||
}
|
||||
|
||||
//===========================================================================
|
||||
|
@ -396,9 +422,11 @@ void FGLRenderer::Draw2D(F2DDrawer *drawer)
|
|||
const auto &mScreenViewport = screen->mScreenViewport;
|
||||
glViewport(mScreenViewport.left, mScreenViewport.top, mScreenViewport.width, mScreenViewport.height);
|
||||
|
||||
gl_RenderState.mViewMatrix.loadIdentity();
|
||||
gl_RenderState.mProjectionMatrix.ortho(0, screen->GetWidth(), screen->GetHeight(), 0, -1.0f, 1.0f);
|
||||
gl_RenderState.ApplyMatrices();
|
||||
HWViewpointUniforms matrices;
|
||||
matrices.SetDefaults();
|
||||
matrices.mProjectionMatrix.ortho(0, screen->GetWidth(), screen->GetHeight(), 0, -1.0f, 1.0f);
|
||||
matrices.CalcDependencies();
|
||||
GLRenderer->mShaderManager->ApplyMatrices(&matrices, NORMAL_PASS);
|
||||
|
||||
glDisable(GL_DEPTH_TEST);
|
||||
|
||||
|
@ -524,7 +552,7 @@ void FGLRenderer::Draw2D(F2DDrawer *drawer)
|
|||
}
|
||||
glDisable(GL_SCISSOR_TEST);
|
||||
|
||||
gl_RenderState.SetVertexBuffer(GLRenderer->mVBO);
|
||||
gl_RenderState.SetVertexBuffer(mVBO);
|
||||
gl_RenderState.EnableTexture(true);
|
||||
gl_RenderState.EnableBrightmap(true);
|
||||
gl_RenderState.SetTextureMode(TM_MODULATE);
|
||||
|
|
|
@ -6,6 +6,7 @@
|
|||
#include "vectors.h"
|
||||
#include "r_renderer.h"
|
||||
#include "r_data/matrix.h"
|
||||
#include "hwrenderer/scene/hw_portal.h"
|
||||
#include "gl/dynlights/gl_shadowmap.h"
|
||||
#include <functional>
|
||||
|
||||
|
@ -37,8 +38,8 @@ class FGL2DDrawer;
|
|||
class FHardwareTexture;
|
||||
class FShadowMapShader;
|
||||
class FCustomPostProcessShaders;
|
||||
class GLSceneDrawer;
|
||||
class SWSceneDrawer;
|
||||
struct FRenderViewpoint;
|
||||
#define NOQUEUE nullptr // just some token to be used as a placeholder
|
||||
|
||||
enum
|
||||
|
@ -54,16 +55,14 @@ class FGLRenderer
|
|||
public:
|
||||
|
||||
OpenGLFrameBuffer *framebuffer;
|
||||
//GLPortal *mClipPortal;
|
||||
GLPortal *mCurrentPortal;
|
||||
int mMirrorCount;
|
||||
int mPlaneMirrorCount;
|
||||
float mCurrentFoV;
|
||||
AActor *mViewActor;
|
||||
FShaderManager *mShaderManager;
|
||||
FSamplerManager *mSamplerManager;
|
||||
unsigned int mFBID;
|
||||
unsigned int mVAOID;
|
||||
unsigned int PortalQueryObject;
|
||||
|
||||
int mOldFBID;
|
||||
|
||||
FGLRenderBuffers *mBuffers;
|
||||
|
@ -82,21 +81,19 @@ public:
|
|||
|
||||
FShadowMap mShadowMap;
|
||||
|
||||
FRotator mAngles;
|
||||
FVector2 mViewVector;
|
||||
//FRotator mAngles;
|
||||
|
||||
FFlatVertexBuffer *mVBO;
|
||||
FSkyVertexBuffer *mSkyVBO;
|
||||
FLightBuffer *mLights;
|
||||
SWSceneDrawer *swdrawer = nullptr;
|
||||
|
||||
bool mDrawingScene2D = false;
|
||||
FPortalSceneState mPortalState;
|
||||
|
||||
bool buffersActive = false;
|
||||
|
||||
float mSceneClearColor[3];
|
||||
|
||||
float mGlobVis = 0.0f;
|
||||
|
||||
FGLRenderer(OpenGLFrameBuffer *fb);
|
||||
~FGLRenderer() ;
|
||||
|
||||
|
@ -104,13 +101,13 @@ public:
|
|||
|
||||
void ClearBorders();
|
||||
|
||||
void FlushTextures();
|
||||
void SetupLevel();
|
||||
void ResetSWScene();
|
||||
|
||||
void PresentStereo();
|
||||
void RenderScreenQuad();
|
||||
void PostProcessScene(int fixedcm, const std::function<void()> &afterBloomDrawEndScene2D);
|
||||
void AmbientOccludeScene();
|
||||
void AmbientOccludeScene(float m5);
|
||||
void UpdateCameraExposure();
|
||||
void BloomScene(int fixedcm);
|
||||
void TonemapScene();
|
||||
|
@ -127,6 +124,10 @@ public:
|
|||
void WriteSavePic(player_t *player, FileWriter *file, int width, int height);
|
||||
sector_t *RenderView(player_t *player);
|
||||
void BeginFrame();
|
||||
|
||||
void Set3DViewport(bool mainview);
|
||||
sector_t *RenderViewpoint (FRenderViewpoint &mainvp, AActor * camera, IntRect * bounds, float fov, float ratio, float fovratio, bool mainview, bool toscreen);
|
||||
|
||||
|
||||
bool StartOffscreen();
|
||||
void EndOffscreen();
|
||||
|
@ -134,9 +135,6 @@ public:
|
|||
void FillSimplePoly(FTexture *texture, FVector2 *points, int npoints,
|
||||
double originx, double originy, double scalex, double scaley,
|
||||
DAngle rotation, const FColormap &colormap, PalEntry flatcolor, int lightlevel, int bottomclip);
|
||||
|
||||
static float GetZNear() { return 5.f; }
|
||||
static float GetZFar() { return 65536.f; }
|
||||
};
|
||||
|
||||
#include "hwrenderer/scene/hw_fakeflat.h"
|
||||
|
|
|
@ -42,7 +42,6 @@ void gl_SetTextureMode(int type);
|
|||
FRenderState gl_RenderState;
|
||||
|
||||
CVAR(Bool, gl_direct_state_change, true, 0)
|
||||
CVAR(Bool, gl_bandedswlight, false, CVAR_ARCHIVE)
|
||||
|
||||
|
||||
static VSMatrix identityMatrix(1);
|
||||
|
@ -62,7 +61,7 @@ static void matrixToGL(const VSMatrix &mat, int loc)
|
|||
void FRenderState::Reset()
|
||||
{
|
||||
mTextureEnabled = true;
|
||||
mClipLineShouldBeActive = mClipLineEnabled = mSplitEnabled = mBrightmapEnabled = mFogEnabled = mGlowEnabled = false;
|
||||
mSplitEnabled = mBrightmapEnabled = mFogEnabled = mGlowEnabled = false;
|
||||
mColorMask[0] = mColorMask[1] = mColorMask[2] = mColorMask[3] = true;
|
||||
currentColorMask[0] = currentColorMask[1] = currentColorMask[2] = currentColorMask[3] = true;
|
||||
mFogColor.d = -1;
|
||||
|
@ -81,8 +80,6 @@ void FRenderState::Reset()
|
|||
mLightParms[0] = mLightParms[1] = mLightParms[2] = 0.0f;
|
||||
mLightParms[3] = -1.f;
|
||||
mSpecialEffect = EFF_NONE;
|
||||
mClipHeight = 0.f;
|
||||
mClipHeightDirection = 0.f;
|
||||
mGlossiness = 0.0f;
|
||||
mSpecularLevel = 0.0f;
|
||||
mShaderTimer = 0.0f;
|
||||
|
@ -96,19 +93,15 @@ void FRenderState::Reset()
|
|||
mInterpolationFactor = 0.0f;
|
||||
|
||||
mColor.Set(1.0f, 1.0f, 1.0f, 1.0f);
|
||||
mCameraPos.Set(0.0f, 0.0f, 0.0f, 0.0f);
|
||||
mGlowTop.Set(0.0f, 0.0f, 0.0f, 0.0f);
|
||||
mGlowBottom.Set(0.0f, 0.0f, 0.0f, 0.0f);
|
||||
mGlowTopPlane.Set(0.0f, 0.0f, 0.0f, 0.0f);
|
||||
mGlowBottomPlane.Set(0.0f, 0.0f, 0.0f, 0.0f);
|
||||
mSplitTopPlane.Set(0.0f, 0.0f, 0.0f, 0.0f);
|
||||
mSplitBottomPlane.Set(0.0f, 0.0f, 0.0f, 0.0f);
|
||||
mClipLine.Set(0.0f, 0.0f, 0.0f, 0.0f);
|
||||
mDynColor.Set(0.0f, 0.0f, 0.0f, 0.0f);
|
||||
mEffectState = 0;
|
||||
activeShader = nullptr;
|
||||
mProjectionMatrix.loadIdentity();
|
||||
mViewMatrix.loadIdentity();
|
||||
mModelMatrix.loadIdentity();
|
||||
mTextureMatrix.loadIdentity();
|
||||
mPassType = NORMAL_PASS;
|
||||
|
@ -162,23 +155,17 @@ bool FRenderState::ApplyShader()
|
|||
|
||||
activeShader->muDesaturation.Set(mDesaturation / 255.f);
|
||||
activeShader->muFogEnabled.Set(fogset);
|
||||
activeShader->muPalLightLevels.Set(static_cast<int>(gl_bandedswlight) | (static_cast<int>(gl_fogmode) << 8));
|
||||
activeShader->muGlobVis.Set(GLRenderer->mGlobVis / 32.0f);
|
||||
activeShader->muTextureMode.Set(mTextureMode == TM_MODULATE && mTempTM == TM_OPAQUE ? TM_OPAQUE : mTextureMode);
|
||||
activeShader->muCameraPos.Set(mCameraPos.vec);
|
||||
activeShader->muLightParms.Set(mLightParms);
|
||||
activeShader->muFogColor.Set(mFogColor);
|
||||
activeShader->muObjectColor.Set(mObjectColor);
|
||||
activeShader->muObjectColor2.Set(mObjectColor2);
|
||||
activeShader->muDynLightColor.Set(mDynColor.vec);
|
||||
activeShader->muInterpolationFactor.Set(mInterpolationFactor);
|
||||
activeShader->muClipHeight.Set(mClipHeight);
|
||||
activeShader->muClipHeightDirection.Set(mClipHeightDirection);
|
||||
activeShader->muTimer.Set((double)(screen->FrameTime - firstFrame) * (double)mShaderTimer / 1000.);
|
||||
activeShader->muAlphaThreshold.Set(mAlphaThreshold);
|
||||
activeShader->muLightIndex.Set(-1);
|
||||
activeShader->muClipSplit.Set(mClipSplit);
|
||||
activeShader->muViewHeight.Set(viewheight);
|
||||
activeShader->muSpecularMaterial.Set(mGlossiness, mSpecularLevel);
|
||||
|
||||
if (mGlowEnabled)
|
||||
|
@ -213,17 +200,6 @@ bool FRenderState::ApplyShader()
|
|||
activeShader->currentsplitstate = 0;
|
||||
}
|
||||
|
||||
if (mClipLineEnabled)
|
||||
{
|
||||
activeShader->muClipLine.Set(mClipLine.vec);
|
||||
activeShader->currentcliplinestate = 1;
|
||||
}
|
||||
else if (activeShader->currentcliplinestate)
|
||||
{
|
||||
activeShader->muClipLine.Set(-10000000.0, 0, 0, 0);
|
||||
activeShader->currentcliplinestate = 0;
|
||||
}
|
||||
|
||||
if (mTextureMatrixEnabled)
|
||||
{
|
||||
matrixToGL(mTextureMatrix, activeShader->texturematrix_index);
|
||||
|
@ -304,14 +280,6 @@ void FRenderState::ApplyColorMask()
|
|||
}
|
||||
}
|
||||
|
||||
void FRenderState::ApplyMatrices()
|
||||
{
|
||||
if (GLRenderer->mShaderManager != NULL)
|
||||
{
|
||||
GLRenderer->mShaderManager->ApplyMatrices(&mProjectionMatrix, &mViewMatrix, mPassType);
|
||||
}
|
||||
}
|
||||
|
||||
void FRenderState::ApplyLightIndex(int index)
|
||||
{
|
||||
if (index > -1 && GLRenderer->mLights->GetBufferType() == GL_UNIFORM_BUFFER)
|
||||
|
@ -320,20 +288,3 @@ void FRenderState::ApplyLightIndex(int index)
|
|||
}
|
||||
activeShader->muLightIndex.Set(index);
|
||||
}
|
||||
|
||||
void FRenderState::SetClipHeight(float height, float direction)
|
||||
{
|
||||
mClipHeight = height;
|
||||
mClipHeightDirection = direction;
|
||||
|
||||
if (gl.flags & RFL_NO_CLIP_PLANES) return;
|
||||
|
||||
if (direction != 0.f)
|
||||
{
|
||||
glEnable(GL_CLIP_DISTANCE0);
|
||||
}
|
||||
else
|
||||
{
|
||||
glDisable(GL_CLIP_DISTANCE0); // GL_CLIP_PLANE0 is the same value so no need to make a distinction
|
||||
}
|
||||
}
|
||||
|
|
|
@ -79,8 +79,6 @@ class FRenderState
|
|||
uint8_t mFogEnabled;
|
||||
bool mGlowEnabled;
|
||||
bool mSplitEnabled;
|
||||
bool mClipLineEnabled;
|
||||
bool mClipLineShouldBeActive;
|
||||
bool mBrightmapEnabled;
|
||||
bool mColorMask[4];
|
||||
bool currentColorMask[4];
|
||||
|
@ -96,18 +94,15 @@ class FRenderState
|
|||
bool mTextureMatrixEnabled;
|
||||
bool mLastDepthClamp;
|
||||
float mInterpolationFactor;
|
||||
float mClipHeight, mClipHeightDirection;
|
||||
float mGlossiness, mSpecularLevel;
|
||||
float mShaderTimer;
|
||||
|
||||
FVertexBuffer *mVertexBuffer, *mCurrentVertexBuffer;
|
||||
FStateVec4 mNormal;
|
||||
FStateVec4 mColor;
|
||||
FStateVec4 mCameraPos;
|
||||
FStateVec4 mGlowTop, mGlowBottom;
|
||||
FStateVec4 mGlowTopPlane, mGlowBottomPlane;
|
||||
FStateVec4 mSplitTopPlane, mSplitBottomPlane;
|
||||
FStateVec4 mClipLine;
|
||||
PalEntry mFogColor;
|
||||
PalEntry mObjectColor;
|
||||
PalEntry mObjectColor2;
|
||||
|
@ -131,11 +126,8 @@ class FRenderState
|
|||
|
||||
public:
|
||||
|
||||
VSMatrix mProjectionMatrix;
|
||||
VSMatrix mViewMatrix;
|
||||
VSMatrix mModelMatrix;
|
||||
VSMatrix mTextureMatrix;
|
||||
VSMatrix mNormalViewMatrix;
|
||||
|
||||
FRenderState()
|
||||
{
|
||||
|
@ -162,7 +154,6 @@ public:
|
|||
|
||||
void Apply();
|
||||
void ApplyColorMask();
|
||||
void ApplyMatrices();
|
||||
void ApplyLightIndex(int index);
|
||||
|
||||
void SetVertexBuffer(FVertexBuffer *vb)
|
||||
|
@ -176,33 +167,6 @@ public:
|
|||
mCurrentVertexBuffer = NULL;
|
||||
}
|
||||
|
||||
float GetClipHeight()
|
||||
{
|
||||
return mClipHeight;
|
||||
}
|
||||
|
||||
float GetClipHeightDirection()
|
||||
{
|
||||
return mClipHeightDirection;
|
||||
}
|
||||
|
||||
FStateVec4 &GetClipLine()
|
||||
{
|
||||
return mClipLine;
|
||||
}
|
||||
|
||||
bool GetClipLineState()
|
||||
{
|
||||
return mClipLineEnabled;
|
||||
}
|
||||
|
||||
bool GetClipLineShouldBeActive()
|
||||
{
|
||||
return mClipLineShouldBeActive;
|
||||
}
|
||||
|
||||
void SetClipHeight(float height, float direction);
|
||||
|
||||
void SetNormal(FVector3 norm)
|
||||
{
|
||||
mNormal.Set(norm.X, norm.Y, norm.Z, 0.f);
|
||||
|
@ -307,32 +271,6 @@ public:
|
|||
}
|
||||
}
|
||||
|
||||
void SetClipLine(line_t *line)
|
||||
{
|
||||
mClipLine.Set(line->v1->fX(), line->v1->fY(), line->Delta().X, line->Delta().Y);
|
||||
}
|
||||
|
||||
void EnableClipLine(bool on)
|
||||
{
|
||||
if (!(gl.flags & RFL_NO_CLIP_PLANES))
|
||||
{
|
||||
mClipLineEnabled = on;
|
||||
if (on)
|
||||
{
|
||||
glEnable(GL_CLIP_DISTANCE0);
|
||||
}
|
||||
else
|
||||
{
|
||||
glDisable(GL_CLIP_DISTANCE0);
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
// this needs to be flagged because in this case per-sector plane rendering needs to be disabled if a clip plane is active.
|
||||
mClipLineShouldBeActive = on;
|
||||
}
|
||||
}
|
||||
|
||||
void EnableBrightmap(bool on)
|
||||
{
|
||||
mBrightmapEnabled = on;
|
||||
|
@ -348,11 +286,6 @@ public:
|
|||
mTextureMatrixEnabled = on;
|
||||
}
|
||||
|
||||
void SetCameraPos(float x, float y, float z)
|
||||
{
|
||||
mCameraPos.Set(x, z, y, 0);
|
||||
}
|
||||
|
||||
void SetGlowParams(float *t, float *b)
|
||||
{
|
||||
mGlowTop.Set(t[0], t[1], t[2], t[3]);
|
||||
|
|
364
src/gl/renderer/gl_stereo3d.cpp
Normal file
364
src/gl/renderer/gl_stereo3d.cpp
Normal file
|
@ -0,0 +1,364 @@
|
|||
//
|
||||
//---------------------------------------------------------------------------
|
||||
//
|
||||
// Copyright(C) 2015 Christopher Bruns
|
||||
// All rights reserved.
|
||||
//
|
||||
// This program is free software: you can redistribute it and/or modify
|
||||
// it under the terms of the GNU Lesser General Public License as published by
|
||||
// the Free Software Foundation, either version 3 of the License, or
|
||||
// (at your option) any later version.
|
||||
//
|
||||
// This program is distributed in the hope that it will be useful,
|
||||
// but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
// GNU Lesser General Public License for more details.
|
||||
//
|
||||
// You should have received a copy of the GNU Lesser General Public License
|
||||
// along with this program. If not, see http://www.gnu.org/licenses/
|
||||
//
|
||||
//--------------------------------------------------------------------------
|
||||
//
|
||||
/*
|
||||
** gl_stereo3d.cpp
|
||||
** Stereoscopic 3D API
|
||||
**
|
||||
*/
|
||||
|
||||
#include "gl_load/gl_system.h"
|
||||
#include "gl/renderer/gl_renderer.h"
|
||||
#include "gl/renderer/gl_renderbuffers.h"
|
||||
#include "hwrenderer/utility/hw_vrmodes.h"
|
||||
#include "gl/system/gl_framebuffer.h"
|
||||
#include "gl/renderer/gl_postprocessstate.h"
|
||||
#include "hwrenderer/postprocessing/hw_presentshader.h"
|
||||
#include "hwrenderer/postprocessing/hw_present3dRowshader.h"
|
||||
|
||||
EXTERN_CVAR(Int, vr_mode)
|
||||
EXTERN_CVAR(Float, vid_saturation)
|
||||
EXTERN_CVAR(Float, vid_brightness)
|
||||
EXTERN_CVAR(Float, vid_contrast)
|
||||
EXTERN_CVAR(Int, gl_satformula)
|
||||
|
||||
//==========================================================================
|
||||
//
|
||||
//
|
||||
//
|
||||
//==========================================================================
|
||||
|
||||
static void PresentAnaglyph(bool r, bool g, bool b)
|
||||
{
|
||||
GLRenderer->mBuffers->BindOutputFB();
|
||||
GLRenderer->ClearBorders();
|
||||
|
||||
glColorMask(r, g, b, 1);
|
||||
GLRenderer->mBuffers->BindEyeTexture(0, 0);
|
||||
GLRenderer->DrawPresentTexture(screen->mOutputLetterbox, true);
|
||||
|
||||
glColorMask(!r, !g, !b, 1);
|
||||
GLRenderer->mBuffers->BindEyeTexture(1, 0);
|
||||
GLRenderer->DrawPresentTexture(screen->mOutputLetterbox, true);
|
||||
|
||||
glColorMask(1, 1, 1, 1);
|
||||
}
|
||||
|
||||
//==========================================================================
|
||||
//
|
||||
//
|
||||
//
|
||||
//==========================================================================
|
||||
|
||||
static void PresentSideBySide()
|
||||
{
|
||||
GLRenderer->mBuffers->BindOutputFB();
|
||||
GLRenderer->ClearBorders();
|
||||
|
||||
// Compute screen regions to use for left and right eye views
|
||||
int leftWidth = screen->mOutputLetterbox.width / 2;
|
||||
int rightWidth = screen->mOutputLetterbox.width - leftWidth;
|
||||
IntRect leftHalfScreen = screen->mOutputLetterbox;
|
||||
leftHalfScreen.width = leftWidth;
|
||||
IntRect rightHalfScreen = screen->mOutputLetterbox;
|
||||
rightHalfScreen.width = rightWidth;
|
||||
rightHalfScreen.left += leftWidth;
|
||||
|
||||
GLRenderer->mBuffers->BindEyeTexture(0, 0);
|
||||
GLRenderer->DrawPresentTexture(leftHalfScreen, true);
|
||||
|
||||
GLRenderer->mBuffers->BindEyeTexture(1, 0);
|
||||
GLRenderer->DrawPresentTexture(rightHalfScreen, true);
|
||||
}
|
||||
|
||||
|
||||
//==========================================================================
|
||||
//
|
||||
//
|
||||
//
|
||||
//==========================================================================
|
||||
|
||||
static void PresentTopBottom()
|
||||
{
|
||||
GLRenderer->mBuffers->BindOutputFB();
|
||||
GLRenderer->ClearBorders();
|
||||
|
||||
// Compute screen regions to use for left and right eye views
|
||||
int topHeight = screen->mOutputLetterbox.height / 2;
|
||||
int bottomHeight = screen->mOutputLetterbox.height - topHeight;
|
||||
IntRect topHalfScreen = screen->mOutputLetterbox;
|
||||
topHalfScreen.height = topHeight;
|
||||
topHalfScreen.top = topHeight;
|
||||
IntRect bottomHalfScreen = screen->mOutputLetterbox;
|
||||
bottomHalfScreen.height = bottomHeight;
|
||||
bottomHalfScreen.top = 0;
|
||||
|
||||
GLRenderer->mBuffers->BindEyeTexture(0, 0);
|
||||
GLRenderer->DrawPresentTexture(topHalfScreen, true);
|
||||
|
||||
GLRenderer->mBuffers->BindEyeTexture(1, 0);
|
||||
GLRenderer->DrawPresentTexture(bottomHalfScreen, true);
|
||||
}
|
||||
|
||||
//==========================================================================
|
||||
//
|
||||
//
|
||||
//
|
||||
//==========================================================================
|
||||
|
||||
static void prepareInterleavedPresent(FPresentShaderBase& shader)
|
||||
{
|
||||
GLRenderer->mBuffers->BindOutputFB();
|
||||
GLRenderer->ClearBorders();
|
||||
|
||||
|
||||
// Bind each eye texture, for composition in the shader
|
||||
GLRenderer->mBuffers->BindEyeTexture(0, 0);
|
||||
GLRenderer->mBuffers->BindEyeTexture(1, 1);
|
||||
|
||||
glActiveTexture(GL_TEXTURE0);
|
||||
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST);
|
||||
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST);
|
||||
|
||||
glActiveTexture(GL_TEXTURE1);
|
||||
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST);
|
||||
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST);
|
||||
|
||||
const IntRect& box = screen->mOutputLetterbox;
|
||||
glViewport(box.left, box.top, box.width, box.height);
|
||||
|
||||
shader.Bind(NOQUEUE);
|
||||
|
||||
if (GLRenderer->framebuffer->IsHWGammaActive())
|
||||
{
|
||||
shader.Uniforms->InvGamma = 1.0f;
|
||||
shader.Uniforms->Contrast = 1.0f;
|
||||
shader.Uniforms->Brightness = 0.0f;
|
||||
shader.Uniforms->Saturation = 1.0f;
|
||||
}
|
||||
else
|
||||
{
|
||||
shader.Uniforms->InvGamma = 1.0f / clamp<float>(Gamma, 0.1f, 4.f);
|
||||
shader.Uniforms->Contrast = clamp<float>(vid_contrast, 0.1f, 3.f);
|
||||
shader.Uniforms->Brightness = clamp<float>(vid_brightness, -0.8f, 0.8f);
|
||||
shader.Uniforms->Saturation = clamp<float>(vid_saturation, -15.0f, 15.0f);
|
||||
shader.Uniforms->GrayFormula = static_cast<int>(gl_satformula);
|
||||
}
|
||||
shader.Uniforms->Scale = {
|
||||
screen->mScreenViewport.width / (float)GLRenderer->mBuffers->GetWidth(),
|
||||
screen->mScreenViewport.height / (float)GLRenderer->mBuffers->GetHeight()
|
||||
};
|
||||
shader.Uniforms.Set();
|
||||
}
|
||||
|
||||
//==========================================================================
|
||||
//
|
||||
//
|
||||
//
|
||||
//==========================================================================
|
||||
|
||||
static void PresentColumnInterleaved()
|
||||
{
|
||||
FGLPostProcessState savedState;
|
||||
savedState.SaveTextureBindings(2);
|
||||
prepareInterleavedPresent(*GLRenderer->mPresent3dColumnShader);
|
||||
|
||||
// Compute absolute offset from top of screen to top of current display window
|
||||
// because we need screen-relative, not window-relative, scan line parity
|
||||
|
||||
// Todo:
|
||||
//auto clientoffset = screen->GetClientOffset();
|
||||
//auto windowHOffset = clientoffset.X % 2;
|
||||
int windowHOffset = 0;
|
||||
|
||||
GLRenderer->mPresent3dColumnShader->Uniforms->WindowPositionParity = windowHOffset;
|
||||
GLRenderer->mPresent3dColumnShader->Uniforms.Set();
|
||||
|
||||
GLRenderer->RenderScreenQuad();
|
||||
}
|
||||
|
||||
//==========================================================================
|
||||
//
|
||||
//
|
||||
//
|
||||
//==========================================================================
|
||||
|
||||
static void PresentRowInterleaved()
|
||||
{
|
||||
FGLPostProcessState savedState;
|
||||
savedState.SaveTextureBindings(2);
|
||||
prepareInterleavedPresent(*GLRenderer->mPresent3dRowShader);
|
||||
|
||||
// Todo:
|
||||
//auto clientoffset = screen->GetClientOffset();
|
||||
//auto windowVOffset = clientoffset.Y % 2;
|
||||
int windowVOffset = 0;
|
||||
|
||||
GLRenderer->mPresent3dRowShader->Uniforms->WindowPositionParity =
|
||||
(windowVOffset
|
||||
+ screen->mOutputLetterbox.height + 1 // +1 because of origin at bottom
|
||||
) % 2;
|
||||
|
||||
GLRenderer->mPresent3dRowShader->Uniforms.Set();
|
||||
GLRenderer->RenderScreenQuad();
|
||||
}
|
||||
|
||||
//==========================================================================
|
||||
//
|
||||
//
|
||||
//
|
||||
//==========================================================================
|
||||
|
||||
static void PresentCheckerInterleaved()
|
||||
{
|
||||
FGLPostProcessState savedState;
|
||||
savedState.SaveTextureBindings(2);
|
||||
prepareInterleavedPresent(*GLRenderer->mPresent3dCheckerShader);
|
||||
|
||||
// Compute absolute offset from top of screen to top of current display window
|
||||
// because we need screen-relative, not window-relative, scan line parity
|
||||
|
||||
//auto clientoffset = screen->GetClientOffset();
|
||||
//auto windowHOffset = clientoffset.X % 2;
|
||||
//auto windowVOffset = clientoffset.Y % 2;
|
||||
int windowHOffset = 0;
|
||||
int windowVOffset = 0;
|
||||
|
||||
GLRenderer->mPresent3dCheckerShader->Uniforms->WindowPositionParity =
|
||||
(windowVOffset
|
||||
+ windowHOffset
|
||||
+ screen->mOutputLetterbox.height + 1 // +1 because of origin at bottom
|
||||
) % 2; // because we want the top pixel offset, but gl_FragCoord.y is the bottom pixel offset
|
||||
|
||||
GLRenderer->mPresent3dCheckerShader->Uniforms.Set();
|
||||
GLRenderer->RenderScreenQuad();
|
||||
}
|
||||
|
||||
//==========================================================================
|
||||
//
|
||||
// Sometimes the stereo render context is not ready immediately at start up
|
||||
//
|
||||
//==========================================================================
|
||||
|
||||
bool QuadStereoCheckInitialRenderContextState()
|
||||
{
|
||||
// Keep trying until we see at least one good OpenGL context to render to
|
||||
static bool bQuadStereoSupported = false;
|
||||
static bool bDecentContextWasFound = false;
|
||||
static int contextCheckCount = 0;
|
||||
if ((!bDecentContextWasFound) && (contextCheckCount < 200))
|
||||
{
|
||||
contextCheckCount += 1;
|
||||
glBindFramebuffer(GL_DRAW_FRAMEBUFFER, 0); // This question is about the main screen display context
|
||||
GLboolean supportsStereo, supportsBuffered;
|
||||
glGetBooleanv(GL_DOUBLEBUFFER, &supportsBuffered);
|
||||
if (supportsBuffered) // Finally, a useful OpenGL context
|
||||
{
|
||||
// This block will be executed exactly ONCE during a game run
|
||||
bDecentContextWasFound = true; // now we can stop checking every frame...
|
||||
// Now check whether this context supports hardware stereo
|
||||
glGetBooleanv(GL_STEREO, &supportsStereo);
|
||||
bQuadStereoSupported = supportsStereo && supportsBuffered;
|
||||
}
|
||||
}
|
||||
return bQuadStereoSupported;
|
||||
}
|
||||
|
||||
//==========================================================================
|
||||
//
|
||||
//
|
||||
//
|
||||
//==========================================================================
|
||||
|
||||
static void PresentQuadStereo()
|
||||
{
|
||||
if (QuadStereoCheckInitialRenderContextState())
|
||||
{
|
||||
GLRenderer->mBuffers->BindOutputFB();
|
||||
|
||||
glDrawBuffer(GL_BACK_LEFT);
|
||||
GLRenderer->ClearBorders();
|
||||
GLRenderer->mBuffers->BindEyeTexture(0, 0);
|
||||
GLRenderer->DrawPresentTexture(screen->mOutputLetterbox, true);
|
||||
|
||||
glDrawBuffer(GL_BACK_RIGHT);
|
||||
GLRenderer->ClearBorders();
|
||||
GLRenderer->mBuffers->BindEyeTexture(1, 0);
|
||||
GLRenderer->DrawPresentTexture(screen->mOutputLetterbox, true);
|
||||
|
||||
glDrawBuffer(GL_BACK);
|
||||
}
|
||||
else
|
||||
{
|
||||
GLRenderer->mBuffers->BindOutputFB();
|
||||
GLRenderer->ClearBorders();
|
||||
GLRenderer->mBuffers->BindEyeTexture(0, 0);
|
||||
GLRenderer->DrawPresentTexture(screen->mOutputLetterbox, true);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
void FGLRenderer::PresentStereo()
|
||||
{
|
||||
switch (vr_mode)
|
||||
{
|
||||
default:
|
||||
return;
|
||||
|
||||
case VR_GREENMAGENTA:
|
||||
PresentAnaglyph(false, true, false);
|
||||
break;
|
||||
|
||||
case VR_REDCYAN:
|
||||
PresentAnaglyph(true, false, false);
|
||||
break;
|
||||
|
||||
case VR_AMBERBLUE:
|
||||
PresentAnaglyph(true, true, false);
|
||||
break;
|
||||
|
||||
case VR_SIDEBYSIDEFULL:
|
||||
case VR_SIDEBYSIDESQUISHED:
|
||||
PresentSideBySide();
|
||||
break;
|
||||
|
||||
case VR_TOPBOTTOM:
|
||||
PresentTopBottom();
|
||||
break;
|
||||
|
||||
case VR_ROWINTERLEAVED:
|
||||
PresentRowInterleaved();
|
||||
break;
|
||||
|
||||
case VR_COLUMNINTERLEAVED:
|
||||
PresentColumnInterleaved();
|
||||
break;
|
||||
|
||||
case VR_CHECKERINTERLEAVED:
|
||||
PresentCheckerInterleaved();
|
||||
break;
|
||||
|
||||
case VR_QUADSTEREO:
|
||||
PresentQuadStereo();
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
|
@ -37,13 +37,23 @@
|
|||
|
||||
#include "gl/data/gl_vertexbuffer.h"
|
||||
#include "gl/scene/gl_drawinfo.h"
|
||||
#include "hwrenderer/scene/hw_clipper.h"
|
||||
#include "gl/scene/gl_portal.h"
|
||||
#include "gl/scene/gl_scenedrawer.h"
|
||||
#include "gl/renderer/gl_renderstate.h"
|
||||
#include "gl/stereo3d/scoped_color_mask.h"
|
||||
#include "gl/renderer/gl_quaddrawer.h"
|
||||
#include "gl/dynlights/gl_lightbuffer.h"
|
||||
|
||||
class FDrawInfoList
|
||||
{
|
||||
public:
|
||||
TDeletingArray<FDrawInfo *> mList;
|
||||
|
||||
|
||||
FDrawInfo * GetNew();
|
||||
void Release(FDrawInfo *);
|
||||
};
|
||||
|
||||
|
||||
static FDrawInfo * gl_drawinfo;
|
||||
FDrawInfoList di_list;
|
||||
|
||||
|
@ -63,7 +73,7 @@ void FDrawInfo::DoDrawSorted(HWDrawList *dl, SortNode * head)
|
|||
if (dl->drawitems[head->itemindex].rendertype == GLDIT_FLAT)
|
||||
{
|
||||
z = dl->flats[dl->drawitems[head->itemindex].index]->z;
|
||||
relation = z > r_viewpoint.Pos.Z ? 1 : -1;
|
||||
relation = z > Viewpoint.Pos.Z ? 1 : -1;
|
||||
}
|
||||
|
||||
|
||||
|
@ -164,23 +174,6 @@ void FDrawInfoList::Release(FDrawInfo * di)
|
|||
mList.Push(di);
|
||||
}
|
||||
|
||||
//==========================================================================
|
||||
//
|
||||
//
|
||||
//
|
||||
//==========================================================================
|
||||
|
||||
FDrawInfo::FDrawInfo()
|
||||
{
|
||||
next = NULL;
|
||||
}
|
||||
|
||||
FDrawInfo::~FDrawInfo()
|
||||
{
|
||||
ClearBuffers();
|
||||
}
|
||||
|
||||
|
||||
//==========================================================================
|
||||
//
|
||||
// Sets up a new drawinfo struct
|
||||
|
@ -190,12 +183,21 @@ FDrawInfo::~FDrawInfo()
|
|||
// OpenGL has no use for multiple clippers so use the same one for all DrawInfos.
|
||||
static Clipper staticClipper;
|
||||
|
||||
FDrawInfo *FDrawInfo::StartDrawInfo(GLSceneDrawer *drawer)
|
||||
FDrawInfo *FDrawInfo::StartDrawInfo(FRenderViewpoint &parentvp, HWViewpointUniforms *uniforms)
|
||||
{
|
||||
FDrawInfo *di=di_list.GetNew();
|
||||
di->mDrawer = drawer;
|
||||
di->mVBO = GLRenderer->mVBO;
|
||||
di->mClipper = &staticClipper;
|
||||
di->Viewpoint = parentvp;
|
||||
if (uniforms)
|
||||
{
|
||||
di->VPUniforms = *uniforms;
|
||||
// The clip planes will never be inherited from the parent drawinfo.
|
||||
di->VPUniforms.mClipLine.X = -1000001.f;
|
||||
di->VPUniforms.mClipHeight = 0;
|
||||
}
|
||||
else di->VPUniforms.SetDefaults();
|
||||
di->mClipper->SetViewpoint(di->Viewpoint);
|
||||
staticClipper.Clear();
|
||||
di->StartScene();
|
||||
return di;
|
||||
|
@ -205,7 +207,7 @@ void FDrawInfo::StartScene()
|
|||
{
|
||||
ClearBuffers();
|
||||
|
||||
next = gl_drawinfo;
|
||||
outer = gl_drawinfo;
|
||||
gl_drawinfo = this;
|
||||
for (int i = 0; i < GLDL_TYPES; i++) drawlists[i].Reset();
|
||||
decals[0].Clear();
|
||||
|
@ -213,7 +215,7 @@ void FDrawInfo::StartScene()
|
|||
hudsprites.Clear();
|
||||
|
||||
// Fullbright information needs to be propagated from the main view.
|
||||
if (next != nullptr) FullbrightFlags = next->FullbrightFlags;
|
||||
if (outer != nullptr) FullbrightFlags = outer->FullbrightFlags;
|
||||
else FullbrightFlags = 0;
|
||||
|
||||
}
|
||||
|
@ -223,15 +225,15 @@ void FDrawInfo::StartScene()
|
|||
//
|
||||
//
|
||||
//==========================================================================
|
||||
void FDrawInfo::EndDrawInfo()
|
||||
FDrawInfo *FDrawInfo::EndDrawInfo()
|
||||
{
|
||||
FDrawInfo * di = gl_drawinfo;
|
||||
|
||||
for(int i=0;i<GLDL_TYPES;i++) di->drawlists[i].Reset();
|
||||
gl_drawinfo=di->next;
|
||||
di_list.Release(di);
|
||||
assert(this == gl_drawinfo);
|
||||
for(int i=0;i<GLDL_TYPES;i++) drawlists[i].Reset();
|
||||
gl_drawinfo=static_cast<FDrawInfo*>(outer);
|
||||
di_list.Release(this);
|
||||
if (gl_drawinfo == nullptr)
|
||||
ResetRenderDataAllocator();
|
||||
return gl_drawinfo;
|
||||
}
|
||||
|
||||
|
||||
|
@ -245,31 +247,30 @@ void FDrawInfo::EndDrawInfo()
|
|||
|
||||
void FDrawInfo::SetupFloodStencil(wallseg * ws)
|
||||
{
|
||||
int recursion = GLPortal::GetRecursion();
|
||||
int recursion = GLRenderer->mPortalState.GetRecursion();
|
||||
|
||||
// Create stencil
|
||||
glStencilFunc(GL_EQUAL, recursion, ~0); // create stencil
|
||||
glStencilOp(GL_KEEP, GL_KEEP, GL_INCR); // increment stencil of valid pixels
|
||||
{
|
||||
// Use revertible color mask, to avoid stomping on anaglyph 3D state
|
||||
ScopedColorMask colorMask(0, 0, 0, 0); // glColorMask(0, 0, 0, 0); // don't write to the graphics buffer
|
||||
gl_RenderState.EnableTexture(false);
|
||||
gl_RenderState.ResetColor();
|
||||
glEnable(GL_DEPTH_TEST);
|
||||
glDepthMask(true);
|
||||
glColorMask(0, 0, 0, 0); // don't write to the graphics buffer
|
||||
gl_RenderState.EnableTexture(false);
|
||||
gl_RenderState.ResetColor();
|
||||
glEnable(GL_DEPTH_TEST);
|
||||
glDepthMask(true);
|
||||
|
||||
gl_RenderState.Apply();
|
||||
FQuadDrawer qd;
|
||||
qd.Set(0, ws->x1, ws->z1, ws->y1, 0, 0);
|
||||
qd.Set(1, ws->x1, ws->z2, ws->y1, 0, 0);
|
||||
qd.Set(2, ws->x2, ws->z2, ws->y2, 0, 0);
|
||||
qd.Set(3, ws->x2, ws->z1, ws->y2, 0, 0);
|
||||
qd.Render(GL_TRIANGLE_FAN);
|
||||
gl_RenderState.Apply();
|
||||
FQuadDrawer qd;
|
||||
qd.Set(0, ws->x1, ws->z1, ws->y1, 0, 0);
|
||||
qd.Set(1, ws->x1, ws->z2, ws->y1, 0, 0);
|
||||
qd.Set(2, ws->x2, ws->z2, ws->y2, 0, 0);
|
||||
qd.Set(3, ws->x2, ws->z1, ws->y2, 0, 0);
|
||||
qd.Render(GL_TRIANGLE_FAN);
|
||||
|
||||
glStencilFunc(GL_EQUAL, recursion + 1, ~0); // draw sky into stencil
|
||||
glStencilOp(GL_KEEP, GL_KEEP, GL_KEEP); // this stage doesn't modify the stencil
|
||||
glStencilFunc(GL_EQUAL, recursion + 1, ~0); // draw sky into stencil
|
||||
glStencilOp(GL_KEEP, GL_KEEP, GL_KEEP); // this stage doesn't modify the stencil
|
||||
|
||||
} // glColorMask(1, 1, 1, 1); // don't write to the graphics buffer
|
||||
glColorMask(1, 1, 1, 1); // don't write to the graphics buffer
|
||||
gl_RenderState.EnableTexture(true);
|
||||
glDisable(GL_DEPTH_TEST);
|
||||
glDepthMask(false);
|
||||
|
@ -277,28 +278,27 @@ void FDrawInfo::SetupFloodStencil(wallseg * ws)
|
|||
|
||||
void FDrawInfo::ClearFloodStencil(wallseg * ws)
|
||||
{
|
||||
int recursion = GLPortal::GetRecursion();
|
||||
int recursion = GLRenderer->mPortalState.GetRecursion();
|
||||
|
||||
glStencilOp(GL_KEEP,GL_KEEP,GL_DECR);
|
||||
glStencilOp(GL_KEEP, GL_KEEP, GL_DECR);
|
||||
gl_RenderState.EnableTexture(false);
|
||||
{
|
||||
// Use revertible color mask, to avoid stomping on anaglyph 3D state
|
||||
ScopedColorMask colorMask(0, 0, 0, 0); // glColorMask(0,0,0,0); // don't write to the graphics buffer
|
||||
gl_RenderState.ResetColor();
|
||||
// Use revertible color mask, to avoid stomping on anaglyph 3D state
|
||||
glColorMask(0, 0, 0, 0); // don't write to the graphics buffer
|
||||
gl_RenderState.ResetColor();
|
||||
|
||||
gl_RenderState.Apply();
|
||||
FQuadDrawer qd;
|
||||
qd.Set(0, ws->x1, ws->z1, ws->y1, 0, 0);
|
||||
qd.Set(1, ws->x1, ws->z2, ws->y1, 0, 0);
|
||||
qd.Set(2, ws->x2, ws->z2, ws->y2, 0, 0);
|
||||
qd.Set(3, ws->x2, ws->z1, ws->y2, 0, 0);
|
||||
qd.Render(GL_TRIANGLE_FAN);
|
||||
gl_RenderState.Apply();
|
||||
FQuadDrawer qd;
|
||||
qd.Set(0, ws->x1, ws->z1, ws->y1, 0, 0);
|
||||
qd.Set(1, ws->x1, ws->z2, ws->y1, 0, 0);
|
||||
qd.Set(2, ws->x2, ws->z2, ws->y2, 0, 0);
|
||||
qd.Set(3, ws->x2, ws->z1, ws->y2, 0, 0);
|
||||
qd.Render(GL_TRIANGLE_FAN);
|
||||
|
||||
// restore old stencil op.
|
||||
glStencilOp(GL_KEEP, GL_KEEP, GL_KEEP);
|
||||
glStencilFunc(GL_EQUAL, recursion, ~0);
|
||||
gl_RenderState.EnableTexture(true);
|
||||
} // glColorMask(1, 1, 1, 1);
|
||||
// restore old stencil op.
|
||||
glStencilOp(GL_KEEP, GL_KEEP, GL_KEEP);
|
||||
glStencilFunc(GL_EQUAL, recursion, ~0);
|
||||
gl_RenderState.EnableTexture(true);
|
||||
glColorMask(1, 1, 1, 1);
|
||||
glEnable(GL_DEPTH_TEST);
|
||||
glDepthMask(true);
|
||||
}
|
||||
|
@ -341,9 +341,9 @@ void FDrawInfo::DrawFloodedPlane(wallseg * ws, float planez, sector_t * sec, boo
|
|||
SetFog(lightlevel, rel, &Colormap, false);
|
||||
gl_RenderState.SetMaterial(gltexture, CLAMP_NONE, 0, -1, false);
|
||||
|
||||
float fviewx = r_viewpoint.Pos.X;
|
||||
float fviewy = r_viewpoint.Pos.Y;
|
||||
float fviewz = r_viewpoint.Pos.Z;
|
||||
float fviewx = Viewpoint.Pos.X;
|
||||
float fviewy = Viewpoint.Pos.Y;
|
||||
float fviewz = Viewpoint.Pos.Z;
|
||||
|
||||
gl_RenderState.SetPlaneTextureRotation(&plane, gltexture);
|
||||
gl_RenderState.Apply();
|
||||
|
@ -394,7 +394,7 @@ void FDrawInfo::FloodUpperGap(seg_t * seg)
|
|||
double frontz = fakefsector->ceilingplane.ZatPoint(seg->v1);
|
||||
|
||||
if (fakebsector->GetTexture(sector_t::ceiling)==skyflatnum) return;
|
||||
if (backz < r_viewpoint.Pos.Z) return;
|
||||
if (backz < Viewpoint.Pos.Z) return;
|
||||
|
||||
if (seg->sidedef == seg->linedef->sidedef[0])
|
||||
{
|
||||
|
@ -447,7 +447,7 @@ void FDrawInfo::FloodLowerGap(seg_t * seg)
|
|||
|
||||
|
||||
if (fakebsector->GetTexture(sector_t::floor) == skyflatnum) return;
|
||||
if (fakebsector->GetPlaneTexZ(sector_t::floor) > r_viewpoint.Pos.Z) return;
|
||||
if (fakebsector->GetPlaneTexZ(sector_t::floor) > Viewpoint.Pos.Z) return;
|
||||
|
||||
if (seg->sidedef == seg->linedef->sidedef[0])
|
||||
{
|
||||
|
@ -478,22 +478,17 @@ void FDrawInfo::FloodLowerGap(seg_t * seg)
|
|||
ClearFloodStencil(&ws);
|
||||
}
|
||||
|
||||
// This was temporarily moved out of gl_renderhacks.cpp so that the dependency on GLWall could be eliminated until things have progressed a bit.
|
||||
void FDrawInfo::ProcessLowerMinisegs(TArray<seg_t *> &lowersegs)
|
||||
{
|
||||
for(unsigned int j=0;j<lowersegs.Size();j++)
|
||||
{
|
||||
seg_t * seg=lowersegs[j];
|
||||
GLWall wall;
|
||||
wall.ProcessLowerMiniseg(this, seg, seg->Subsector->render_sector, seg->PartnerSeg->Subsector->render_sector);
|
||||
rendered_lines++;
|
||||
}
|
||||
}
|
||||
|
||||
// Same here for the dependency on the portal.
|
||||
void FDrawInfo::AddSubsectorToPortal(FSectorPortalGroup *portal, subsector_t *sub)
|
||||
void FDrawInfo::AddSubsectorToPortal(FSectorPortalGroup *ptg, subsector_t *sub)
|
||||
{
|
||||
portal->GetRenderState()->AddSubsector(sub);
|
||||
auto portal = FindPortal(ptg);
|
||||
if (!portal)
|
||||
{
|
||||
portal = new GLScenePortal(&GLRenderer->mPortalState, new HWSectorStackPortal(ptg));
|
||||
Portals.Push(portal);
|
||||
}
|
||||
auto ptl = static_cast<HWSectorStackPortal*>(static_cast<GLScenePortal*>(portal)->mScene);
|
||||
ptl->AddSubsector(sub);
|
||||
}
|
||||
|
||||
std::pair<FFlatVertex *, unsigned int> FDrawInfo::AllocVertices(unsigned int count)
|
||||
|
@ -515,5 +510,10 @@ int FDrawInfo::UploadLights(FDynLightData &data)
|
|||
return GLRenderer->mLights->UploadLights(data);
|
||||
}
|
||||
|
||||
bool FDrawInfo::SetDepthClamp(bool on)
|
||||
{
|
||||
return gl_RenderState.SetDepthClamp(on);
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
|
|
@ -4,13 +4,12 @@
|
|||
#include "gl/renderer/gl_lightdata.h"
|
||||
#include "hwrenderer/scene/hw_drawlist.h"
|
||||
#include "hwrenderer/scene/hw_weapon.h"
|
||||
#include "hwrenderer/scene/hw_viewpointuniforms.h"
|
||||
|
||||
#ifdef _MSC_VER
|
||||
#pragma warning(disable:4244)
|
||||
#endif
|
||||
|
||||
class GLSceneDrawer;
|
||||
|
||||
enum DrawListType
|
||||
{
|
||||
GLDL_PLAINWALLS,
|
||||
|
@ -36,16 +35,12 @@ enum Drawpasses
|
|||
|
||||
struct FDrawInfo : public HWDrawInfo
|
||||
{
|
||||
GLSceneDrawer *mDrawer;
|
||||
|
||||
FDrawInfo * next;
|
||||
HWDrawList drawlists[GLDL_TYPES];
|
||||
TArray<HUDSprite> hudsprites; // These may just be stored by value.
|
||||
TArray<GLDecal *> decals[2]; // the second slot is for mirrors which get rendered in a separate pass.
|
||||
|
||||
FDrawInfo();
|
||||
~FDrawInfo();
|
||||
|
||||
void ApplyVPUniforms() override;
|
||||
|
||||
void AddWall(GLWall *wall) override;
|
||||
void AddMirrorSurface(GLWall *w) override;
|
||||
GLDecal *AddDecal(bool onmirror) override;
|
||||
|
@ -57,15 +52,6 @@ struct FDrawInfo : public HWDrawInfo
|
|||
std::pair<FFlatVertex *, unsigned int> AllocVertices(unsigned int count) override;
|
||||
int UploadLights(FDynLightData &data) override;
|
||||
|
||||
// Legacy GL only.
|
||||
bool PutWallCompat(GLWall *wall, int passflag);
|
||||
bool PutFlatCompat(GLFlat *flat, bool fog);
|
||||
void RenderFogBoundaryCompat(GLWall *wall);
|
||||
void RenderLightsCompat(GLWall *wall, int pass);
|
||||
void DrawSubsectorLights(GLFlat *flat, subsector_t * sub, int pass);
|
||||
void DrawLightsCompat(GLFlat *flat, int pass);
|
||||
|
||||
|
||||
void DrawDecal(GLDecal *gldecal);
|
||||
void DrawDecals();
|
||||
void DrawDecalsForMirror(GLWall *wall);
|
||||
|
@ -103,11 +89,19 @@ struct FDrawInfo : public HWDrawInfo
|
|||
void DrawSorted(int listindex);
|
||||
|
||||
// These two may be moved to the API independent part of the renderer later.
|
||||
void ProcessLowerMinisegs(TArray<seg_t *> &lowersegs) override;
|
||||
void AddSubsectorToPortal(FSectorPortalGroup *portal, subsector_t *sub) override;
|
||||
|
||||
void CreateScene();
|
||||
void RenderScene(int recursion);
|
||||
void RenderTranslucent();
|
||||
void DrawScene(int drawmode);
|
||||
void ProcessScene(bool toscreen = false);
|
||||
void EndDrawScene(sector_t * viewsector);
|
||||
void DrawEndScene2D(sector_t * viewsector);
|
||||
bool SetDepthClamp(bool on) override;
|
||||
|
||||
static FDrawInfo *StartDrawInfo(GLSceneDrawer *drawer);
|
||||
static void EndDrawInfo();
|
||||
static FDrawInfo *StartDrawInfo(FRenderViewpoint &parentvp, HWViewpointUniforms *uniforms);
|
||||
FDrawInfo *EndDrawInfo();
|
||||
|
||||
gl_subsectorrendernode * GetOtherFloorPlanes(unsigned int sector)
|
||||
{
|
||||
|
@ -133,16 +127,6 @@ struct FDrawInfo : public HWDrawInfo
|
|||
|
||||
};
|
||||
|
||||
class FDrawInfoList
|
||||
{
|
||||
TDeletingArray<FDrawInfo *> mList;
|
||||
|
||||
public:
|
||||
|
||||
FDrawInfo *GetNew();
|
||||
void Release(FDrawInfo *);
|
||||
};
|
||||
|
||||
|
||||
void gl_SetRenderStyle(FRenderStyle style, bool drawopaque, bool allowcolorblending);
|
||||
|
||||
|
|
|
@ -45,7 +45,6 @@
|
|||
#include "gl/data/gl_vertexbuffer.h"
|
||||
#include "gl/dynlights/gl_lightbuffer.h"
|
||||
#include "gl/scene/gl_drawinfo.h"
|
||||
#include "gl/scene/gl_scenedrawer.h"
|
||||
#include "gl/renderer/gl_quaddrawer.h"
|
||||
|
||||
//==========================================================================
|
||||
|
@ -167,7 +166,7 @@ void FDrawInfo::ProcessLights(GLFlat *flat, bool istrans)
|
|||
{
|
||||
flat->dynlightindex = GLRenderer->mLights->GetIndexPtr();
|
||||
|
||||
if (flat->sector->ibocount > 0 && !gl_RenderState.GetClipLineShouldBeActive())
|
||||
if (flat->sector->ibocount > 0 && !ClipLineShouldBeActive())
|
||||
{
|
||||
SetupSectorLights(flat, GLPASS_LIGHTSONLY, nullptr);
|
||||
}
|
||||
|
@ -216,7 +215,7 @@ void FDrawInfo::DrawSubsectors(GLFlat *flat, int pass, bool processlights, bool
|
|||
|
||||
if (iboindex >= 0)
|
||||
{
|
||||
if (vcount > 0 && !gl_RenderState.GetClipLineShouldBeActive())
|
||||
if (vcount > 0 && !ClipLineShouldBeActive())
|
||||
{
|
||||
if (processlights) SetupSectorLights(flat, GLPASS_ALL, &dli);
|
||||
drawcalls.Clock();
|
||||
|
|
File diff suppressed because it is too large
Load diff
|
@ -37,218 +37,59 @@
|
|||
#define __GL_PORTAL_H
|
||||
|
||||
#include "tarray.h"
|
||||
#include "r_utility.h"
|
||||
#include "actor.h"
|
||||
#include "gl/renderer/gl_renderer.h"
|
||||
#include "gl/scene/gl_drawinfo.h"
|
||||
#include "hwrenderer/scene/hw_drawstructs.h"
|
||||
#include "hwrenderer/scene/hw_portal.h"
|
||||
|
||||
extern UniqueList<GLSkyInfo> UniqueSkies;
|
||||
extern UniqueList<GLHorizonInfo> UniqueHorizons;
|
||||
extern UniqueList<secplane_t> UniquePlaneMirrors;
|
||||
struct GLEEHorizonPortal;
|
||||
class GLSceneDrawer;
|
||||
|
||||
class GLPortal : public IPortal
|
||||
{
|
||||
static TArray<GLPortal *> portals;
|
||||
static int recursion;
|
||||
static unsigned int QueryObject;
|
||||
protected:
|
||||
static TArray<float> planestack;
|
||||
static int MirrorFlag;
|
||||
static int PlaneMirrorFlag;
|
||||
static int renderdepth;
|
||||
|
||||
public:
|
||||
static GLSceneDrawer *drawer;
|
||||
static int PlaneMirrorMode;
|
||||
static int inupperstack;
|
||||
static bool inskybox;
|
||||
|
||||
private:
|
||||
void DrawPortalStencil();
|
||||
|
||||
DVector3 savedviewpath[2];
|
||||
DVector3 savedViewPos;
|
||||
DVector3 savedViewActorPos;
|
||||
DRotator savedAngles;
|
||||
bool savedshowviewer;
|
||||
AActor * savedviewactor;
|
||||
ActorRenderFlags savedvisibility;
|
||||
GLPortal *PrevPortal;
|
||||
TArray<unsigned int> mPrimIndices;
|
||||
|
||||
protected:
|
||||
TArray<GLWall> lines;
|
||||
int level;
|
||||
|
||||
GLPortal(bool local = false) { if (!local) portals.Push(this); }
|
||||
virtual ~GLPortal() { }
|
||||
GLPortal(FPortalSceneState *state, bool local = false) : IPortal(state, local) { }
|
||||
|
||||
bool Start(bool usestencil, bool doquery, FDrawInfo *outer_di, FDrawInfo **pDi);
|
||||
void End(bool usestencil);
|
||||
virtual void DrawContents(FDrawInfo *di)=0;
|
||||
virtual void * GetSource() const =0; // GetSource MUST be implemented!
|
||||
void ClearClipper(FDrawInfo *di);
|
||||
bool Start(bool usestencil, bool doquery, HWDrawInfo *outer_di, HWDrawInfo **pDi) override;
|
||||
void End(HWDrawInfo *di, bool usestencil) override;
|
||||
void ClearScreen(HWDrawInfo *di);
|
||||
};
|
||||
|
||||
class GLScenePortal : public GLPortal
|
||||
{
|
||||
public:
|
||||
HWScenePortalBase *mScene;
|
||||
GLScenePortal(FPortalSceneState *state, HWScenePortalBase *handler) : GLPortal(state)
|
||||
{
|
||||
mScene = handler;
|
||||
handler->SetOwner(this);
|
||||
}
|
||||
~GLScenePortal() { delete mScene; }
|
||||
virtual void * GetSource() const { return mScene->GetSource(); }
|
||||
virtual const char *GetName() { return mScene->GetName(); }
|
||||
virtual bool IsSky() { return false; }
|
||||
virtual bool NeedCap() { return true; }
|
||||
virtual bool NeedDepthBuffer() { return true; }
|
||||
void ClearScreen();
|
||||
virtual const char *GetName() = 0;
|
||||
virtual void PushState() {}
|
||||
virtual void PopState() {}
|
||||
|
||||
public:
|
||||
|
||||
void RenderPortal(bool usestencil, bool doquery, FDrawInfo *outer_di)
|
||||
{
|
||||
// Start may perform an occlusion query. If that returns 0 there
|
||||
// is no need to draw the stencil's contents and there's also no
|
||||
// need to restore the affected area becasue there is none!
|
||||
FDrawInfo *di;
|
||||
if (Start(usestencil, doquery, outer_di, &di))
|
||||
virtual void DrawContents(HWDrawInfo *di)
|
||||
{
|
||||
if (mScene->Setup(di, di->mClipper))
|
||||
{
|
||||
DrawContents(di);
|
||||
End(usestencil);
|
||||
static_cast<FDrawInfo*>(di)->DrawScene(DM_PORTAL);
|
||||
mScene->Shutdown(di);
|
||||
}
|
||||
else ClearScreen(di);
|
||||
}
|
||||
|
||||
void AddLine(GLWall * l)
|
||||
{
|
||||
lines.Push(*l);
|
||||
}
|
||||
|
||||
static int GetRecursion()
|
||||
{
|
||||
return recursion;
|
||||
}
|
||||
|
||||
static bool isMirrored() { return !!((MirrorFlag ^ PlaneMirrorFlag) & 1); }
|
||||
|
||||
virtual void RenderAttached(FDrawInfo *di) {}
|
||||
|
||||
static void BeginScene();
|
||||
static void StartFrame();
|
||||
static bool RenderFirstSkyPortal(int recursion, FDrawInfo *outer_di);
|
||||
static void EndFrame(FDrawInfo *outer_di);
|
||||
static GLPortal * FindPortal(const void * src);
|
||||
|
||||
static void Initialize();
|
||||
static void Shutdown();
|
||||
};
|
||||
|
||||
struct GLLinePortal : public GLPortal
|
||||
{
|
||||
// this must be the same as at the start of line_t, so that we can pass in this structure directly to P_ClipLineToPortal.
|
||||
vertex_t *v1, *v2; // vertices, from v1 to v2
|
||||
DVector2 delta; // precalculated v2 - v1 for side checking
|
||||
|
||||
angle_t angv1, angv2; // for quick comparisons with a line or subsector
|
||||
|
||||
GLLinePortal(line_t *line)
|
||||
{
|
||||
v1 = line->v1;
|
||||
v2 = line->v2;
|
||||
CalcDelta();
|
||||
}
|
||||
|
||||
GLLinePortal(FLinePortalSpan *line)
|
||||
{
|
||||
if (line->lines[0]->mType != PORTT_LINKED || line->v1 == nullptr)
|
||||
{
|
||||
// For non-linked portals we must check the actual linedef.
|
||||
line_t *lline = line->lines[0]->mDestination;
|
||||
v1 = lline->v1;
|
||||
v2 = lline->v2;
|
||||
}
|
||||
else
|
||||
{
|
||||
// For linked portals we can check the merged span.
|
||||
v1 = line->v1;
|
||||
v2 = line->v2;
|
||||
}
|
||||
CalcDelta();
|
||||
}
|
||||
|
||||
void CalcDelta()
|
||||
{
|
||||
delta = v2->fPos() - v1->fPos();
|
||||
}
|
||||
|
||||
line_t *line()
|
||||
{
|
||||
vertex_t **pv = &v1;
|
||||
return reinterpret_cast<line_t*>(pv);
|
||||
}
|
||||
|
||||
virtual int ClipSeg(seg_t *seg);
|
||||
virtual int ClipSubsector(subsector_t *sub);
|
||||
virtual int ClipPoint(const DVector2 &pos);
|
||||
virtual bool NeedCap() { return false; }
|
||||
virtual void PushState();
|
||||
virtual void PopState();
|
||||
};
|
||||
|
||||
|
||||
struct GLMirrorPortal : public GLLinePortal
|
||||
{
|
||||
// mirror portals always consist of single linedefs!
|
||||
line_t * linedef;
|
||||
|
||||
protected:
|
||||
virtual void DrawContents(FDrawInfo *di);
|
||||
virtual void * GetSource() const { return linedef; }
|
||||
virtual const char *GetName();
|
||||
|
||||
public:
|
||||
|
||||
GLMirrorPortal(line_t * line)
|
||||
: GLLinePortal(line)
|
||||
{
|
||||
linedef=line;
|
||||
}
|
||||
};
|
||||
|
||||
|
||||
struct GLLineToLinePortal : public GLLinePortal
|
||||
{
|
||||
FLinePortalSpan *glport;
|
||||
protected:
|
||||
virtual void DrawContents(FDrawInfo *di);
|
||||
virtual void * GetSource() const { return glport; }
|
||||
virtual const char *GetName();
|
||||
virtual line_t *ClipLine() { return line(); }
|
||||
virtual void RenderAttached(FDrawInfo *di);
|
||||
|
||||
public:
|
||||
|
||||
GLLineToLinePortal(FLinePortalSpan *ll)
|
||||
: GLLinePortal(ll)
|
||||
{
|
||||
glport = ll;
|
||||
}
|
||||
};
|
||||
|
||||
|
||||
struct GLSkyboxPortal : public GLPortal
|
||||
{
|
||||
FSectorPortal * portal;
|
||||
|
||||
protected:
|
||||
virtual void DrawContents(FDrawInfo *di);
|
||||
virtual void * GetSource() const { return portal; }
|
||||
virtual bool IsSky() { return true; }
|
||||
virtual const char *GetName();
|
||||
|
||||
public:
|
||||
|
||||
|
||||
GLSkyboxPortal(FSectorPortal * pt)
|
||||
{
|
||||
portal=pt;
|
||||
}
|
||||
|
||||
virtual void RenderAttached(HWDrawInfo *di) { return mScene->RenderAttached(di); }
|
||||
};
|
||||
|
||||
|
||||
|
@ -258,7 +99,7 @@ struct GLSkyPortal : public GLPortal
|
|||
friend struct GLEEHorizonPortal;
|
||||
|
||||
protected:
|
||||
virtual void DrawContents(FDrawInfo *di);
|
||||
virtual void DrawContents(HWDrawInfo *di);
|
||||
virtual void * GetSource() const { return origin; }
|
||||
virtual bool IsSky() { return true; }
|
||||
virtual bool NeedDepthBuffer() { return false; }
|
||||
|
@ -267,61 +108,14 @@ protected:
|
|||
public:
|
||||
|
||||
|
||||
GLSkyPortal(GLSkyInfo * pt, bool local = false)
|
||||
: GLPortal(local)
|
||||
GLSkyPortal(FPortalSceneState *state, GLSkyInfo * pt, bool local = false)
|
||||
: GLPortal(state, local)
|
||||
{
|
||||
origin=pt;
|
||||
}
|
||||
|
||||
};
|
||||
|
||||
|
||||
|
||||
struct GLSectorStackPortal : public GLPortal
|
||||
{
|
||||
TArray<subsector_t *> subsectors;
|
||||
protected:
|
||||
virtual ~GLSectorStackPortal();
|
||||
virtual void DrawContents(FDrawInfo *di);
|
||||
virtual void * GetSource() const { return origin; }
|
||||
virtual bool IsSky() { return true; } // although this isn't a real sky it can be handled as one.
|
||||
virtual const char *GetName();
|
||||
FSectorPortalGroup *origin;
|
||||
|
||||
public:
|
||||
|
||||
GLSectorStackPortal(FSectorPortalGroup *pt)
|
||||
{
|
||||
origin=pt;
|
||||
}
|
||||
void SetupCoverage(FDrawInfo *di);
|
||||
void AddSubsector(subsector_t *sub)
|
||||
{
|
||||
subsectors.Push(sub);
|
||||
}
|
||||
|
||||
};
|
||||
|
||||
struct GLPlaneMirrorPortal : public GLPortal
|
||||
{
|
||||
protected:
|
||||
virtual void DrawContents(FDrawInfo *di);
|
||||
virtual void * GetSource() const { return origin; }
|
||||
virtual const char *GetName();
|
||||
virtual void PushState();
|
||||
virtual void PopState();
|
||||
secplane_t * origin;
|
||||
|
||||
public:
|
||||
|
||||
GLPlaneMirrorPortal(secplane_t * pt)
|
||||
{
|
||||
origin=pt;
|
||||
}
|
||||
|
||||
};
|
||||
|
||||
|
||||
struct GLHorizonPortal : public GLPortal
|
||||
{
|
||||
GLHorizonInfo * origin;
|
||||
|
@ -330,7 +124,7 @@ struct GLHorizonPortal : public GLPortal
|
|||
friend struct GLEEHorizonPortal;
|
||||
|
||||
protected:
|
||||
virtual void DrawContents(FDrawInfo *di);
|
||||
virtual void DrawContents(HWDrawInfo *di);
|
||||
virtual void * GetSource() const { return origin; }
|
||||
virtual bool NeedDepthBuffer() { return false; }
|
||||
virtual bool NeedCap() { return false; }
|
||||
|
@ -338,7 +132,7 @@ protected:
|
|||
|
||||
public:
|
||||
|
||||
GLHorizonPortal(GLHorizonInfo * pt, bool local = false);
|
||||
GLHorizonPortal(FPortalSceneState *state, GLHorizonInfo * pt, FRenderViewpoint &vp, bool local = false);
|
||||
};
|
||||
|
||||
struct GLEEHorizonPortal : public GLPortal
|
||||
|
@ -346,7 +140,7 @@ struct GLEEHorizonPortal : public GLPortal
|
|||
FSectorPortal * portal;
|
||||
|
||||
protected:
|
||||
virtual void DrawContents(FDrawInfo *di);
|
||||
virtual void DrawContents(HWDrawInfo *di);
|
||||
virtual void * GetSource() const { return portal; }
|
||||
virtual bool NeedDepthBuffer() { return false; }
|
||||
virtual bool NeedCap() { return false; }
|
||||
|
@ -354,7 +148,7 @@ protected:
|
|||
|
||||
public:
|
||||
|
||||
GLEEHorizonPortal(FSectorPortal *pt)
|
||||
GLEEHorizonPortal(FPortalSceneState *state, FSectorPortal *pt) : GLPortal(state)
|
||||
{
|
||||
portal=pt;
|
||||
}
|
||||
|
|
|
@ -50,11 +50,10 @@
|
|||
#include "gl/renderer/gl_renderbuffers.h"
|
||||
#include "gl/data/gl_vertexbuffer.h"
|
||||
#include "hwrenderer/scene/hw_clipper.h"
|
||||
#include "hwrenderer/scene/hw_portal.h"
|
||||
#include "gl/scene/gl_drawinfo.h"
|
||||
#include "gl/scene/gl_portal.h"
|
||||
#include "gl/scene/gl_scenedrawer.h"
|
||||
#include "gl/stereo3d/gl_stereo3d.h"
|
||||
#include "hwrenderer/utility/scoped_view_shifter.h"
|
||||
#include "hwrenderer/utility/hw_vrmodes.h"
|
||||
|
||||
//==========================================================================
|
||||
//
|
||||
|
@ -72,136 +71,25 @@ EXTERN_CVAR (Bool, r_deathcamera)
|
|||
EXTERN_CVAR (Float, r_visibility)
|
||||
EXTERN_CVAR (Bool, r_drawvoxels)
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
//
|
||||
// R_FrustumAngle
|
||||
//
|
||||
//-----------------------------------------------------------------------------
|
||||
angle_t GLSceneDrawer::FrustumAngle()
|
||||
|
||||
void FDrawInfo::ApplyVPUniforms()
|
||||
{
|
||||
float tilt = fabs(GLRenderer->mAngles.Pitch.Degrees);
|
||||
VPUniforms.CalcDependencies();
|
||||
GLRenderer->mShaderManager->ApplyMatrices(&VPUniforms, NORMAL_PASS);
|
||||
|
||||
// If the pitch is larger than this you can look all around at a FOV of 90°
|
||||
if (tilt > 46.0f) return 0xffffffff;
|
||||
|
||||
// ok, this is a gross hack that barely works...
|
||||
// but at least it doesn't overestimate too much...
|
||||
double floatangle = 2.0 + (45.0 + ((tilt / 1.9)))*GLRenderer->mCurrentFoV*48.0 / AspectMultiplier(r_viewwindow.WidescreenRatio) / 90.0;
|
||||
angle_t a1 = DAngle(floatangle).BAMs();
|
||||
if (a1 >= ANGLE_180) return 0xffffffff;
|
||||
return a1;
|
||||
}
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
//
|
||||
// resets the 3D viewport
|
||||
//
|
||||
//-----------------------------------------------------------------------------
|
||||
|
||||
void GLSceneDrawer::Reset3DViewport()
|
||||
{
|
||||
glViewport(screen->mScreenViewport.left, screen->mScreenViewport.top, screen->mScreenViewport.width, screen->mScreenViewport.height);
|
||||
}
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
//
|
||||
// sets 3D viewport and initial state
|
||||
//
|
||||
//-----------------------------------------------------------------------------
|
||||
|
||||
void GLSceneDrawer::Set3DViewport(bool mainview)
|
||||
{
|
||||
if (mainview && GLRenderer->buffersActive)
|
||||
if (!(gl.flags & RFL_NO_CLIP_PLANES))
|
||||
{
|
||||
bool useSSAO = (gl_ssao != 0);
|
||||
GLRenderer->mBuffers->BindSceneFB(useSSAO);
|
||||
gl_RenderState.SetPassType(useSSAO ? GBUFFER_PASS : NORMAL_PASS);
|
||||
gl_RenderState.EnableDrawBuffers(gl_RenderState.GetPassDrawBufferCount());
|
||||
gl_RenderState.Apply();
|
||||
if (VPUniforms.mClipHeightDirection != 0.f || VPUniforms.mClipLine.X > -10000000.0f)
|
||||
{
|
||||
glEnable(GL_CLIP_DISTANCE0);
|
||||
}
|
||||
else
|
||||
{
|
||||
glDisable(GL_CLIP_DISTANCE0);
|
||||
}
|
||||
}
|
||||
|
||||
// Always clear all buffers with scissor test disabled.
|
||||
// This is faster on newer hardware because it allows the GPU to skip
|
||||
// reading from slower memory where the full buffers are stored.
|
||||
glDisable(GL_SCISSOR_TEST);
|
||||
glClearColor(GLRenderer->mSceneClearColor[0], GLRenderer->mSceneClearColor[1], GLRenderer->mSceneClearColor[2], 1.0f);
|
||||
glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT | GL_STENCIL_BUFFER_BIT);
|
||||
|
||||
const auto &bounds = screen->mSceneViewport;
|
||||
glViewport(bounds.left, bounds.top, bounds.width, bounds.height);
|
||||
glScissor(bounds.left, bounds.top, bounds.width, bounds.height);
|
||||
|
||||
glEnable(GL_SCISSOR_TEST);
|
||||
|
||||
glEnable(GL_MULTISAMPLE);
|
||||
glEnable(GL_DEPTH_TEST);
|
||||
glEnable(GL_STENCIL_TEST);
|
||||
glStencilFunc(GL_ALWAYS,0,~0); // default stencil
|
||||
glStencilOp(GL_KEEP,GL_KEEP,GL_REPLACE);
|
||||
}
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
//
|
||||
// Setup the camera position
|
||||
//
|
||||
//-----------------------------------------------------------------------------
|
||||
|
||||
void GLSceneDrawer::SetViewAngle(DAngle viewangle)
|
||||
{
|
||||
GLRenderer->mAngles.Yaw = float(270.0-viewangle.Degrees);
|
||||
DVector2 v = r_viewpoint.Angles.Yaw.ToVector();
|
||||
GLRenderer->mViewVector.X = v.X;
|
||||
GLRenderer->mViewVector.Y = v.Y;
|
||||
|
||||
R_SetViewAngle(r_viewpoint, r_viewwindow);
|
||||
}
|
||||
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
//
|
||||
// SetProjection
|
||||
// sets projection matrix
|
||||
//
|
||||
//-----------------------------------------------------------------------------
|
||||
|
||||
void GLSceneDrawer::SetProjection(VSMatrix matrix)
|
||||
{
|
||||
gl_RenderState.mProjectionMatrix.loadIdentity();
|
||||
gl_RenderState.mProjectionMatrix.multMatrix(matrix);
|
||||
}
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
//
|
||||
// Setup the modelview matrix
|
||||
//
|
||||
//-----------------------------------------------------------------------------
|
||||
|
||||
void GLSceneDrawer::SetViewMatrix(float vx, float vy, float vz, bool mirror, bool planemirror)
|
||||
{
|
||||
float mult = mirror? -1:1;
|
||||
float planemult = planemirror? -level.info->pixelstretch : level.info->pixelstretch;
|
||||
|
||||
gl_RenderState.mViewMatrix.loadIdentity();
|
||||
gl_RenderState.mViewMatrix.rotate(GLRenderer->mAngles.Roll.Degrees, 0.0f, 0.0f, 1.0f);
|
||||
gl_RenderState.mViewMatrix.rotate(GLRenderer->mAngles.Pitch.Degrees, 1.0f, 0.0f, 0.0f);
|
||||
gl_RenderState.mViewMatrix.rotate(GLRenderer->mAngles.Yaw.Degrees, 0.0f, mult, 0.0f);
|
||||
gl_RenderState.mViewMatrix.translate(vx * mult, -vz * planemult , -vy);
|
||||
gl_RenderState.mViewMatrix.scale(-mult, planemult, 1);
|
||||
}
|
||||
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
//
|
||||
// SetupView
|
||||
// Setup the view rotation matrix for the given viewpoint
|
||||
//
|
||||
//-----------------------------------------------------------------------------
|
||||
void GLSceneDrawer::SetupView(float vx, float vy, float vz, DAngle va, bool mirror, bool planemirror)
|
||||
{
|
||||
SetViewAngle(va);
|
||||
SetViewMatrix(vx, vy, vz, mirror, planemirror);
|
||||
gl_RenderState.ApplyMatrices();
|
||||
}
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
//
|
||||
|
@ -211,48 +99,45 @@ void GLSceneDrawer::SetupView(float vx, float vy, float vz, DAngle va, bool mirr
|
|||
//
|
||||
//-----------------------------------------------------------------------------
|
||||
|
||||
void GLSceneDrawer::CreateScene(FDrawInfo *di)
|
||||
void FDrawInfo::CreateScene()
|
||||
{
|
||||
const auto &vp = Viewpoint;
|
||||
angle_t a1 = FrustumAngle();
|
||||
di->mClipper->SafeAddClipRangeRealAngles(r_viewpoint.Angles.Yaw.BAMs() + a1, r_viewpoint.Angles.Yaw.BAMs() - a1);
|
||||
mClipper->SafeAddClipRangeRealAngles(vp.Angles.Yaw.BAMs() + a1, vp.Angles.Yaw.BAMs() - a1);
|
||||
|
||||
// reset the portal manager
|
||||
GLPortal::StartFrame();
|
||||
GLRenderer->mPortalState.StartFrame();
|
||||
PO_LinkToSubsectors();
|
||||
|
||||
ProcessAll.Clock();
|
||||
|
||||
// clip the scene and fill the drawlists
|
||||
for(auto p : level.portalGroups) p->glportal = nullptr;
|
||||
Bsp.Clock();
|
||||
GLRenderer->mVBO->Map();
|
||||
GLRenderer->mLights->Begin();
|
||||
|
||||
// Give the DrawInfo the viewpoint in fixed point because that's what the nodes are.
|
||||
di->viewx = FLOAT2FIXED(r_viewpoint.Pos.X);
|
||||
di->viewy = FLOAT2FIXED(r_viewpoint.Pos.Y);
|
||||
viewx = FLOAT2FIXED(vp.Pos.X);
|
||||
viewy = FLOAT2FIXED(vp.Pos.Y);
|
||||
|
||||
validcount++; // used for processing sidedefs only once by the renderer.
|
||||
|
||||
di->mAngles = GLRenderer->mAngles;
|
||||
di->mViewVector = GLRenderer->mViewVector;
|
||||
di->mViewActor = GLRenderer->mViewActor;
|
||||
di->mShadowMap = &GLRenderer->mShadowMap;
|
||||
mShadowMap = &GLRenderer->mShadowMap;
|
||||
|
||||
di->RenderBSPNode (level.HeadNode());
|
||||
di->PreparePlayerSprites(r_viewpoint.sector, di->in_area);
|
||||
RenderBSPNode (level.HeadNode());
|
||||
PreparePlayerSprites(vp.sector, in_area);
|
||||
|
||||
// Process all the sprites on the current portal's back side which touch the portal.
|
||||
if (GLRenderer->mCurrentPortal != NULL) GLRenderer->mCurrentPortal->RenderAttached(di);
|
||||
if (mCurrentPortal != nullptr) mCurrentPortal->RenderAttached(this);
|
||||
Bsp.Unclock();
|
||||
|
||||
// And now the crappy hacks that have to be done to avoid rendering anomalies.
|
||||
// These cannot be multithreaded when the time comes because all these depend
|
||||
// on the global 'validcount' variable.
|
||||
|
||||
di->HandleMissingTextures(di->in_area); // Missing upper/lower textures
|
||||
di->HandleHackedSubsectors(); // open sector hacks for deep water
|
||||
di->ProcessSectorStacks(di->in_area); // merge visplanes of sector stacks
|
||||
HandleMissingTextures(in_area); // Missing upper/lower textures
|
||||
HandleHackedSubsectors(); // open sector hacks for deep water
|
||||
ProcessSectorStacks(in_area); // merge visplanes of sector stacks
|
||||
GLRenderer->mLights->Finish();
|
||||
GLRenderer->mVBO->Unmap();
|
||||
|
||||
|
@ -268,36 +153,35 @@ void GLSceneDrawer::CreateScene(FDrawInfo *di)
|
|||
//
|
||||
//-----------------------------------------------------------------------------
|
||||
|
||||
void GLSceneDrawer::RenderScene(FDrawInfo *di, int recursion)
|
||||
void FDrawInfo::RenderScene(int recursion)
|
||||
{
|
||||
const auto &vp = Viewpoint;
|
||||
RenderAll.Clock();
|
||||
|
||||
glDepthMask(true);
|
||||
if (!gl_no_skyclear) GLPortal::RenderFirstSkyPortal(recursion, di);
|
||||
|
||||
gl_RenderState.SetCameraPos(r_viewpoint.Pos.X, r_viewpoint.Pos.Y, r_viewpoint.Pos.Z);
|
||||
if (!gl_no_skyclear) GLRenderer->mPortalState.RenderFirstSkyPortal(recursion, this);
|
||||
|
||||
gl_RenderState.EnableFog(true);
|
||||
gl_RenderState.BlendFunc(GL_ONE,GL_ZERO);
|
||||
|
||||
if (gl_sort_textures)
|
||||
{
|
||||
di->drawlists[GLDL_PLAINWALLS].SortWalls();
|
||||
di->drawlists[GLDL_PLAINFLATS].SortFlats();
|
||||
di->drawlists[GLDL_MASKEDWALLS].SortWalls();
|
||||
di->drawlists[GLDL_MASKEDFLATS].SortFlats();
|
||||
di->drawlists[GLDL_MASKEDWALLSOFS].SortWalls();
|
||||
drawlists[GLDL_PLAINWALLS].SortWalls();
|
||||
drawlists[GLDL_PLAINFLATS].SortFlats();
|
||||
drawlists[GLDL_MASKEDWALLS].SortWalls();
|
||||
drawlists[GLDL_MASKEDFLATS].SortFlats();
|
||||
drawlists[GLDL_MASKEDWALLSOFS].SortWalls();
|
||||
}
|
||||
|
||||
// if we don't have a persistently mapped buffer, we have to process all the dynamic lights up front,
|
||||
// so that we don't have to do repeated map/unmap calls on the buffer.
|
||||
if (gl.lightmethod == LM_DEFERRED && level.HasDynamicLights && !di->isFullbrightScene())
|
||||
if (gl.lightmethod == LM_DEFERRED && level.HasDynamicLights && !isFullbrightScene())
|
||||
{
|
||||
GLRenderer->mLights->Begin();
|
||||
di->drawlists[GLDL_PLAINFLATS].DrawFlats(di, GLPASS_LIGHTSONLY);
|
||||
di->drawlists[GLDL_MASKEDFLATS].DrawFlats(di, GLPASS_LIGHTSONLY);
|
||||
di->drawlists[GLDL_TRANSLUCENTBORDER].Draw(di, GLPASS_LIGHTSONLY);
|
||||
di->drawlists[GLDL_TRANSLUCENT].Draw(di, GLPASS_LIGHTSONLY, true);
|
||||
drawlists[GLDL_PLAINFLATS].DrawFlats(this, GLPASS_LIGHTSONLY);
|
||||
drawlists[GLDL_MASKEDFLATS].DrawFlats(this, GLPASS_LIGHTSONLY);
|
||||
drawlists[GLDL_TRANSLUCENTBORDER].Draw(this, GLPASS_LIGHTSONLY);
|
||||
drawlists[GLDL_TRANSLUCENT].Draw(this, GLPASS_LIGHTSONLY, true);
|
||||
GLRenderer->mLights->Finish();
|
||||
}
|
||||
|
||||
|
@ -310,8 +194,8 @@ void GLSceneDrawer::RenderScene(FDrawInfo *di, int recursion)
|
|||
|
||||
gl_RenderState.EnableTexture(gl_texture);
|
||||
gl_RenderState.EnableBrightmap(true);
|
||||
di->drawlists[GLDL_PLAINWALLS].DrawWalls(di, pass);
|
||||
di->drawlists[GLDL_PLAINFLATS].DrawFlats(di, pass);
|
||||
drawlists[GLDL_PLAINWALLS].DrawWalls(this, pass);
|
||||
drawlists[GLDL_PLAINFLATS].DrawFlats(this, pass);
|
||||
|
||||
|
||||
// Part 2: masked geometry. This is set up so that only pixels with alpha>gl_mask_threshold will show
|
||||
|
@ -321,20 +205,20 @@ void GLSceneDrawer::RenderScene(FDrawInfo *di, int recursion)
|
|||
gl_RenderState.SetTextureMode(TM_MASK);
|
||||
}
|
||||
gl_RenderState.AlphaFunc(GL_GEQUAL, gl_mask_threshold);
|
||||
di->drawlists[GLDL_MASKEDWALLS].DrawWalls(di, pass);
|
||||
di->drawlists[GLDL_MASKEDFLATS].DrawFlats(di, pass);
|
||||
drawlists[GLDL_MASKEDWALLS].DrawWalls(this, pass);
|
||||
drawlists[GLDL_MASKEDFLATS].DrawFlats(this, pass);
|
||||
|
||||
// Part 3: masked geometry with polygon offset. This list is empty most of the time so only waste time on it when in use.
|
||||
if (di->drawlists[GLDL_MASKEDWALLSOFS].Size() > 0)
|
||||
if (drawlists[GLDL_MASKEDWALLSOFS].Size() > 0)
|
||||
{
|
||||
glEnable(GL_POLYGON_OFFSET_FILL);
|
||||
glPolygonOffset(-1.0f, -128.0f);
|
||||
di->drawlists[GLDL_MASKEDWALLSOFS].DrawWalls(di, pass);
|
||||
drawlists[GLDL_MASKEDWALLSOFS].DrawWalls(this, pass);
|
||||
glDisable(GL_POLYGON_OFFSET_FILL);
|
||||
glPolygonOffset(0, 0);
|
||||
}
|
||||
|
||||
di->drawlists[GLDL_MODELS].Draw(di, pass);
|
||||
drawlists[GLDL_MODELS].Draw(this, pass);
|
||||
|
||||
gl_RenderState.BlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
|
||||
|
||||
|
@ -343,7 +227,7 @@ void GLSceneDrawer::RenderScene(FDrawInfo *di, int recursion)
|
|||
glEnable(GL_POLYGON_OFFSET_FILL);
|
||||
glPolygonOffset(-1.0f, -128.0f);
|
||||
glDepthMask(false);
|
||||
di->DrawDecals();
|
||||
DrawDecals();
|
||||
|
||||
gl_RenderState.SetTextureMode(TM_MODULATE);
|
||||
|
||||
|
@ -361,7 +245,7 @@ void GLSceneDrawer::RenderScene(FDrawInfo *di, int recursion)
|
|||
gl_RenderState.EnableFog(true);
|
||||
gl_RenderState.AlphaFunc(GL_GEQUAL, 0.f);
|
||||
gl_RenderState.BlendFunc(GL_ONE,GL_ZERO);
|
||||
di->DrawUnhandledMissingTextures();
|
||||
DrawUnhandledMissingTextures();
|
||||
glDepthMask(true);
|
||||
|
||||
glPolygonOffset(0.0f, 0.0f);
|
||||
|
@ -378,20 +262,18 @@ void GLSceneDrawer::RenderScene(FDrawInfo *di, int recursion)
|
|||
//
|
||||
//-----------------------------------------------------------------------------
|
||||
|
||||
void GLSceneDrawer::RenderTranslucent(FDrawInfo *di)
|
||||
void FDrawInfo::RenderTranslucent()
|
||||
{
|
||||
RenderAll.Clock();
|
||||
|
||||
gl_RenderState.SetCameraPos(r_viewpoint.Pos.X, r_viewpoint.Pos.Y, r_viewpoint.Pos.Z);
|
||||
|
||||
// final pass: translucent stuff
|
||||
gl_RenderState.AlphaFunc(GL_GEQUAL, gl_mask_sprite_threshold);
|
||||
gl_RenderState.BlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
|
||||
|
||||
gl_RenderState.EnableBrightmap(true);
|
||||
di->drawlists[GLDL_TRANSLUCENTBORDER].Draw(di, GLPASS_TRANSLUCENT);
|
||||
drawlists[GLDL_TRANSLUCENTBORDER].Draw(this, GLPASS_TRANSLUCENT);
|
||||
glDepthMask(false);
|
||||
di->DrawSorted(GLDL_TRANSLUCENT);
|
||||
DrawSorted(GLDL_TRANSLUCENT);
|
||||
gl_RenderState.EnableBrightmap(false);
|
||||
|
||||
|
||||
|
@ -411,10 +293,11 @@ void GLSceneDrawer::RenderTranslucent(FDrawInfo *di)
|
|||
//
|
||||
//-----------------------------------------------------------------------------
|
||||
|
||||
void GLSceneDrawer::DrawScene(FDrawInfo *di, int drawmode)
|
||||
void FDrawInfo::DrawScene(int drawmode)
|
||||
{
|
||||
static int recursion=0;
|
||||
static int ssao_portals_available = 0;
|
||||
const auto &vp = Viewpoint;
|
||||
|
||||
bool applySSAO = false;
|
||||
if (drawmode == DM_MAINVIEW)
|
||||
|
@ -432,35 +315,35 @@ void GLSceneDrawer::DrawScene(FDrawInfo *di, int drawmode)
|
|||
ssao_portals_available--;
|
||||
}
|
||||
|
||||
if (r_viewpoint.camera != nullptr)
|
||||
if (vp.camera != nullptr)
|
||||
{
|
||||
ActorRenderFlags savedflags = r_viewpoint.camera->renderflags;
|
||||
CreateScene(di);
|
||||
r_viewpoint.camera->renderflags = savedflags;
|
||||
ActorRenderFlags savedflags = vp.camera->renderflags;
|
||||
CreateScene();
|
||||
vp.camera->renderflags = savedflags;
|
||||
}
|
||||
else
|
||||
{
|
||||
CreateScene(di);
|
||||
CreateScene();
|
||||
}
|
||||
|
||||
RenderScene(di, recursion);
|
||||
RenderScene(recursion);
|
||||
|
||||
if (applySSAO && gl_RenderState.GetPassType() == GBUFFER_PASS)
|
||||
{
|
||||
gl_RenderState.EnableDrawBuffers(1);
|
||||
GLRenderer->AmbientOccludeScene();
|
||||
GLRenderer->AmbientOccludeScene(VPUniforms.mProjectionMatrix.get()[5]);
|
||||
GLRenderer->mBuffers->BindSceneFB(true);
|
||||
gl_RenderState.EnableDrawBuffers(gl_RenderState.GetPassDrawBufferCount());
|
||||
gl_RenderState.Apply();
|
||||
gl_RenderState.ApplyMatrices();
|
||||
ApplyVPUniforms();
|
||||
}
|
||||
|
||||
// Handle all portals after rendering the opaque objects but before
|
||||
// doing all translucent stuff
|
||||
recursion++;
|
||||
GLPortal::EndFrame(di);
|
||||
GLRenderer->mPortalState.EndFrame(this);
|
||||
recursion--;
|
||||
RenderTranslucent(di);
|
||||
RenderTranslucent();
|
||||
}
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
|
@ -470,7 +353,7 @@ void GLSceneDrawer::DrawScene(FDrawInfo *di, int drawmode)
|
|||
//-----------------------------------------------------------------------------
|
||||
|
||||
|
||||
void GLSceneDrawer::EndDrawScene(FDrawInfo *di, sector_t * viewsector)
|
||||
void FDrawInfo::EndDrawScene(sector_t * viewsector)
|
||||
{
|
||||
gl_RenderState.EnableFog(false);
|
||||
|
||||
|
@ -480,12 +363,11 @@ void GLSceneDrawer::EndDrawScene(FDrawInfo *di, sector_t * viewsector)
|
|||
{
|
||||
// [BB] The HUD model should be drawn over everything else already drawn.
|
||||
glClear(GL_DEPTH_BUFFER_BIT);
|
||||
di->DrawPlayerSprites(true);
|
||||
DrawPlayerSprites(true);
|
||||
}
|
||||
|
||||
glDisable(GL_STENCIL_TEST);
|
||||
|
||||
Reset3DViewport();
|
||||
glViewport(screen->mScreenViewport.left, screen->mScreenViewport.top, screen->mScreenViewport.width, screen->mScreenViewport.height);
|
||||
|
||||
// Restore standard rendering state
|
||||
gl_RenderState.BlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
|
||||
|
@ -494,19 +376,19 @@ void GLSceneDrawer::EndDrawScene(FDrawInfo *di, sector_t * viewsector)
|
|||
glDisable(GL_SCISSOR_TEST);
|
||||
}
|
||||
|
||||
void GLSceneDrawer::DrawEndScene2D(FDrawInfo *di, sector_t * viewsector)
|
||||
void FDrawInfo::DrawEndScene2D(sector_t * viewsector)
|
||||
{
|
||||
const bool renderHUDModel = IsHUDModelForPlayerAvailable(players[consoleplayer].camera->player);
|
||||
auto vrmode = VRMode::GetVRMode(true);
|
||||
|
||||
// This should be removed once all 2D stuff is really done through the 2D interface.
|
||||
gl_RenderState.mViewMatrix.loadIdentity();
|
||||
gl_RenderState.mProjectionMatrix.ortho(0, screen->GetWidth(), screen->GetHeight(), 0, -1.0f, 1.0f);
|
||||
gl_RenderState.ApplyMatrices();
|
||||
VPUniforms.mViewMatrix.loadIdentity();
|
||||
VPUniforms.mProjectionMatrix = vrmode->GetHUDSpriteProjection();
|
||||
ApplyVPUniforms();
|
||||
glDisable(GL_DEPTH_TEST);
|
||||
glDisable(GL_MULTISAMPLE);
|
||||
|
||||
|
||||
di->DrawPlayerSprites(false);
|
||||
DrawPlayerSprites(false);
|
||||
|
||||
gl_RenderState.SetSoftLightLevel(-1);
|
||||
|
||||
|
@ -523,152 +405,99 @@ void GLSceneDrawer::DrawEndScene2D(FDrawInfo *di, sector_t * viewsector)
|
|||
//
|
||||
//-----------------------------------------------------------------------------
|
||||
|
||||
void GLSceneDrawer::ProcessScene(FDrawInfo *di, bool toscreen)
|
||||
void FDrawInfo::ProcessScene(bool toscreen)
|
||||
{
|
||||
iter_dlightf = iter_dlight = draw_dlight = draw_dlightf = 0;
|
||||
GLPortal::BeginScene();
|
||||
GLRenderer->mPortalState.BeginScene();
|
||||
|
||||
int mapsection = R_PointInSubsector(r_viewpoint.Pos)->mapsection;
|
||||
di->CurrentMapSections.Set(mapsection);
|
||||
GLRenderer->mCurrentPortal = nullptr;
|
||||
DrawScene(di, toscreen ? DM_MAINVIEW : DM_OFFSCREEN);
|
||||
int mapsection = R_PointInSubsector(Viewpoint.Pos)->mapsection;
|
||||
CurrentMapSections.Set(mapsection);
|
||||
DrawScene(toscreen ? DM_MAINVIEW : DM_OFFSCREEN);
|
||||
|
||||
}
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
//
|
||||
// sets 3D viewport and initial state
|
||||
//
|
||||
//-----------------------------------------------------------------------------
|
||||
|
||||
void FGLRenderer::Set3DViewport(bool mainview)
|
||||
{
|
||||
if (mainview && buffersActive)
|
||||
{
|
||||
bool useSSAO = (gl_ssao != 0);
|
||||
mBuffers->BindSceneFB(useSSAO);
|
||||
gl_RenderState.SetPassType(useSSAO ? GBUFFER_PASS : NORMAL_PASS);
|
||||
gl_RenderState.EnableDrawBuffers(gl_RenderState.GetPassDrawBufferCount());
|
||||
gl_RenderState.Apply();
|
||||
}
|
||||
|
||||
// Always clear all buffers with scissor test disabled.
|
||||
// This is faster on newer hardware because it allows the GPU to skip
|
||||
// reading from slower memory where the full buffers are stored.
|
||||
glDisable(GL_SCISSOR_TEST);
|
||||
glClearColor(mSceneClearColor[0], mSceneClearColor[1], mSceneClearColor[2], 1.0f);
|
||||
glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT | GL_STENCIL_BUFFER_BIT);
|
||||
|
||||
const auto &bounds = screen->mSceneViewport;
|
||||
glViewport(bounds.left, bounds.top, bounds.width, bounds.height);
|
||||
glScissor(bounds.left, bounds.top, bounds.width, bounds.height);
|
||||
|
||||
glEnable(GL_SCISSOR_TEST);
|
||||
|
||||
glEnable(GL_MULTISAMPLE);
|
||||
glEnable(GL_DEPTH_TEST);
|
||||
glEnable(GL_STENCIL_TEST);
|
||||
glStencilFunc(GL_ALWAYS,0,~0); // default stencil
|
||||
glStencilOp(GL_KEEP,GL_KEEP,GL_REPLACE);
|
||||
}
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
//
|
||||
// Renders one viewpoint in a scene
|
||||
//
|
||||
//-----------------------------------------------------------------------------
|
||||
|
||||
sector_t * GLSceneDrawer::RenderViewpoint (AActor * camera, IntRect * bounds, float fov, float ratio, float fovratio, bool mainview, bool toscreen)
|
||||
{
|
||||
sector_t * lviewsector;
|
||||
GLRenderer->mSceneClearColor[0] = 0.0f;
|
||||
GLRenderer->mSceneClearColor[1] = 0.0f;
|
||||
GLRenderer->mSceneClearColor[2] = 0.0f;
|
||||
R_SetupFrame (r_viewpoint, r_viewwindow, camera);
|
||||
sector_t * FGLRenderer::RenderViewpoint (FRenderViewpoint &mainvp, AActor * camera, IntRect * bounds, float fov, float ratio, float fovratio, bool mainview, bool toscreen)
|
||||
{
|
||||
R_SetupFrame (mainvp, r_viewwindow, camera);
|
||||
|
||||
GLRenderer->mGlobVis = R_GetGlobVis(r_viewwindow, r_visibility);
|
||||
|
||||
// We have to scale the pitch to account for the pixel stretching, because the playsim doesn't know about this and treats it as 1:1.
|
||||
double radPitch = r_viewpoint.Angles.Pitch.Normalized180().Radians();
|
||||
double angx = cos(radPitch);
|
||||
double angy = sin(radPitch) * level.info->pixelstretch;
|
||||
double alen = sqrt(angx*angx + angy*angy);
|
||||
|
||||
GLRenderer->mAngles.Pitch = (float)RAD2DEG(asin(angy / alen));
|
||||
GLRenderer->mAngles.Roll.Degrees = r_viewpoint.Angles.Roll.Degrees;
|
||||
|
||||
if (camera->player && camera->player-players==consoleplayer &&
|
||||
((camera->player->cheats & CF_CHASECAM) || (r_deathcamera && camera->health <= 0)) && camera==camera->player->mo)
|
||||
// Render (potentially) multiple views for stereo 3d
|
||||
// Fixme. The view offsetting should be done with a static table and not require setup of the entire render state for the mode.
|
||||
auto vrmode = VRMode::GetVRMode(mainview && toscreen);
|
||||
for (int eye_ix = 0; eye_ix < vrmode->mEyeCount; ++eye_ix)
|
||||
{
|
||||
GLRenderer->mViewActor=NULL;
|
||||
}
|
||||
else
|
||||
{
|
||||
GLRenderer->mViewActor=camera;
|
||||
}
|
||||
|
||||
// 'viewsector' will not survive the rendering so it cannot be used anymore below.
|
||||
lviewsector = r_viewpoint.sector;
|
||||
|
||||
// Render (potentially) multiple views for stereo 3d
|
||||
float viewShift[3];
|
||||
const s3d::Stereo3DMode& stereo3dMode = mainview && toscreen? s3d::Stereo3DMode::getCurrentMode() : s3d::Stereo3DMode::getMonoMode();
|
||||
stereo3dMode.SetUp();
|
||||
for (int eye_ix = 0; eye_ix < stereo3dMode.eye_count(); ++eye_ix)
|
||||
{
|
||||
const s3d::EyePose * eye = stereo3dMode.getEyePose(eye_ix);
|
||||
eye->SetUp();
|
||||
const auto &eye = vrmode->mEyes[eye_ix];
|
||||
screen->SetViewportRects(bounds);
|
||||
Set3DViewport(mainview);
|
||||
GLRenderer->mDrawingScene2D = true;
|
||||
GLRenderer->mCurrentFoV = fov;
|
||||
|
||||
FDrawInfo *di = FDrawInfo::StartDrawInfo(this);
|
||||
FDrawInfo *di = FDrawInfo::StartDrawInfo(mainvp, nullptr);
|
||||
auto &vp = di->Viewpoint;
|
||||
di->SetViewArea();
|
||||
auto cm = di->SetFullbrightFlags(mainview ? r_viewpoint.camera->player : nullptr);
|
||||
auto cm = di->SetFullbrightFlags(mainview ? vp.camera->player : nullptr);
|
||||
di->Viewpoint.FieldOfView = fov; // Set the real FOV for the current scene (it's not necessarily the same as the global setting in r_viewpoint)
|
||||
|
||||
// Stereo mode specific perspective projection
|
||||
SetProjection( eye->GetProjection(fov, ratio, fovratio) );
|
||||
// SetProjection(fov, ratio, fovratio); // switch to perspective mode and set up clipper
|
||||
SetViewAngle(r_viewpoint.Angles.Yaw);
|
||||
// Stereo mode specific viewpoint adjustment - temporarily shifts global ViewPos
|
||||
eye->GetViewShift(GLRenderer->mAngles.Yaw.Degrees, viewShift);
|
||||
ScopedViewShifter viewShifter(r_viewpoint.Pos, viewShift);
|
||||
SetViewMatrix(r_viewpoint.Pos.X, r_viewpoint.Pos.Y, r_viewpoint.Pos.Z, false, false);
|
||||
gl_RenderState.ApplyMatrices();
|
||||
di->VPUniforms.mProjectionMatrix = eye.GetProjection(fov, ratio, fovratio);
|
||||
// Stereo mode specific viewpoint adjustment
|
||||
vp.Pos += eye.GetViewShift(vp.HWAngles.Yaw.Degrees);
|
||||
di->SetupView(vp.Pos.X, vp.Pos.Y, vp.Pos.Z, false, false);
|
||||
|
||||
ProcessScene(di, toscreen);
|
||||
|
||||
di->ProcessScene(toscreen);
|
||||
|
||||
if (mainview)
|
||||
{
|
||||
if (toscreen) EndDrawScene(di, lviewsector); // do not call this for camera textures.
|
||||
GLRenderer->PostProcessScene(cm, [&]() { DrawEndScene2D(di, lviewsector); });
|
||||
|
||||
// This should be done after postprocessing, not before.
|
||||
GLRenderer->mBuffers->BindCurrentFB();
|
||||
glViewport(screen->mScreenViewport.left, screen->mScreenViewport.top, screen->mScreenViewport.width, screen->mScreenViewport.height);
|
||||
|
||||
if (!toscreen)
|
||||
{
|
||||
gl_RenderState.mViewMatrix.loadIdentity();
|
||||
gl_RenderState.mProjectionMatrix.ortho(screen->mScreenViewport.left, screen->mScreenViewport.width, screen->mScreenViewport.height, screen->mScreenViewport.top, -1.0f, 1.0f);
|
||||
gl_RenderState.ApplyMatrices();
|
||||
}
|
||||
if (toscreen) di->EndDrawScene(mainvp.sector); // do not call this for camera textures.
|
||||
PostProcessScene(cm, [&]() { di->DrawEndScene2D(mainvp.sector); });
|
||||
}
|
||||
FDrawInfo::EndDrawInfo();
|
||||
GLRenderer->mDrawingScene2D = false;
|
||||
if (!stereo3dMode.IsMono())
|
||||
GLRenderer->mBuffers->BlitToEyeTexture(eye_ix);
|
||||
eye->TearDown();
|
||||
di->EndDrawInfo();
|
||||
if (vrmode->mEyeCount > 1)
|
||||
mBuffers->BlitToEyeTexture(eye_ix);
|
||||
}
|
||||
stereo3dMode.TearDown();
|
||||
|
||||
interpolator.RestoreInterpolations ();
|
||||
return lviewsector;
|
||||
return mainvp.sector;
|
||||
}
|
||||
|
||||
//===========================================================================
|
||||
//
|
||||
// Render the view to a savegame picture
|
||||
//
|
||||
//===========================================================================
|
||||
|
||||
void GLSceneDrawer::WriteSavePic (player_t *player, FileWriter *file, int width, int height)
|
||||
{
|
||||
IntRect bounds;
|
||||
bounds.left = 0;
|
||||
bounds.top = 0;
|
||||
bounds.width = width;
|
||||
bounds.height = height;
|
||||
|
||||
// if GLRenderer->mVBO is persistently mapped we must be sure the GPU finished reading from it before we fill it with new data.
|
||||
glFinish();
|
||||
|
||||
// Switch to render buffers dimensioned for the savepic
|
||||
GLRenderer->mBuffers = GLRenderer->mSaveBuffers;
|
||||
|
||||
P_FindParticleSubsectors(); // make sure that all recently spawned particles have a valid subsector.
|
||||
gl_RenderState.SetVertexBuffer(GLRenderer->mVBO);
|
||||
GLRenderer->mVBO->Reset();
|
||||
GLRenderer->mLights->Clear();
|
||||
|
||||
sector_t *viewsector = RenderViewpoint(players[consoleplayer].camera, &bounds, r_viewpoint.FieldOfView.Degrees, 1.6f, 1.6f, true, false);
|
||||
glDisable(GL_STENCIL_TEST);
|
||||
gl_RenderState.SetSoftLightLevel(-1);
|
||||
GLRenderer->CopyToBackbuffer(&bounds, false);
|
||||
|
||||
// strictly speaking not needed as the glReadPixels should block until the scene is rendered, but this is to safeguard against shitty drivers
|
||||
glFinish();
|
||||
|
||||
uint8_t * scr = (uint8_t *)M_Malloc(width * height * 3);
|
||||
glReadPixels(0,0,width, height,GL_RGB,GL_UNSIGNED_BYTE,scr);
|
||||
M_CreatePNG (file, scr + ((height-1) * width * 3), NULL, SS_RGB, width, height, -width * 3, Gamma);
|
||||
M_Free(scr);
|
||||
|
||||
// Switch back the screen render buffers
|
||||
screen->SetViewportRects(nullptr);
|
||||
GLRenderer->mBuffers = GLRenderer->mScreenBuffers;
|
||||
}
|
||||
|
|
|
@ -1,47 +0,0 @@
|
|||
#pragma once
|
||||
|
||||
#include "r_defs.h"
|
||||
#include "m_fixed.h"
|
||||
#include "hwrenderer/scene/hw_clipper.h"
|
||||
#include "gl_portal.h"
|
||||
#include "gl/renderer/gl_lightdata.h"
|
||||
#include "gl/renderer/gl_renderer.h"
|
||||
#include "r_utility.h"
|
||||
#include "c_cvars.h"
|
||||
|
||||
struct HUDSprite;
|
||||
|
||||
class GLSceneDrawer
|
||||
{
|
||||
TMap<DPSprite*, int> weapondynlightindex;
|
||||
|
||||
void RenderMultipassStuff(FDrawInfo *di);
|
||||
|
||||
void RenderScene(FDrawInfo *di, int recursion);
|
||||
void RenderTranslucent(FDrawInfo *di);
|
||||
|
||||
void CreateScene(FDrawInfo *di);
|
||||
|
||||
public:
|
||||
GLSceneDrawer()
|
||||
{
|
||||
GLPortal::drawer = this;
|
||||
}
|
||||
|
||||
angle_t FrustumAngle();
|
||||
|
||||
void SetViewMatrix(float vx, float vy, float vz, bool mirror, bool planemirror);
|
||||
void SetupView(float vx, float vy, float vz, DAngle va, bool mirror, bool planemirror);
|
||||
void SetViewAngle(DAngle viewangle);
|
||||
void SetProjection(VSMatrix matrix);
|
||||
void Set3DViewport(bool mainview);
|
||||
void Reset3DViewport();
|
||||
void DrawScene(FDrawInfo *di, int drawmode);
|
||||
void ProcessScene(FDrawInfo *di, bool toscreen = false);
|
||||
void EndDrawScene(FDrawInfo *di, sector_t * viewsector);
|
||||
void DrawEndScene2D(FDrawInfo *di, sector_t * viewsector);
|
||||
|
||||
sector_t *RenderViewpoint(AActor * camera, IntRect * bounds, float fov, float ratio, float fovratio, bool mainview, bool toscreen);
|
||||
sector_t *RenderView(player_t *player);
|
||||
void WriteSavePic(player_t *player, FileWriter *file, int width, int height);
|
||||
};
|
|
@ -32,9 +32,10 @@
|
|||
#include "gl_load/gl_interface.h"
|
||||
#include "gl/data/gl_vertexbuffer.h"
|
||||
#include "gl/renderer/gl_lightdata.h"
|
||||
#include "gl/renderer/gl_renderer.h"
|
||||
#include "gl/renderer/gl_renderstate.h"
|
||||
#include "gl/scene/gl_drawinfo.h"
|
||||
#include "gl/scene/gl_scenedrawer.h"
|
||||
#include "gl/scene/gl_portal.h"
|
||||
#include "gl/shaders/gl_shader.h"
|
||||
|
||||
|
||||
|
@ -209,9 +210,10 @@ static void RenderBox(FTextureID texno, FMaterial * gltex, float x_offset, bool
|
|||
//
|
||||
//
|
||||
//-----------------------------------------------------------------------------
|
||||
void GLSkyPortal::DrawContents(FDrawInfo *di)
|
||||
void GLSkyPortal::DrawContents(HWDrawInfo *di)
|
||||
{
|
||||
bool drawBoth = false;
|
||||
auto &vp = di->Viewpoint;
|
||||
|
||||
// We have no use for Doom lighting special handling here, so disable it for this function.
|
||||
int oldlightmode = ::level.lightmode;
|
||||
|
@ -228,8 +230,7 @@ void GLSkyPortal::DrawContents(FDrawInfo *di)
|
|||
gl_RenderState.BlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
|
||||
bool oldClamp = gl_RenderState.SetDepthClamp(true);
|
||||
|
||||
gl_MatrixStack.Push(gl_RenderState.mViewMatrix);
|
||||
drawer->SetupView(0, 0, 0, r_viewpoint.Angles.Yaw, !!(MirrorFlag & 1), !!(PlaneMirrorFlag & 1));
|
||||
di->SetupView(0, 0, 0, !!(mState->MirrorFlag & 1), !!(mState->PlaneMirrorFlag & 1));
|
||||
|
||||
gl_RenderState.SetVertexBuffer(GLRenderer->mSkyVBO);
|
||||
if (origin->texture[0] && origin->texture[0]->tex->bSkybox)
|
||||
|
@ -268,8 +269,7 @@ void GLSkyPortal::DrawContents(FDrawInfo *di)
|
|||
}
|
||||
}
|
||||
gl_RenderState.SetVertexBuffer(GLRenderer->mVBO);
|
||||
gl_MatrixStack.Pop(gl_RenderState.mViewMatrix);
|
||||
gl_RenderState.ApplyMatrices();
|
||||
di->ApplyVPUniforms();
|
||||
::level.lightmode = oldlightmode;
|
||||
gl_RenderState.SetDepthClamp(oldClamp);
|
||||
}
|
||||
|
|
|
@ -47,7 +47,6 @@
|
|||
#include "gl/renderer/gl_renderstate.h"
|
||||
#include "gl/renderer/gl_renderer.h"
|
||||
#include "gl/scene/gl_drawinfo.h"
|
||||
#include "gl/scene/gl_scenedrawer.h"
|
||||
#include "gl/models/gl_models.h"
|
||||
#include "gl/renderer/gl_quaddrawer.h"
|
||||
#include "gl/dynlights/gl_lightbuffer.h"
|
||||
|
@ -79,6 +78,7 @@ void FDrawInfo::DrawSprite(GLSprite *sprite, int pass)
|
|||
bool additivefog = false;
|
||||
bool foglayer = false;
|
||||
int rel = sprite->fullbright? 0 : getExtraLight();
|
||||
auto &vp = Viewpoint;
|
||||
|
||||
if (pass==GLPASS_TRANSLUCENT)
|
||||
{
|
||||
|
@ -112,7 +112,7 @@ void FDrawInfo::DrawSprite(GLSprite *sprite, int pass)
|
|||
// fog + fuzz don't work well without some fiddling with the alpha value!
|
||||
if (!sprite->Colormap.FadeColor.isBlack())
|
||||
{
|
||||
float dist=Dist2(r_viewpoint.Pos.X, r_viewpoint.Pos.Y, sprite->x, sprite->y);
|
||||
float dist=Dist2(vp.Pos.X, vp.Pos.Y, sprite->x, sprite->y);
|
||||
int fogd = hw_GetFogDensity(sprite->lightlevel, sprite->Colormap.FadeColor, sprite->Colormap.FogDensity);
|
||||
|
||||
// this value was determined by trial and error and is scale dependent!
|
||||
|
@ -221,7 +221,7 @@ void FDrawInfo::DrawSprite(GLSprite *sprite, int pass)
|
|||
secplane_t *lowplane = i == (*lightlist).Size() - 1 ? &bottomp : &(*lightlist)[i + 1].plane;
|
||||
|
||||
int thislight = (*lightlist)[i].caster != nullptr ? hw_ClampLight(*(*lightlist)[i].p_lightlevel) : sprite->lightlevel;
|
||||
int thisll = sprite->actor == nullptr? thislight : (uint8_t)sprite->actor->Sector->CheckSpriteGlow(thislight, sprite->actor->InterpolatedPosition(r_viewpoint.TicFrac));
|
||||
int thisll = sprite->actor == nullptr? thislight : (uint8_t)sprite->actor->Sector->CheckSpriteGlow(thislight, sprite->actor->InterpolatedPosition(vp.TicFrac));
|
||||
|
||||
FColormap thiscm;
|
||||
thiscm.CopyFog(sprite->Colormap);
|
||||
|
@ -249,7 +249,8 @@ void FDrawInfo::DrawSprite(GLSprite *sprite, int pass)
|
|||
|
||||
FVector3 v[4];
|
||||
gl_RenderState.SetNormal(0, 0, 0);
|
||||
if (sprite->CalculateVertices(this, v))
|
||||
|
||||
if (sprite->CalculateVertices(this, v, &vp.Pos))
|
||||
{
|
||||
glEnable(GL_POLYGON_OFFSET_FILL);
|
||||
glPolygonOffset(-1.0f, -128.0f);
|
||||
|
@ -276,7 +277,8 @@ void FDrawInfo::DrawSprite(GLSprite *sprite, int pass)
|
|||
}
|
||||
else
|
||||
{
|
||||
gl_RenderModel(sprite, sprite->dynlightindex);
|
||||
FGLModelRenderer renderer(this, sprite->dynlightindex);
|
||||
renderer.RenderModel(sprite->x, sprite->y, sprite->z, sprite->modelframe, sprite->actor, vp.TicFrac);
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -37,7 +37,6 @@
|
|||
#include "gl/dynlights/gl_lightbuffer.h"
|
||||
#include "gl/scene/gl_drawinfo.h"
|
||||
#include "gl/scene/gl_portal.h"
|
||||
#include "gl/scene/gl_scenedrawer.h"
|
||||
|
||||
EXTERN_CVAR(Bool, gl_seamless)
|
||||
|
||||
|
@ -94,7 +93,6 @@ void FDrawInfo::RenderMirrorSurface(GLWall *wall)
|
|||
|
||||
// we use texture coordinates and texture matrix to pass the normal stuff to the shader so that the default vertex buffer format can be used as is.
|
||||
gl_RenderState.EnableTextureMatrix(true);
|
||||
gl_RenderState.mTextureMatrix.computeNormalMatrix(gl_RenderState.mViewMatrix);
|
||||
|
||||
// Use sphere mapping for this
|
||||
gl_RenderState.SetEffect(EFF_SPHEREMAP);
|
||||
|
@ -339,7 +337,8 @@ void FDrawInfo::AddMirrorSurface(GLWall *w)
|
|||
|
||||
void FDrawInfo::AddPortal(GLWall *wall, int ptype)
|
||||
{
|
||||
GLPortal * portal;
|
||||
auto &pstate = GLRenderer->mPortalState;
|
||||
IPortal * portal;
|
||||
|
||||
wall->MakeVertices(this, false);
|
||||
switch (ptype)
|
||||
|
@ -347,42 +346,63 @@ void FDrawInfo::AddPortal(GLWall *wall, int ptype)
|
|||
// portals don't go into the draw list.
|
||||
// Instead they are added to the portal manager
|
||||
case PORTALTYPE_HORIZON:
|
||||
wall->horizon = UniqueHorizons.Get(wall->horizon);
|
||||
portal = GLPortal::FindPortal(wall->horizon);
|
||||
if (!portal) portal = new GLHorizonPortal(wall->horizon);
|
||||
wall->horizon = pstate.UniqueHorizons.Get(wall->horizon);
|
||||
portal = FindPortal(wall->horizon);
|
||||
if (!portal)
|
||||
{
|
||||
portal = new GLHorizonPortal(&pstate, wall->horizon, Viewpoint);
|
||||
Portals.Push(portal);
|
||||
}
|
||||
portal->AddLine(wall);
|
||||
break;
|
||||
|
||||
case PORTALTYPE_SKYBOX:
|
||||
portal = GLPortal::FindPortal(wall->secportal);
|
||||
portal = FindPortal(wall->secportal);
|
||||
if (!portal)
|
||||
{
|
||||
// either a regular skybox or an Eternity-style horizon
|
||||
if (wall->secportal->mType != PORTS_SKYVIEWPOINT) portal = new GLEEHorizonPortal(wall->secportal);
|
||||
else portal = new GLSkyboxPortal(wall->secportal);
|
||||
if (wall->secportal->mType != PORTS_SKYVIEWPOINT) portal = new GLEEHorizonPortal(&pstate, wall->secportal);
|
||||
else
|
||||
{
|
||||
portal = new GLScenePortal(&pstate, new HWSkyboxPortal(wall->secportal));
|
||||
Portals.Push(portal);
|
||||
}
|
||||
}
|
||||
portal->AddLine(wall);
|
||||
break;
|
||||
|
||||
case PORTALTYPE_SECTORSTACK:
|
||||
portal = wall->portal->GetRenderState();
|
||||
portal = FindPortal(wall->portal);
|
||||
if (!portal)
|
||||
{
|
||||
portal = new GLScenePortal(&pstate, new HWSectorStackPortal(wall->portal));
|
||||
Portals.Push(portal);
|
||||
}
|
||||
portal->AddLine(wall);
|
||||
break;
|
||||
|
||||
case PORTALTYPE_PLANEMIRROR:
|
||||
if (GLPortal::PlaneMirrorMode * wall->planemirror->fC() <= 0)
|
||||
if (pstate.PlaneMirrorMode * wall->planemirror->fC() <= 0)
|
||||
{
|
||||
//@sync-portal
|
||||
wall->planemirror = UniquePlaneMirrors.Get(wall->planemirror);
|
||||
portal = GLPortal::FindPortal(wall->planemirror);
|
||||
if (!portal) portal = new GLPlaneMirrorPortal(wall->planemirror);
|
||||
wall->planemirror = pstate.UniquePlaneMirrors.Get(wall->planemirror);
|
||||
portal = FindPortal(wall->planemirror);
|
||||
if (!portal)
|
||||
{
|
||||
portal = new GLScenePortal(&pstate, new HWPlaneMirrorPortal(wall->planemirror));
|
||||
Portals.Push(portal);
|
||||
}
|
||||
portal->AddLine(wall);
|
||||
}
|
||||
break;
|
||||
|
||||
case PORTALTYPE_MIRROR:
|
||||
portal = GLPortal::FindPortal(wall->seg->linedef);
|
||||
if (!portal) portal = new GLMirrorPortal(wall->seg->linedef);
|
||||
portal = FindPortal(wall->seg->linedef);
|
||||
if (!portal)
|
||||
{
|
||||
portal = new GLScenePortal(&pstate, new HWMirrorPortal(wall->seg->linedef));
|
||||
Portals.Push(portal);
|
||||
}
|
||||
portal->AddLine(wall);
|
||||
if (gl_mirror_envmap)
|
||||
{
|
||||
|
@ -392,23 +412,28 @@ void FDrawInfo::AddPortal(GLWall *wall, int ptype)
|
|||
break;
|
||||
|
||||
case PORTALTYPE_LINETOLINE:
|
||||
portal = GLPortal::FindPortal(wall->lineportal);
|
||||
portal = FindPortal(wall->lineportal);
|
||||
if (!portal)
|
||||
{
|
||||
line_t *otherside = wall->lineportal->lines[0]->mDestination;
|
||||
if (otherside != NULL && otherside->portalindex < level.linePortals.Size())
|
||||
if (otherside != nullptr && otherside->portalindex < level.linePortals.Size())
|
||||
{
|
||||
ProcessActorsInPortal(otherside->getPortal()->mGroup, in_area);
|
||||
}
|
||||
portal = new GLLineToLinePortal(wall->lineportal);
|
||||
portal = new GLScenePortal(&pstate, new HWLineToLinePortal(wall->lineportal));
|
||||
Portals.Push(portal);
|
||||
}
|
||||
portal->AddLine(wall);
|
||||
break;
|
||||
|
||||
case PORTALTYPE_SKY:
|
||||
wall->sky = UniqueSkies.Get(wall->sky);
|
||||
portal = GLPortal::FindPortal(wall->sky);
|
||||
if (!portal) portal = new GLSkyPortal(wall->sky);
|
||||
wall->sky = pstate.UniqueSkies.Get(wall->sky);
|
||||
portal = FindPortal(wall->sky);
|
||||
if (!portal)
|
||||
{
|
||||
portal = new GLSkyPortal(&pstate, wall->sky);
|
||||
Portals.Push(portal);
|
||||
}
|
||||
portal->AddLine(wall);
|
||||
break;
|
||||
}
|
||||
|
|
|
@ -37,9 +37,7 @@
|
|||
#include "gl/renderer/gl_renderstate.h"
|
||||
#include "gl/data/gl_vertexbuffer.h"
|
||||
#include "gl/scene/gl_drawinfo.h"
|
||||
#include "gl/scene/gl_scenedrawer.h"
|
||||
#include "gl/models/gl_models.h"
|
||||
#include "gl/stereo3d/gl_stereo3d.h"
|
||||
#include "gl/dynlights/gl_lightbuffer.h"
|
||||
|
||||
//==========================================================================
|
||||
|
@ -66,7 +64,8 @@ void FDrawInfo::DrawPSprite (HUDSprite *huds)
|
|||
if (huds->mframe)
|
||||
{
|
||||
gl_RenderState.AlphaFunc(GL_GEQUAL, 0);
|
||||
gl_RenderHUDModel(huds->weapon, huds->mx, huds->my, huds->lightindex);
|
||||
FGLModelRenderer renderer(this, huds->lightindex);
|
||||
renderer.RenderHUDModel(huds->weapon, huds->mx, huds->my);
|
||||
}
|
||||
else
|
||||
{
|
||||
|
@ -91,8 +90,6 @@ void FDrawInfo::DrawPSprite (HUDSprite *huds)
|
|||
|
||||
void FDrawInfo::DrawPlayerSprites(bool hudModelStep)
|
||||
{
|
||||
s3d::Stereo3DMode::getCurrentMode().AdjustPlayerSprites();
|
||||
|
||||
int oldlightmode = level.lightmode;
|
||||
if (!hudModelStep && level.lightmode == 8) level.lightmode = 2; // Software lighting cannot handle 2D content so revert to lightmode 2 for that.
|
||||
for(auto &hudsprite : hudsprites)
|
||||
|
|
|
@ -34,6 +34,7 @@
|
|||
#include "cmdlib.h"
|
||||
#include "hwrenderer/utility/hw_shaderpatcher.h"
|
||||
#include "hwrenderer/data/shaderuniforms.h"
|
||||
#include "hwrenderer/scene/hw_viewpointuniforms.h"
|
||||
|
||||
#include "gl_load/gl_interface.h"
|
||||
#include "gl/system/gl_debug.h"
|
||||
|
@ -307,10 +308,7 @@ bool FShader::Load(const char * name, const char * vert_prog_lump, const char *
|
|||
|
||||
muDesaturation.Init(hShader, "uDesaturationFactor");
|
||||
muFogEnabled.Init(hShader, "uFogEnabled");
|
||||
muPalLightLevels.Init(hShader, "uPalLightLevels");
|
||||
muGlobVis.Init(hShader, "uGlobVis");
|
||||
muTextureMode.Init(hShader, "uTextureMode");
|
||||
muCameraPos.Init(hShader, "uCameraPos");
|
||||
muLightParms.Init(hShader, "uLightAttr");
|
||||
muClipSplit.Init(hShader, "uClipSplit");
|
||||
muLightIndex.Init(hShader, "uLightIndex");
|
||||
|
@ -324,13 +322,9 @@ bool FShader::Load(const char * name, const char * vert_prog_lump, const char *
|
|||
muGlowTopPlane.Init(hShader, "uGlowTopPlane");
|
||||
muSplitBottomPlane.Init(hShader, "uSplitBottomPlane");
|
||||
muSplitTopPlane.Init(hShader, "uSplitTopPlane");
|
||||
muClipLine.Init(hShader, "uClipLine");
|
||||
muInterpolationFactor.Init(hShader, "uInterpolationFactor");
|
||||
muClipHeight.Init(hShader, "uClipHeight");
|
||||
muClipHeightDirection.Init(hShader, "uClipHeightDirection");
|
||||
muAlphaThreshold.Init(hShader, "uAlphaThreshold");
|
||||
muSpecularMaterial.Init(hShader, "uSpecularMaterial");
|
||||
muViewHeight.Init(hShader, "uViewHeight");
|
||||
muTimer.Init(hShader, "timer");
|
||||
|
||||
lights_index = glGetUniformLocation(hShader, "lights");
|
||||
|
@ -344,6 +338,13 @@ bool FShader::Load(const char * name, const char * vert_prog_lump, const char *
|
|||
normalviewmatrix_index = glGetUniformLocation(hShader, "NormalViewMatrix");
|
||||
normalmodelmatrix_index = glGetUniformLocation(hShader, "NormalModelMatrix");
|
||||
quadmode_index = glGetUniformLocation(hShader, "uQuadMode");
|
||||
viewheight_index = glGetUniformLocation(hShader, "uViewHeight");
|
||||
camerapos_index = glGetUniformLocation(hShader, "uCameraPos");
|
||||
pallightlevels_index = glGetUniformLocation(hShader, "uPalLightLevels");
|
||||
globvis_index = glGetUniformLocation(hShader, "uGlobVis");
|
||||
clipheight_index = glGetUniformLocation(hShader, "uClipHeight");
|
||||
clipheightdirection_index = glGetUniformLocation(hShader, "uClipHeightDirection");
|
||||
clipline_index = glGetUniformLocation(hShader, "uClipLine");
|
||||
|
||||
if (!(gl.flags & RFL_SHADER_STORAGE_BUFFER))
|
||||
{
|
||||
|
@ -434,12 +435,19 @@ FShader *FShaderCollection::Compile (const char *ShaderName, const char *ShaderP
|
|||
//
|
||||
//==========================================================================
|
||||
|
||||
void FShader::ApplyMatrices(VSMatrix *proj, VSMatrix *view, VSMatrix *norm)
|
||||
void FShader::ApplyMatrices(HWViewpointUniforms *u)
|
||||
{
|
||||
Bind();
|
||||
glUniformMatrix4fv(projectionmatrix_index, 1, false, proj->get());
|
||||
glUniformMatrix4fv(viewmatrix_index, 1, false, view->get());
|
||||
glUniformMatrix4fv(normalviewmatrix_index, 1, false, norm->get());
|
||||
glUniformMatrix4fv(projectionmatrix_index, 1, false, u->mProjectionMatrix.get());
|
||||
glUniformMatrix4fv(viewmatrix_index, 1, false, u->mViewMatrix.get());
|
||||
glUniformMatrix4fv(normalviewmatrix_index, 1, false, u->mNormalViewMatrix.get());
|
||||
|
||||
glUniform4fv(camerapos_index, 1, &u->mCameraPos[0]);
|
||||
glUniform1i(viewheight_index, u->mViewHeight);
|
||||
glUniform1i(pallightlevels_index, u->mPalLightLevels);
|
||||
glUniform1f(globvis_index, u->mGlobVis);
|
||||
glUniform1f(clipheight_index, u->mClipHeight);
|
||||
glUniform1f(clipheightdirection_index, u->mClipHeightDirection);
|
||||
}
|
||||
|
||||
//==========================================================================
|
||||
|
@ -539,10 +547,10 @@ FShader *FShaderManager::Get(unsigned int eff, bool alphateston, EPassType passT
|
|||
return nullptr;
|
||||
}
|
||||
|
||||
void FShaderManager::ApplyMatrices(VSMatrix *proj, VSMatrix *view, EPassType passType)
|
||||
void FShaderManager::ApplyMatrices(HWViewpointUniforms *u, EPassType passType)
|
||||
{
|
||||
if (passType < mPassShaders.Size())
|
||||
mPassShaders[passType]->ApplyMatrices(proj, view);
|
||||
mPassShaders[passType]->ApplyMatrices(u);
|
||||
|
||||
if (mActiveShader)
|
||||
mActiveShader->Bind();
|
||||
|
@ -687,28 +695,25 @@ FShader *FShaderCollection::BindEffect(int effect)
|
|||
//==========================================================================
|
||||
EXTERN_CVAR(Int, gl_fuzztype)
|
||||
|
||||
void FShaderCollection::ApplyMatrices(VSMatrix *proj, VSMatrix *view)
|
||||
void FShaderCollection::ApplyMatrices(HWViewpointUniforms *u)
|
||||
{
|
||||
VSMatrix norm;
|
||||
norm.computeNormalMatrix(*view);
|
||||
|
||||
for (int i = 0; i < SHADER_NoTexture; i++)
|
||||
{
|
||||
mMaterialShaders[i]->ApplyMatrices(proj, view, &norm);
|
||||
mMaterialShadersNAT[i]->ApplyMatrices(proj, view, &norm);
|
||||
mMaterialShaders[i]->ApplyMatrices(u);
|
||||
mMaterialShadersNAT[i]->ApplyMatrices(u);
|
||||
}
|
||||
mMaterialShaders[SHADER_NoTexture]->ApplyMatrices(proj, view, &norm);
|
||||
mMaterialShaders[SHADER_NoTexture]->ApplyMatrices(u);
|
||||
if (gl_fuzztype != 0)
|
||||
{
|
||||
mMaterialShaders[SHADER_NoTexture + gl_fuzztype]->ApplyMatrices(proj, view, &norm);
|
||||
mMaterialShaders[SHADER_NoTexture + gl_fuzztype]->ApplyMatrices(u);
|
||||
}
|
||||
for (unsigned i = FIRST_USER_SHADER; i < mMaterialShaders.Size(); i++)
|
||||
{
|
||||
mMaterialShaders[i]->ApplyMatrices(proj, view, &norm);
|
||||
mMaterialShaders[i]->ApplyMatrices(u);
|
||||
}
|
||||
for (int i = 0; i < MAX_EFFECTS; i++)
|
||||
{
|
||||
mEffectShaders[i]->ApplyMatrices(proj, view, &norm);
|
||||
mEffectShaders[i]->ApplyMatrices(u);
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -38,6 +38,7 @@ enum
|
|||
};
|
||||
|
||||
class FShaderCollection;
|
||||
struct HWViewpointUniforms;
|
||||
|
||||
//==========================================================================
|
||||
//
|
||||
|
@ -242,10 +243,7 @@ class FShader
|
|||
|
||||
FBufferedUniform1f muDesaturation;
|
||||
FBufferedUniform1i muFogEnabled;
|
||||
FBufferedUniform1i muPalLightLevels;
|
||||
FBufferedUniform1f muGlobVis;
|
||||
FBufferedUniform1i muTextureMode;
|
||||
FBufferedUniform4f muCameraPos;
|
||||
FBufferedUniform4f muLightParms;
|
||||
FBufferedUniform2f muClipSplit;
|
||||
FBufferedUniform1i muLightIndex;
|
||||
|
@ -259,22 +257,27 @@ class FShader
|
|||
FUniform4f muGlowTopPlane;
|
||||
FUniform4f muSplitBottomPlane;
|
||||
FUniform4f muSplitTopPlane;
|
||||
FUniform4f muClipLine;
|
||||
FBufferedUniform1f muInterpolationFactor;
|
||||
FBufferedUniform1f muClipHeight;
|
||||
FBufferedUniform1f muClipHeightDirection;
|
||||
FBufferedUniform1f muAlphaThreshold;
|
||||
FBufferedUniform1i muViewHeight;
|
||||
FBufferedUniform2f muSpecularMaterial;
|
||||
FBufferedUniform1f muTimer;
|
||||
|
||||
int lights_index;
|
||||
int projectionmatrix_index;
|
||||
int viewmatrix_index;
|
||||
int normalviewmatrix_index;
|
||||
int modelmatrix_index;
|
||||
int normalmodelmatrix_index;
|
||||
int texturematrix_index;
|
||||
|
||||
int projectionmatrix_index;
|
||||
int viewmatrix_index;
|
||||
int normalviewmatrix_index;
|
||||
int viewheight_index;
|
||||
int camerapos_index;
|
||||
int pallightlevels_index;
|
||||
int globvis_index;
|
||||
int clipheight_index;
|
||||
int clipheightdirection_index;
|
||||
int clipline_index;
|
||||
|
||||
public:
|
||||
int vertexmatrix_index;
|
||||
int texcoordmatrix_index;
|
||||
|
@ -306,7 +309,7 @@ public:
|
|||
bool Bind();
|
||||
unsigned int GetHandle() const { return hShader; }
|
||||
|
||||
void ApplyMatrices(VSMatrix *proj, VSMatrix *view, VSMatrix *norm);
|
||||
void ApplyMatrices(HWViewpointUniforms *u);
|
||||
|
||||
};
|
||||
|
||||
|
@ -326,7 +329,7 @@ public:
|
|||
|
||||
FShader *BindEffect(int effect, EPassType passType);
|
||||
FShader *Get(unsigned int eff, bool alphateston, EPassType passType);
|
||||
void ApplyMatrices(VSMatrix *proj, VSMatrix *view, EPassType passType);
|
||||
void ApplyMatrices(HWViewpointUniforms *u, EPassType passType);
|
||||
|
||||
private:
|
||||
FShader *mActiveShader = nullptr;
|
||||
|
@ -348,7 +351,7 @@ public:
|
|||
FShader *Compile(const char *ShaderName, const char *ShaderPath, const char *LightModePath, const char *shaderdefines, bool usediscard, EPassType passType);
|
||||
int Find(const char *mame);
|
||||
FShader *BindEffect(int effect);
|
||||
void ApplyMatrices(VSMatrix *proj, VSMatrix *view);
|
||||
void ApplyMatrices(HWViewpointUniforms *u);
|
||||
|
||||
FShader *Get(unsigned int eff, bool alphateston)
|
||||
{
|
||||
|
|
|
@ -1,84 +0,0 @@
|
|||
//
|
||||
//---------------------------------------------------------------------------
|
||||
//
|
||||
// Copyright(C) 2015 Christopher Bruns
|
||||
// All rights reserved.
|
||||
//
|
||||
// This program is free software: you can redistribute it and/or modify
|
||||
// it under the terms of the GNU Lesser General Public License as published by
|
||||
// the Free Software Foundation, either version 3 of the License, or
|
||||
// (at your option) any later version.
|
||||
//
|
||||
// This program is distributed in the hope that it will be useful,
|
||||
// but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
// GNU Lesser General Public License for more details.
|
||||
//
|
||||
// You should have received a copy of the GNU Lesser General Public License
|
||||
// along with this program. If not, see http://www.gnu.org/licenses/
|
||||
//
|
||||
//--------------------------------------------------------------------------
|
||||
//
|
||||
/*
|
||||
** gl_anaglyph.cpp
|
||||
** Color mask based stereoscopic 3D modes for GZDoom
|
||||
**
|
||||
*/
|
||||
|
||||
#include "gl_anaglyph.h"
|
||||
#include "gl/renderer/gl_renderbuffers.h"
|
||||
|
||||
namespace s3d {
|
||||
|
||||
MaskAnaglyph::MaskAnaglyph(const ColorMask& leftColorMask, double ipdMeters)
|
||||
: leftEye(leftColorMask, ipdMeters), rightEye(leftColorMask.inverse(), ipdMeters)
|
||||
{
|
||||
eye_ptrs.Push(&leftEye);
|
||||
eye_ptrs.Push(&rightEye);
|
||||
}
|
||||
|
||||
void MaskAnaglyph::Present() const
|
||||
{
|
||||
GLRenderer->mBuffers->BindOutputFB();
|
||||
GLRenderer->ClearBorders();
|
||||
|
||||
gl_RenderState.SetColorMask(leftEye.GetColorMask().r, leftEye.GetColorMask().g, leftEye.GetColorMask().b, true);
|
||||
gl_RenderState.ApplyColorMask();
|
||||
GLRenderer->mBuffers->BindEyeTexture(0, 0);
|
||||
GLRenderer->DrawPresentTexture(screen->mOutputLetterbox, true);
|
||||
|
||||
gl_RenderState.SetColorMask(rightEye.GetColorMask().r, rightEye.GetColorMask().g, rightEye.GetColorMask().b, true);
|
||||
gl_RenderState.ApplyColorMask();
|
||||
GLRenderer->mBuffers->BindEyeTexture(1, 0);
|
||||
GLRenderer->DrawPresentTexture(screen->mOutputLetterbox, true);
|
||||
|
||||
gl_RenderState.ResetColorMask();
|
||||
gl_RenderState.ApplyColorMask();
|
||||
}
|
||||
|
||||
|
||||
/* static */
|
||||
const GreenMagenta& GreenMagenta::getInstance(float ipd)
|
||||
{
|
||||
static GreenMagenta instance(ipd);
|
||||
return instance;
|
||||
}
|
||||
|
||||
|
||||
/* static */
|
||||
const RedCyan& RedCyan::getInstance(float ipd)
|
||||
{
|
||||
static RedCyan instance(ipd);
|
||||
return instance;
|
||||
}
|
||||
|
||||
|
||||
/* static */
|
||||
const AmberBlue& AmberBlue::getInstance(float ipd)
|
||||
{
|
||||
static AmberBlue instance(ipd);
|
||||
return instance;
|
||||
}
|
||||
|
||||
|
||||
} /* namespace s3d */
|
|
@ -1,113 +0,0 @@
|
|||
//
|
||||
//---------------------------------------------------------------------------
|
||||
//
|
||||
// Copyright(C) 2015 Christopher Bruns
|
||||
// All rights reserved.
|
||||
//
|
||||
// This program is free software: you can redistribute it and/or modify
|
||||
// it under the terms of the GNU Lesser General Public License as published by
|
||||
// the Free Software Foundation, either version 3 of the License, or
|
||||
// (at your option) any later version.
|
||||
//
|
||||
// This program is distributed in the hope that it will be useful,
|
||||
// but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
// GNU Lesser General Public License for more details.
|
||||
//
|
||||
// You should have received a copy of the GNU Lesser General Public License
|
||||
// along with this program. If not, see http://www.gnu.org/licenses/
|
||||
//
|
||||
//--------------------------------------------------------------------------
|
||||
//
|
||||
/*
|
||||
** gl_anaglyph.h
|
||||
** Color mask based stereoscopic 3D modes for GZDoom
|
||||
**
|
||||
*/
|
||||
|
||||
#ifndef GL_ANAGLYPH_H_
|
||||
#define GL_ANAGLYPH_H_
|
||||
|
||||
#include "gl_stereo3d.h"
|
||||
#include "gl_stereo_leftright.h"
|
||||
#include "gl_load/gl_system.h"
|
||||
#include "gl/renderer/gl_renderstate.h"
|
||||
|
||||
|
||||
namespace s3d {
|
||||
|
||||
|
||||
class ColorMask
|
||||
{
|
||||
public:
|
||||
ColorMask(bool r, bool g, bool b) : r(r), g(g), b(b) {}
|
||||
ColorMask inverse() const { return ColorMask(!r, !g, !b); }
|
||||
|
||||
bool r;
|
||||
bool g;
|
||||
bool b;
|
||||
};
|
||||
|
||||
|
||||
class AnaglyphLeftPose : public LeftEyePose
|
||||
{
|
||||
public:
|
||||
AnaglyphLeftPose(const ColorMask& colorMask, float ipd) : LeftEyePose(ipd), colorMask(colorMask) {}
|
||||
ColorMask GetColorMask() const { return colorMask; }
|
||||
|
||||
private:
|
||||
ColorMask colorMask;
|
||||
};
|
||||
|
||||
class AnaglyphRightPose : public RightEyePose
|
||||
{
|
||||
public:
|
||||
AnaglyphRightPose(const ColorMask& colorMask, float ipd) : RightEyePose(ipd), colorMask(colorMask) {}
|
||||
ColorMask GetColorMask() const { return colorMask; }
|
||||
|
||||
private:
|
||||
ColorMask colorMask;
|
||||
};
|
||||
|
||||
class MaskAnaglyph : public Stereo3DMode
|
||||
{
|
||||
public:
|
||||
MaskAnaglyph(const ColorMask& leftColorMask, double ipdMeters);
|
||||
void Present() const override;
|
||||
private:
|
||||
AnaglyphLeftPose leftEye;
|
||||
AnaglyphRightPose rightEye;
|
||||
};
|
||||
|
||||
|
||||
class RedCyan : public MaskAnaglyph
|
||||
{
|
||||
public:
|
||||
static const RedCyan& getInstance(float ipd);
|
||||
|
||||
RedCyan(float ipd) : MaskAnaglyph(ColorMask(true, false, false), ipd) {}
|
||||
};
|
||||
|
||||
class GreenMagenta : public MaskAnaglyph
|
||||
{
|
||||
public:
|
||||
static const GreenMagenta& getInstance(float ipd);
|
||||
|
||||
GreenMagenta(float ipd) : MaskAnaglyph(ColorMask(false, true, false), ipd) {}
|
||||
};
|
||||
|
||||
class AmberBlue : public MaskAnaglyph
|
||||
{
|
||||
public:
|
||||
static const AmberBlue& getInstance(float ipd);
|
||||
|
||||
AmberBlue(float ipd) : MaskAnaglyph(ColorMask(true, true, false), ipd) {}
|
||||
};
|
||||
|
||||
// TODO matrix anaglyph
|
||||
|
||||
|
||||
} /* namespace s3d */
|
||||
|
||||
|
||||
#endif /* GL_ANAGLYPH_H_ */
|
|
@ -1,232 +0,0 @@
|
|||
/*
|
||||
** gl_interleaved3d.cpp
|
||||
** Interleaved image stereoscopic 3D modes for GZDoom
|
||||
**
|
||||
**---------------------------------------------------------------------------
|
||||
** Copyright 2016 Christopher Bruns
|
||||
** All rights reserved.
|
||||
**
|
||||
** Redistribution and use in source and binary forms, with or without
|
||||
** modification, are permitted provided that the following conditions
|
||||
** are met:
|
||||
**
|
||||
** 1. Redistributions of source code must retain the above copyright
|
||||
** notice, this list of conditions and the following disclaimer.
|
||||
** 2. Redistributions in binary form must reproduce the above copyright
|
||||
** notice, this list of conditions and the following disclaimer in the
|
||||
** documentation and/or other materials provided with the distribution.
|
||||
** 3. The name of the author may not be used to endorse or promote products
|
||||
** derived from this software without specific prior written permission.
|
||||
**
|
||||
** THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
|
||||
** IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
|
||||
** OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
|
||||
** IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
|
||||
** INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
|
||||
** NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
|
||||
** DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
|
||||
** THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
|
||||
** (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
|
||||
** THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
**---------------------------------------------------------------------------
|
||||
**
|
||||
**
|
||||
*/
|
||||
|
||||
#include "gl_interleaved3d.h"
|
||||
#include "gl/renderer/gl_renderbuffers.h"
|
||||
#include "gl/renderer/gl_postprocessstate.h"
|
||||
#include "gl/system/gl_framebuffer.h"
|
||||
#include "hwrenderer/postprocessing/hw_present3dRowshader.h"
|
||||
|
||||
#ifdef _WIN32
|
||||
#include "hardware.h"
|
||||
#endif // _WIN32
|
||||
|
||||
EXTERN_CVAR(Float, vid_saturation)
|
||||
EXTERN_CVAR(Float, vid_brightness)
|
||||
EXTERN_CVAR(Float, vid_contrast)
|
||||
EXTERN_CVAR(Int, gl_satformula)
|
||||
EXTERN_CVAR(Bool, fullscreen)
|
||||
EXTERN_CVAR(Int, win_x) // screen pixel position of left of display window
|
||||
EXTERN_CVAR(Int, win_y) // screen pixel position of top of display window
|
||||
|
||||
namespace s3d {
|
||||
|
||||
/* static */
|
||||
const CheckerInterleaved3D& CheckerInterleaved3D::getInstance(float ipd)
|
||||
{
|
||||
static CheckerInterleaved3D instance(ipd);
|
||||
return instance;
|
||||
}
|
||||
|
||||
/* static */
|
||||
const ColumnInterleaved3D& ColumnInterleaved3D::getInstance(float ipd)
|
||||
{
|
||||
static ColumnInterleaved3D instance(ipd);
|
||||
return instance;
|
||||
}
|
||||
|
||||
/* static */
|
||||
const RowInterleaved3D& RowInterleaved3D::getInstance(float ipd)
|
||||
{
|
||||
static RowInterleaved3D instance(ipd);
|
||||
return instance;
|
||||
}
|
||||
|
||||
static void prepareInterleavedPresent(FPresentShaderBase& shader)
|
||||
{
|
||||
GLRenderer->mBuffers->BindOutputFB();
|
||||
GLRenderer->ClearBorders();
|
||||
|
||||
|
||||
// Bind each eye texture, for composition in the shader
|
||||
GLRenderer->mBuffers->BindEyeTexture(0, 0);
|
||||
GLRenderer->mBuffers->BindEyeTexture(1, 1);
|
||||
|
||||
glActiveTexture(GL_TEXTURE0);
|
||||
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST);
|
||||
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST);
|
||||
|
||||
glActiveTexture(GL_TEXTURE1);
|
||||
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST);
|
||||
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST);
|
||||
|
||||
const IntRect& box = screen->mOutputLetterbox;
|
||||
glViewport(box.left, box.top, box.width, box.height);
|
||||
|
||||
shader.Bind(NOQUEUE);
|
||||
|
||||
if ( GLRenderer->framebuffer->IsHWGammaActive() )
|
||||
{
|
||||
shader.Uniforms->InvGamma = 1.0f;
|
||||
shader.Uniforms->Contrast = 1.0f;
|
||||
shader.Uniforms->Brightness = 0.0f;
|
||||
shader.Uniforms->Saturation = 1.0f;
|
||||
}
|
||||
else
|
||||
{
|
||||
shader.Uniforms->InvGamma = 1.0f / clamp<float>(Gamma, 0.1f, 4.f);
|
||||
shader.Uniforms->Contrast = clamp<float>(vid_contrast, 0.1f, 3.f);
|
||||
shader.Uniforms->Brightness = clamp<float>(vid_brightness, -0.8f, 0.8f);
|
||||
shader.Uniforms->Saturation = clamp<float>(vid_saturation, -15.0f, 15.0f);
|
||||
shader.Uniforms->GrayFormula = static_cast<int>(gl_satformula);
|
||||
}
|
||||
shader.Uniforms->Scale = {
|
||||
screen->mScreenViewport.width / (float)GLRenderer->mBuffers->GetWidth(),
|
||||
screen->mScreenViewport.height / (float)GLRenderer->mBuffers->GetHeight()
|
||||
};
|
||||
shader.Uniforms.Set();
|
||||
}
|
||||
|
||||
// fixme: I don't know how to get absolute window position on Mac and Linux
|
||||
// fixme: I don't know how to get window border decoration size anywhere
|
||||
// So for now I'll hard code the border effect on my test machine.
|
||||
// Workaround for others is to fuss with vr_swap_eyes CVAR until it looks right.
|
||||
// Presumably the top/left window border on my test machine has an odd number of pixels
|
||||
// in the horizontal direction, and an even number in the vertical direction.
|
||||
#define WINDOW_BORDER_HORIZONTAL_PARITY 1
|
||||
#define WINDOW_BORDER_VERTICAL_PARITY 0
|
||||
|
||||
void CheckerInterleaved3D::Present() const
|
||||
{
|
||||
FGLPostProcessState savedState;
|
||||
savedState.SaveTextureBindings(2);
|
||||
prepareInterleavedPresent(*GLRenderer->mPresent3dCheckerShader);
|
||||
|
||||
// Compute absolute offset from top of screen to top of current display window
|
||||
// because we need screen-relative, not window-relative, scan line parity
|
||||
int windowVOffset = 0;
|
||||
int windowHOffset = 0;
|
||||
|
||||
#ifdef _WIN32
|
||||
/* this needs to be done differently!
|
||||
if (!fullscreen) {
|
||||
I_SaveWindowedPos(); // update win_y CVAR
|
||||
windowHOffset = (win_x + WINDOW_BORDER_HORIZONTAL_PARITY) % 2;
|
||||
windowVOffset = (win_y + WINDOW_BORDER_VERTICAL_PARITY) % 2;
|
||||
}
|
||||
*/
|
||||
#endif // _WIN32
|
||||
|
||||
GLRenderer->mPresent3dCheckerShader->Uniforms->WindowPositionParity =
|
||||
(windowVOffset
|
||||
+ windowHOffset
|
||||
+ screen->mOutputLetterbox.height + 1 // +1 because of origin at bottom
|
||||
) % 2; // because we want the top pixel offset, but gl_FragCoord.y is the bottom pixel offset
|
||||
|
||||
GLRenderer->mPresent3dCheckerShader->Uniforms.Set();
|
||||
GLRenderer->RenderScreenQuad();
|
||||
}
|
||||
|
||||
void s3d::CheckerInterleaved3D::AdjustViewports() const
|
||||
{
|
||||
// decrease the total pixel count by 2, but keep the same aspect ratio
|
||||
const float sqrt2 = 1.41421356237f;
|
||||
// Change size of renderbuffer, and align to screen
|
||||
screen->mSceneViewport.height /= sqrt2;
|
||||
screen->mSceneViewport.top /= sqrt2;
|
||||
screen->mSceneViewport.width /= sqrt2;
|
||||
screen->mSceneViewport.left /= sqrt2;
|
||||
|
||||
screen->mScreenViewport.height /= sqrt2;
|
||||
screen->mScreenViewport.top /= sqrt2;
|
||||
screen->mScreenViewport.width /= sqrt2;
|
||||
screen->mScreenViewport.left /= sqrt2;
|
||||
}
|
||||
|
||||
void ColumnInterleaved3D::Present() const
|
||||
{
|
||||
FGLPostProcessState savedState;
|
||||
savedState.SaveTextureBindings(2);
|
||||
prepareInterleavedPresent(*GLRenderer->mPresent3dColumnShader);
|
||||
|
||||
// Compute absolute offset from top of screen to top of current display window
|
||||
// because we need screen-relative, not window-relative, scan line parity
|
||||
int windowHOffset = 0;
|
||||
|
||||
#ifdef _WIN32
|
||||
/* this needs to be done differently!
|
||||
if (!fullscreen) {
|
||||
I_SaveWindowedPos(); // update win_y CVAR
|
||||
windowHOffset = (win_x + WINDOW_BORDER_HORIZONTAL_PARITY) % 2;
|
||||
}
|
||||
*/
|
||||
#endif // _WIN32
|
||||
|
||||
GLRenderer->mPresent3dColumnShader->Uniforms->WindowPositionParity = windowHOffset;
|
||||
GLRenderer->mPresent3dColumnShader->Uniforms.Set();
|
||||
|
||||
GLRenderer->RenderScreenQuad();
|
||||
}
|
||||
|
||||
void RowInterleaved3D::Present() const
|
||||
{
|
||||
FGLPostProcessState savedState;
|
||||
savedState.SaveTextureBindings(2);
|
||||
prepareInterleavedPresent(*GLRenderer->mPresent3dRowShader);
|
||||
|
||||
// Compute absolute offset from top of screen to top of current display window
|
||||
// because we need screen-relative, not window-relative, scan line parity
|
||||
int windowVOffset = 0;
|
||||
|
||||
#ifdef _WIN32
|
||||
/* this needs to be done differently!
|
||||
if (! fullscreen) {
|
||||
I_SaveWindowedPos(); // update win_y CVAR
|
||||
windowVOffset = (win_y + WINDOW_BORDER_VERTICAL_PARITY) % 2;
|
||||
}
|
||||
*/
|
||||
#endif // _WIN32
|
||||
|
||||
GLRenderer->mPresent3dRowShader->Uniforms->WindowPositionParity =
|
||||
(windowVOffset
|
||||
+ screen->mOutputLetterbox.height + 1 // +1 because of origin at bottom
|
||||
) % 2;
|
||||
|
||||
GLRenderer->mPresent3dRowShader->Uniforms.Set();
|
||||
GLRenderer->RenderScreenQuad();
|
||||
}
|
||||
|
||||
|
||||
} /* namespace s3d */
|
|
@ -1,75 +0,0 @@
|
|||
/*
|
||||
** gl_interleaved3d.h
|
||||
** Interleaved stereoscopic 3D modes for GZDoom
|
||||
**
|
||||
**---------------------------------------------------------------------------
|
||||
** Copyright 2016 Christopher Bruns
|
||||
** All rights reserved.
|
||||
**
|
||||
** Redistribution and use in source and binary forms, with or without
|
||||
** modification, are permitted provided that the following conditions
|
||||
** are met:
|
||||
**
|
||||
** 1. Redistributions of source code must retain the above copyright
|
||||
** notice, this list of conditions and the following disclaimer.
|
||||
** 2. Redistributions in binary form must reproduce the above copyright
|
||||
** notice, this list of conditions and the following disclaimer in the
|
||||
** documentation and/or other materials provided with the distribution.
|
||||
** 3. The name of the author may not be used to endorse or promote products
|
||||
** derived from this software without specific prior written permission.
|
||||
**
|
||||
** THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
|
||||
** IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
|
||||
** OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
|
||||
** IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
|
||||
** INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
|
||||
** NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
|
||||
** DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
|
||||
** THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
|
||||
** (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
|
||||
** THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
**---------------------------------------------------------------------------
|
||||
**
|
||||
**
|
||||
*/
|
||||
|
||||
#ifndef GL_INTERLEAVED3D_H_
|
||||
#define GL_INTERLEAVED3D_H_
|
||||
|
||||
#include "gl_stereo3d.h"
|
||||
#include "gl_stereo_leftright.h"
|
||||
#include "gl_sidebyside3d.h"
|
||||
#include "gl_load/gl_system.h"
|
||||
#include "gl/renderer/gl_renderstate.h"
|
||||
|
||||
namespace s3d {
|
||||
|
||||
class CheckerInterleaved3D : public SideBySideSquished
|
||||
{
|
||||
public:
|
||||
static const CheckerInterleaved3D& getInstance(float ipd);
|
||||
CheckerInterleaved3D(double ipdMeters) : SideBySideSquished(ipdMeters) {}
|
||||
void Present() const override;
|
||||
void AdjustViewports() const override;
|
||||
};
|
||||
|
||||
class ColumnInterleaved3D : public SideBySideSquished
|
||||
{
|
||||
public:
|
||||
static const ColumnInterleaved3D& getInstance(float ipd);
|
||||
ColumnInterleaved3D(double ipdMeters) : SideBySideSquished(ipdMeters) {}
|
||||
void Present() const override;
|
||||
};
|
||||
|
||||
class RowInterleaved3D : public TopBottom3D
|
||||
{
|
||||
public:
|
||||
static const RowInterleaved3D& getInstance(float ipd);
|
||||
RowInterleaved3D(double ipdMeters) : TopBottom3D(ipdMeters) {}
|
||||
void Present() const override;
|
||||
};
|
||||
|
||||
} /* namespace s3d */
|
||||
|
||||
|
||||
#endif /* GL_INTERLEAVED3D_H_ */
|
|
@ -1,115 +0,0 @@
|
|||
//
|
||||
//---------------------------------------------------------------------------
|
||||
//
|
||||
// Copyright(C) 2015 Christopher Bruns
|
||||
// All rights reserved.
|
||||
//
|
||||
// This program is free software: you can redistribute it and/or modify
|
||||
// it under the terms of the GNU Lesser General Public License as published by
|
||||
// the Free Software Foundation, either version 3 of the License, or
|
||||
// (at your option) any later version.
|
||||
//
|
||||
// This program is distributed in the hope that it will be useful,
|
||||
// but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
// GNU Lesser General Public License for more details.
|
||||
//
|
||||
// You should have received a copy of the GNU Lesser General Public License
|
||||
// along with this program. If not, see http://www.gnu.org/licenses/
|
||||
//
|
||||
//--------------------------------------------------------------------------
|
||||
//
|
||||
/*
|
||||
** gl_quadstereo.cpp
|
||||
** Quad-buffered OpenGL stereoscopic 3D mode for GZDoom
|
||||
**
|
||||
*/
|
||||
|
||||
#include "gl_quadstereo.h"
|
||||
#include "gl/renderer/gl_renderbuffers.h"
|
||||
|
||||
namespace s3d {
|
||||
|
||||
QuadStereo::QuadStereo(double ipdMeters)
|
||||
: leftEye(ipdMeters), rightEye(ipdMeters)
|
||||
{
|
||||
// Check whether quad-buffered stereo is supported in the current context
|
||||
// We are assuming the OpenGL context is already current at this point,
|
||||
// i.e. this constructor is called "just in time".
|
||||
|
||||
// First initialize to mono-ish initial state
|
||||
bQuadStereoSupported = leftEye.bQuadStereoSupported = rightEye.bQuadStereoSupported = false;
|
||||
eye_ptrs.Push(&leftEye); // We ALWAYS want to show at least this one view...
|
||||
// We will possibly advance to true stereo mode in the Setup() method...
|
||||
}
|
||||
|
||||
// Sometimes the stereo render context is not ready immediately at start up
|
||||
/* private */
|
||||
void QuadStereo::checkInitialRenderContextState()
|
||||
{
|
||||
// Keep trying until we see at least one good OpenGL context to render to
|
||||
static bool bDecentContextWasFound = false;
|
||||
static int contextCheckCount = 0;
|
||||
if ( (! bDecentContextWasFound) && (contextCheckCount < 200) )
|
||||
{
|
||||
contextCheckCount += 1;
|
||||
glBindFramebuffer(GL_DRAW_FRAMEBUFFER, 0); // This question is about the main screen display context
|
||||
GLboolean supportsStereo, supportsBuffered;
|
||||
glGetBooleanv(GL_DOUBLEBUFFER, &supportsBuffered);
|
||||
if (supportsBuffered) // Finally, a useful OpenGL context
|
||||
{
|
||||
// This block will be executed exactly ONCE during a game run
|
||||
bDecentContextWasFound = true; // now we can stop checking every frame...
|
||||
// Now check whether this context supports hardware stereo
|
||||
glGetBooleanv(GL_STEREO, &supportsStereo);
|
||||
bQuadStereoSupported = supportsStereo && supportsBuffered;
|
||||
leftEye.bQuadStereoSupported = bQuadStereoSupported;
|
||||
rightEye.bQuadStereoSupported = bQuadStereoSupported;
|
||||
if (bQuadStereoSupported)
|
||||
eye_ptrs.Push(&rightEye); // Use the other eye too, if we can do stereo
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void QuadStereo::Present() const
|
||||
{
|
||||
if (bQuadStereoSupported)
|
||||
{
|
||||
GLRenderer->mBuffers->BindOutputFB();
|
||||
|
||||
glDrawBuffer(GL_BACK_LEFT);
|
||||
GLRenderer->ClearBorders();
|
||||
GLRenderer->mBuffers->BindEyeTexture(0, 0);
|
||||
GLRenderer->DrawPresentTexture(screen->mOutputLetterbox, true);
|
||||
|
||||
glDrawBuffer(GL_BACK_RIGHT);
|
||||
GLRenderer->ClearBorders();
|
||||
GLRenderer->mBuffers->BindEyeTexture(1, 0);
|
||||
GLRenderer->DrawPresentTexture(screen->mOutputLetterbox, true);
|
||||
|
||||
glDrawBuffer(GL_BACK);
|
||||
}
|
||||
else
|
||||
{
|
||||
GLRenderer->mBuffers->BindOutputFB();
|
||||
GLRenderer->ClearBorders();
|
||||
GLRenderer->mBuffers->BindEyeTexture(0, 0);
|
||||
GLRenderer->DrawPresentTexture(screen->mOutputLetterbox, true);
|
||||
}
|
||||
}
|
||||
|
||||
void QuadStereo::SetUp() const
|
||||
{
|
||||
Stereo3DMode::SetUp();
|
||||
// Maybe advance to true stereo mode (ONCE), after the stereo context is finally ready
|
||||
const_cast<QuadStereo*>(this)->checkInitialRenderContextState();
|
||||
}
|
||||
|
||||
/* static */
|
||||
const QuadStereo& QuadStereo::getInstance(float ipd)
|
||||
{
|
||||
static QuadStereo instance(ipd);
|
||||
return instance;
|
||||
}
|
||||
|
||||
} /* namespace s3d */
|
|
@ -1,77 +0,0 @@
|
|||
//
|
||||
//---------------------------------------------------------------------------
|
||||
//
|
||||
// Copyright(C) 2015 Christopher Bruns
|
||||
// All rights reserved.
|
||||
//
|
||||
// This program is free software: you can redistribute it and/or modify
|
||||
// it under the terms of the GNU Lesser General Public License as published by
|
||||
// the Free Software Foundation, either version 3 of the License, or
|
||||
// (at your option) any later version.
|
||||
//
|
||||
// This program is distributed in the hope that it will be useful,
|
||||
// but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
// GNU Lesser General Public License for more details.
|
||||
//
|
||||
// You should have received a copy of the GNU Lesser General Public License
|
||||
// along with this program. If not, see http://www.gnu.org/licenses/
|
||||
//
|
||||
//--------------------------------------------------------------------------
|
||||
//
|
||||
/*
|
||||
** gl_quadstereo.h
|
||||
** Quad-buffered OpenGL stereoscopic 3D mode for GZDoom
|
||||
**
|
||||
*/
|
||||
|
||||
#ifndef GL_QUADSTEREO_H_
|
||||
#define GL_QUADSTEREO_H_
|
||||
|
||||
#include "gl_stereo3d.h"
|
||||
#include "gl_stereo_leftright.h"
|
||||
#include "gl_load/gl_system.h"
|
||||
|
||||
namespace s3d {
|
||||
|
||||
|
||||
class QuadStereoLeftPose : public LeftEyePose
|
||||
{
|
||||
public:
|
||||
QuadStereoLeftPose(float ipd) : LeftEyePose(ipd), bQuadStereoSupported(false) {}
|
||||
bool bQuadStereoSupported;
|
||||
};
|
||||
|
||||
class QuadStereoRightPose : public RightEyePose
|
||||
{
|
||||
public:
|
||||
QuadStereoRightPose(float ipd) : RightEyePose(ipd), bQuadStereoSupported(false){}
|
||||
bool bQuadStereoSupported;
|
||||
};
|
||||
|
||||
// To use Quad-buffered stereo mode with nvidia 3d vision glasses,
|
||||
// you must either:
|
||||
// A) be using a Quadro series video card, OR
|
||||
//
|
||||
// B) be using nvidia driver version 314.07 or later
|
||||
// AND have your monitor set to 120 Hz refresh rate
|
||||
// AND have gzdoom in true full screen mode
|
||||
class QuadStereo : public Stereo3DMode
|
||||
{
|
||||
public:
|
||||
QuadStereo(double ipdMeters);
|
||||
void Present() const override;
|
||||
void SetUp() const override;
|
||||
static const QuadStereo& getInstance(float ipd);
|
||||
private:
|
||||
QuadStereoLeftPose leftEye;
|
||||
QuadStereoRightPose rightEye;
|
||||
bool bQuadStereoSupported;
|
||||
void checkInitialRenderContextState();
|
||||
};
|
||||
|
||||
|
||||
} /* namespace s3d */
|
||||
|
||||
|
||||
#endif /* GL_QUADSTEREO_H_ */
|
|
@ -1,149 +0,0 @@
|
|||
/*
|
||||
** gl_sidebyside3d.cpp
|
||||
** Mosaic image stereoscopic 3D modes for GZDoom
|
||||
**
|
||||
**---------------------------------------------------------------------------
|
||||
** Copyright 2016 Christopher Bruns
|
||||
** All rights reserved.
|
||||
**
|
||||
** Redistribution and use in source and binary forms, with or without
|
||||
** modification, are permitted provided that the following conditions
|
||||
** are met:
|
||||
**
|
||||
** 1. Redistributions of source code must retain the above copyright
|
||||
** notice, this list of conditions and the following disclaimer.
|
||||
** 2. Redistributions in binary form must reproduce the above copyright
|
||||
** notice, this list of conditions and the following disclaimer in the
|
||||
** documentation and/or other materials provided with the distribution.
|
||||
** 3. The name of the author may not be used to endorse or promote products
|
||||
** derived from this software without specific prior written permission.
|
||||
**
|
||||
** THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
|
||||
** IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
|
||||
** OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
|
||||
** IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
|
||||
** INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
|
||||
** NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
|
||||
** DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
|
||||
** THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
|
||||
** (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
|
||||
** THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
**---------------------------------------------------------------------------
|
||||
**
|
||||
**
|
||||
*/
|
||||
|
||||
#include "gl_sidebyside3d.h"
|
||||
#include "gl/renderer/gl_renderbuffers.h"
|
||||
|
||||
namespace s3d {
|
||||
|
||||
void SideBySideBase::Present() const
|
||||
{
|
||||
GLRenderer->mBuffers->BindOutputFB();
|
||||
GLRenderer->ClearBorders();
|
||||
|
||||
// Compute screen regions to use for left and right eye views
|
||||
int leftWidth = screen->mOutputLetterbox.width / 2;
|
||||
int rightWidth = screen->mOutputLetterbox.width - leftWidth;
|
||||
IntRect leftHalfScreen = screen->mOutputLetterbox;
|
||||
leftHalfScreen.width = leftWidth;
|
||||
IntRect rightHalfScreen = screen->mOutputLetterbox;
|
||||
rightHalfScreen.width = rightWidth;
|
||||
rightHalfScreen.left += leftWidth;
|
||||
|
||||
GLRenderer->mBuffers->BindEyeTexture(0, 0);
|
||||
GLRenderer->DrawPresentTexture(leftHalfScreen, true);
|
||||
|
||||
GLRenderer->mBuffers->BindEyeTexture(1, 0);
|
||||
GLRenderer->DrawPresentTexture(rightHalfScreen, true);
|
||||
}
|
||||
|
||||
// AdjustViewports() is called from within FLGRenderer::SetOutputViewport(...)
|
||||
void SideBySideBase::AdjustViewports() const
|
||||
{
|
||||
// Change size of renderbuffer, and align to screen
|
||||
screen->mSceneViewport.width /= 2;
|
||||
screen->mSceneViewport.left /= 2;
|
||||
screen->mScreenViewport.width /= 2;
|
||||
screen->mScreenViewport.left /= 2;
|
||||
}
|
||||
|
||||
/* static */
|
||||
const SideBySideSquished& SideBySideSquished::getInstance(float ipd)
|
||||
{
|
||||
static SideBySideSquished instance(ipd);
|
||||
return instance;
|
||||
}
|
||||
|
||||
SideBySideSquished::SideBySideSquished(double ipdMeters)
|
||||
: leftEye(ipdMeters), rightEye(ipdMeters)
|
||||
{
|
||||
eye_ptrs.Push(&leftEye);
|
||||
eye_ptrs.Push(&rightEye);
|
||||
}
|
||||
|
||||
/* static */
|
||||
const SideBySideFull& SideBySideFull::getInstance(float ipd)
|
||||
{
|
||||
static SideBySideFull instance(ipd);
|
||||
return instance;
|
||||
}
|
||||
|
||||
SideBySideFull::SideBySideFull(double ipdMeters)
|
||||
: leftEye(ipdMeters), rightEye(ipdMeters)
|
||||
{
|
||||
eye_ptrs.Push(&leftEye);
|
||||
eye_ptrs.Push(&rightEye);
|
||||
}
|
||||
|
||||
/* virtual */
|
||||
void SideBySideFull::AdjustPlayerSprites() const /* override */
|
||||
{
|
||||
// Show weapon at double width, so it would appear normal width after rescaling
|
||||
int w = screen->mScreenViewport.width;
|
||||
int h = screen->mScreenViewport.height;
|
||||
gl_RenderState.mProjectionMatrix.ortho(w/2, w + w/2, h, 0, -1.0f, 1.0f);
|
||||
gl_RenderState.ApplyMatrices();
|
||||
}
|
||||
|
||||
/* static */
|
||||
const TopBottom3D& TopBottom3D::getInstance(float ipd)
|
||||
{
|
||||
static TopBottom3D instance(ipd);
|
||||
return instance;
|
||||
}
|
||||
|
||||
void TopBottom3D::Present() const
|
||||
{
|
||||
GLRenderer->mBuffers->BindOutputFB();
|
||||
GLRenderer->ClearBorders();
|
||||
|
||||
// Compute screen regions to use for left and right eye views
|
||||
int topHeight = screen->mOutputLetterbox.height / 2;
|
||||
int bottomHeight = screen->mOutputLetterbox.height - topHeight;
|
||||
IntRect topHalfScreen = screen->mOutputLetterbox;
|
||||
topHalfScreen.height = topHeight;
|
||||
topHalfScreen.top = topHeight;
|
||||
IntRect bottomHalfScreen = screen->mOutputLetterbox;
|
||||
bottomHalfScreen.height = bottomHeight;
|
||||
bottomHalfScreen.top = 0;
|
||||
|
||||
GLRenderer->mBuffers->BindEyeTexture(0, 0);
|
||||
GLRenderer->DrawPresentTexture(topHalfScreen, true);
|
||||
|
||||
GLRenderer->mBuffers->BindEyeTexture(1, 0);
|
||||
GLRenderer->DrawPresentTexture(bottomHalfScreen, true);
|
||||
}
|
||||
|
||||
// AdjustViewports() is called from within FLGRenderer::SetOutputViewport(...)
|
||||
void TopBottom3D::AdjustViewports() const
|
||||
{
|
||||
// Change size of renderbuffer, and align to screen
|
||||
screen->mSceneViewport.height /= 2;
|
||||
screen->mSceneViewport.top /= 2;
|
||||
screen->mScreenViewport.height /= 2;
|
||||
screen->mScreenViewport.top /= 2;
|
||||
}
|
||||
|
||||
} /* namespace s3d */
|
|
@ -1,103 +0,0 @@
|
|||
/*
|
||||
** gl_sidebyside3d.h
|
||||
** Mosaic image stereoscopic 3D modes for GZDoom
|
||||
**
|
||||
**---------------------------------------------------------------------------
|
||||
** Copyright 2016 Christopher Bruns
|
||||
** All rights reserved.
|
||||
**
|
||||
** Redistribution and use in source and binary forms, with or without
|
||||
** modification, are permitted provided that the following conditions
|
||||
** are met:
|
||||
**
|
||||
** 1. Redistributions of source code must retain the above copyright
|
||||
** notice, this list of conditions and the following disclaimer.
|
||||
** 2. Redistributions in binary form must reproduce the above copyright
|
||||
** notice, this list of conditions and the following disclaimer in the
|
||||
** documentation and/or other materials provided with the distribution.
|
||||
** 3. The name of the author may not be used to endorse or promote products
|
||||
** derived from this software without specific prior written permission.
|
||||
**
|
||||
** THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
|
||||
** IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
|
||||
** OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
|
||||
** IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
|
||||
** INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
|
||||
** NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
|
||||
** DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
|
||||
** THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
|
||||
** (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
|
||||
** THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
**---------------------------------------------------------------------------
|
||||
**
|
||||
**
|
||||
*/
|
||||
|
||||
#ifndef GL_SIDEBYSIDE3D_H_
|
||||
#define GL_SIDEBYSIDE3D_H_
|
||||
|
||||
#include "gl_stereo3d.h"
|
||||
#include "gl_stereo_leftright.h"
|
||||
#include "gl_load/gl_system.h"
|
||||
#include "gl/renderer/gl_renderstate.h"
|
||||
|
||||
|
||||
namespace s3d {
|
||||
|
||||
class SideBySideBase : public Stereo3DMode
|
||||
{
|
||||
public:
|
||||
void Present() const override;
|
||||
virtual void AdjustViewports() const override;
|
||||
};
|
||||
|
||||
class SideBySideSquished : public SideBySideBase
|
||||
{
|
||||
public:
|
||||
static const SideBySideSquished& getInstance(float ipd);
|
||||
SideBySideSquished(double ipdMeters);
|
||||
private:
|
||||
LeftEyePose leftEye;
|
||||
RightEyePose rightEye;
|
||||
};
|
||||
|
||||
class SBSFLeftEyePose : public LeftEyePose {
|
||||
public:
|
||||
SBSFLeftEyePose(double ipdMeters) : LeftEyePose(ipdMeters) {}
|
||||
virtual VSMatrix GetProjection(float fov, float aspectRatio, float fovRatio) const override {
|
||||
return LeftEyePose::GetProjection(fov, 0.5f * aspectRatio, fovRatio);
|
||||
}
|
||||
};
|
||||
|
||||
class SBSFRightEyePose : public RightEyePose {
|
||||
public:
|
||||
SBSFRightEyePose(double ipdMeters) : RightEyePose(ipdMeters) {}
|
||||
virtual VSMatrix GetProjection(float fov, float aspectRatio, float fovRatio) const override {
|
||||
return RightEyePose::GetProjection(fov, 0.5f * aspectRatio, fovRatio);
|
||||
}
|
||||
};
|
||||
|
||||
class SideBySideFull : public SideBySideBase
|
||||
{
|
||||
public:
|
||||
static const SideBySideFull& getInstance(float ipd);
|
||||
SideBySideFull(double ipdMeters);
|
||||
virtual void AdjustPlayerSprites() const override;
|
||||
private:
|
||||
SBSFLeftEyePose leftEye;
|
||||
SBSFRightEyePose rightEye;
|
||||
};
|
||||
|
||||
class TopBottom3D : public SideBySideSquished
|
||||
{
|
||||
public:
|
||||
static const TopBottom3D& getInstance(float ipd);
|
||||
TopBottom3D(double ipdMeters) : SideBySideSquished(ipdMeters) {}
|
||||
void Present() const override;
|
||||
virtual void AdjustViewports() const override;
|
||||
};
|
||||
|
||||
} /* namespace s3d */
|
||||
|
||||
|
||||
#endif /* GL_SIDEBYSIDE3D_H_ */
|
|
@ -1,82 +0,0 @@
|
|||
//
|
||||
//---------------------------------------------------------------------------
|
||||
//
|
||||
// Copyright(C) 2015 Christopher Bruns
|
||||
// All rights reserved.
|
||||
//
|
||||
// This program is free software: you can redistribute it and/or modify
|
||||
// it under the terms of the GNU Lesser General Public License as published by
|
||||
// the Free Software Foundation, either version 3 of the License, or
|
||||
// (at your option) any later version.
|
||||
//
|
||||
// This program is distributed in the hope that it will be useful,
|
||||
// but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
// GNU Lesser General Public License for more details.
|
||||
//
|
||||
// You should have received a copy of the GNU Lesser General Public License
|
||||
// along with this program. If not, see http://www.gnu.org/licenses/
|
||||
//
|
||||
//--------------------------------------------------------------------------
|
||||
//
|
||||
/*
|
||||
** gl_stereo3d.cpp
|
||||
** Stereoscopic 3D API
|
||||
**
|
||||
*/
|
||||
|
||||
#include "gl_load/gl_system.h"
|
||||
#include "gl/stereo3d/gl_stereo3d.h"
|
||||
|
||||
namespace s3d {
|
||||
|
||||
|
||||
/* virtual */
|
||||
VSMatrix EyePose::GetProjection(float fov, float aspectRatio, float fovRatio) const
|
||||
{
|
||||
VSMatrix result;
|
||||
|
||||
// Lifted from gl_scene.cpp FGLRenderer::SetProjection()
|
||||
float fovy = (float)(2 * RAD2DEG(atan(tan(DEG2RAD(fov) / 2) / fovRatio)));
|
||||
result.perspective(fovy, aspectRatio, FGLRenderer::GetZNear(), FGLRenderer::GetZFar());
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
/* virtual */
|
||||
Viewport EyePose::GetViewport(const Viewport& fullViewport) const
|
||||
{
|
||||
return fullViewport;
|
||||
}
|
||||
|
||||
|
||||
/* virtual */
|
||||
void EyePose::GetViewShift(float yaw, float outViewShift[3]) const
|
||||
{
|
||||
// pass-through for Mono view
|
||||
outViewShift[0] = 0;
|
||||
outViewShift[1] = 0;
|
||||
outViewShift[2] = 0;
|
||||
}
|
||||
|
||||
|
||||
Stereo3DMode::Stereo3DMode()
|
||||
{
|
||||
}
|
||||
|
||||
Stereo3DMode::~Stereo3DMode()
|
||||
{
|
||||
}
|
||||
|
||||
// Avoid static initialization order fiasco by declaring first Mode type (Mono) here in the
|
||||
// same source file as Stereo3DMode::getCurrentMode()
|
||||
// https://isocpp.org/wiki/faq/ctors#static-init-order
|
||||
|
||||
/* static */
|
||||
const MonoView& MonoView::getInstance()
|
||||
{
|
||||
static MonoView instance;
|
||||
return instance;
|
||||
}
|
||||
|
||||
} /* namespace s3d */
|
|
@ -1,115 +0,0 @@
|
|||
//
|
||||
//---------------------------------------------------------------------------
|
||||
//
|
||||
// Copyright(C) 2015 Christopher Bruns
|
||||
// All rights reserved.
|
||||
//
|
||||
// This program is free software: you can redistribute it and/or modify
|
||||
// it under the terms of the GNU Lesser General Public License as published by
|
||||
// the Free Software Foundation, either version 3 of the License, or
|
||||
// (at your option) any later version.
|
||||
//
|
||||
// This program is distributed in the hope that it will be useful,
|
||||
// but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
// GNU Lesser General Public License for more details.
|
||||
//
|
||||
// You should have received a copy of the GNU Lesser General Public License
|
||||
// along with this program. If not, see http://www.gnu.org/licenses/
|
||||
//
|
||||
//--------------------------------------------------------------------------
|
||||
//
|
||||
/*
|
||||
** gl_stereo3d.h
|
||||
** Stereoscopic 3D API
|
||||
**
|
||||
*/
|
||||
|
||||
#ifndef GL_STEREO3D_H_
|
||||
#define GL_STEREO3D_H_
|
||||
|
||||
#include <cstring> // needed for memcpy on linux, which is needed by VSMatrix copy ctor
|
||||
#include "tarray.h"
|
||||
#include "r_data/matrix.h"
|
||||
#include "gl/renderer/gl_renderer.h"
|
||||
|
||||
|
||||
/* stereoscopic 3D API */
|
||||
namespace s3d {
|
||||
|
||||
|
||||
/* Subregion of current display window */
|
||||
class Viewport
|
||||
{
|
||||
public:
|
||||
int x, y;
|
||||
int width, height;
|
||||
};
|
||||
|
||||
|
||||
/* Viewpoint of one eye */
|
||||
class EyePose
|
||||
{
|
||||
public:
|
||||
EyePose() {}
|
||||
virtual ~EyePose() {}
|
||||
virtual VSMatrix GetProjection(float fov, float aspectRatio, float fovRatio) const;
|
||||
virtual Viewport GetViewport(const Viewport& fullViewport) const;
|
||||
virtual void GetViewShift(float yaw, float outViewShift[3]) const;
|
||||
virtual void SetUp() const {};
|
||||
virtual void TearDown() const {};
|
||||
};
|
||||
|
||||
|
||||
/* Base class for stereoscopic 3D rendering modes */
|
||||
class Stereo3DMode
|
||||
{
|
||||
public:
|
||||
/* static methods for managing the selected stereoscopic view state */
|
||||
static const Stereo3DMode& getCurrentMode();
|
||||
static const Stereo3DMode& getMonoMode();
|
||||
|
||||
Stereo3DMode();
|
||||
virtual ~Stereo3DMode();
|
||||
virtual int eye_count() const { return eye_ptrs.Size(); }
|
||||
virtual const EyePose * getEyePose(int ix) const { return eye_ptrs(ix); }
|
||||
|
||||
/* hooks for setup and cleanup operations for each stereo mode */
|
||||
virtual void SetUp() const {};
|
||||
virtual void TearDown() const {};
|
||||
|
||||
virtual bool IsMono() const { return false; }
|
||||
virtual void AdjustViewports() const {};
|
||||
virtual void AdjustPlayerSprites() const {};
|
||||
virtual void Present() const = 0;
|
||||
|
||||
protected:
|
||||
TArray<const EyePose *> eye_ptrs;
|
||||
|
||||
private:
|
||||
static Stereo3DMode const * currentStereo3DMode;
|
||||
static void setCurrentMode(const Stereo3DMode& mode);
|
||||
};
|
||||
|
||||
|
||||
/**
|
||||
* Ordinary non-3D rendering
|
||||
*/
|
||||
class MonoView : public Stereo3DMode
|
||||
{
|
||||
public:
|
||||
static const MonoView& getInstance();
|
||||
|
||||
bool IsMono() const override { return true; }
|
||||
void Present() const override { }
|
||||
|
||||
protected:
|
||||
MonoView() { eye_ptrs.Push(¢ralEye); }
|
||||
EyePose centralEye;
|
||||
};
|
||||
|
||||
|
||||
} /* namespace st3d */
|
||||
|
||||
|
||||
#endif /* GL_STEREO3D_H_ */
|
|
@ -1,127 +0,0 @@
|
|||
//
|
||||
//---------------------------------------------------------------------------
|
||||
//
|
||||
// Copyright(C) 2015 Christopher Bruns
|
||||
// All rights reserved.
|
||||
//
|
||||
// This program is free software: you can redistribute it and/or modify
|
||||
// it under the terms of the GNU Lesser General Public License as published by
|
||||
// the Free Software Foundation, either version 3 of the License, or
|
||||
// (at your option) any later version.
|
||||
//
|
||||
// This program is distributed in the hope that it will be useful,
|
||||
// but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
// GNU Lesser General Public License for more details.
|
||||
//
|
||||
// You should have received a copy of the GNU Lesser General Public License
|
||||
// along with this program. If not, see http://www.gnu.org/licenses/
|
||||
//
|
||||
//--------------------------------------------------------------------------
|
||||
//
|
||||
/*
|
||||
** gl_stereo_cvars.cpp
|
||||
** Console variables related to stereoscopic 3D in GZDoom
|
||||
**
|
||||
*/
|
||||
|
||||
#include "gl/stereo3d/gl_stereo3d.h"
|
||||
#include "gl/stereo3d/gl_stereo_leftright.h"
|
||||
#include "gl/stereo3d/gl_anaglyph.h"
|
||||
#include "gl/stereo3d/gl_quadstereo.h"
|
||||
#include "gl/stereo3d/gl_sidebyside3d.h"
|
||||
#include "gl/stereo3d/gl_interleaved3d.h"
|
||||
#include "version.h"
|
||||
|
||||
// Set up 3D-specific console variables:
|
||||
CVAR(Int, vr_mode, 0, CVAR_GLOBALCONFIG)
|
||||
|
||||
// switch left and right eye views
|
||||
CVAR(Bool, vr_swap_eyes, false, CVAR_GLOBALCONFIG)
|
||||
|
||||
// intraocular distance in meters
|
||||
CVAR(Float, vr_ipd, 0.062f, CVAR_ARCHIVE|CVAR_GLOBALCONFIG) // METERS
|
||||
|
||||
// distance between viewer and the display screen
|
||||
CVAR(Float, vr_screendist, 0.80f, CVAR_ARCHIVE | CVAR_GLOBALCONFIG) // METERS
|
||||
|
||||
// default conversion between (vertical) DOOM units and meters
|
||||
CVAR(Float, vr_hunits_per_meter, 41.0f, CVAR_ARCHIVE | CVAR_GLOBALCONFIG) // METERS
|
||||
|
||||
// Manage changing of 3D modes:
|
||||
namespace s3d {
|
||||
|
||||
// Initialize static member
|
||||
Stereo3DMode const * Stereo3DMode::currentStereo3DMode = 0; // "nullptr" not resolved on linux (presumably not C++11)
|
||||
|
||||
/* static */
|
||||
void Stereo3DMode::setCurrentMode(const Stereo3DMode& mode) {
|
||||
Stereo3DMode::currentStereo3DMode = &mode;
|
||||
}
|
||||
|
||||
/* static */
|
||||
const Stereo3DMode& Stereo3DMode::getCurrentMode()
|
||||
{
|
||||
// NOTE: Ensure that these vr_mode values correspond to the ones in wadsrc/static/menudef.z
|
||||
switch (vr_mode)
|
||||
{
|
||||
case 1:
|
||||
setCurrentMode(GreenMagenta::getInstance(vr_ipd));
|
||||
break;
|
||||
case 2:
|
||||
setCurrentMode(RedCyan::getInstance(vr_ipd));
|
||||
break;
|
||||
case 3:
|
||||
setCurrentMode(SideBySideFull::getInstance(vr_ipd));
|
||||
break;
|
||||
case 4:
|
||||
setCurrentMode(SideBySideSquished::getInstance(vr_ipd));
|
||||
break;
|
||||
case 5:
|
||||
setCurrentMode(LeftEyeView::getInstance(vr_ipd));
|
||||
break;
|
||||
case 6:
|
||||
setCurrentMode(RightEyeView::getInstance(vr_ipd));
|
||||
break;
|
||||
case 7:
|
||||
if (screen->enable_quadbuffered) {
|
||||
setCurrentMode(QuadStereo::getInstance(vr_ipd));
|
||||
}
|
||||
else {
|
||||
setCurrentMode(MonoView::getInstance());
|
||||
}
|
||||
break;
|
||||
// TODO: 8: Oculus Rift
|
||||
case 9:
|
||||
setCurrentMode(AmberBlue::getInstance(vr_ipd));
|
||||
break;
|
||||
// TODO: 10: HTC Vive/OpenVR
|
||||
case 11:
|
||||
setCurrentMode(TopBottom3D::getInstance(vr_ipd));
|
||||
break;
|
||||
case 12:
|
||||
setCurrentMode(RowInterleaved3D::getInstance(vr_ipd));
|
||||
break;
|
||||
case 13:
|
||||
setCurrentMode(ColumnInterleaved3D::getInstance(vr_ipd));
|
||||
break;
|
||||
case 14:
|
||||
setCurrentMode(CheckerInterleaved3D::getInstance(vr_ipd));
|
||||
break;
|
||||
case 0:
|
||||
default:
|
||||
setCurrentMode(MonoView::getInstance());
|
||||
break;
|
||||
}
|
||||
return *currentStereo3DMode;
|
||||
}
|
||||
|
||||
const Stereo3DMode& Stereo3DMode::getMonoMode()
|
||||
{
|
||||
setCurrentMode(MonoView::getInstance());
|
||||
return *currentStereo3DMode;
|
||||
}
|
||||
|
||||
|
||||
} /* namespace s3d */
|
||||
|
|
@ -1,116 +0,0 @@
|
|||
//
|
||||
//---------------------------------------------------------------------------
|
||||
//
|
||||
// Copyright(C) 2015 Christopher Bruns
|
||||
// All rights reserved.
|
||||
//
|
||||
// This program is free software: you can redistribute it and/or modify
|
||||
// it under the terms of the GNU Lesser General Public License as published by
|
||||
// the Free Software Foundation, either version 3 of the License, or
|
||||
// (at your option) any later version.
|
||||
//
|
||||
// This program is distributed in the hope that it will be useful,
|
||||
// but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
// GNU Lesser General Public License for more details.
|
||||
//
|
||||
// You should have received a copy of the GNU Lesser General Public License
|
||||
// along with this program. If not, see http://www.gnu.org/licenses/
|
||||
//
|
||||
//--------------------------------------------------------------------------
|
||||
//
|
||||
/*
|
||||
** gl_stereo_leftright.cpp
|
||||
** Offsets for left and right eye views
|
||||
**
|
||||
*/
|
||||
|
||||
#include "gl_stereo_leftright.h"
|
||||
#include "vectors.h" // RAD2DEG
|
||||
#include "doomtype.h" // M_PI
|
||||
#include "hwrenderer/utility/hw_cvars.h"
|
||||
#include "gl_load/gl_system.h"
|
||||
#include "gl/renderer/gl_renderstate.h"
|
||||
#include "gl/renderer/gl_renderer.h"
|
||||
#include "gl/renderer/gl_renderbuffers.h"
|
||||
|
||||
EXTERN_CVAR(Float, vr_screendist)
|
||||
EXTERN_CVAR(Float, vr_hunits_per_meter)
|
||||
EXTERN_CVAR(Bool, vr_swap_eyes)
|
||||
|
||||
namespace s3d {
|
||||
|
||||
|
||||
/* virtual */
|
||||
VSMatrix ShiftedEyePose::GetProjection(float fov, float aspectRatio, float fovRatio) const
|
||||
{
|
||||
double zNear = 5.0;
|
||||
double zFar = 65536.0;
|
||||
|
||||
// For stereo 3D, use asymmetric frustum shift in projection matrix
|
||||
// Q: shouldn't shift vary with roll angle, at least for desktop display?
|
||||
// A: No. (lab) roll is not measured on desktop display (yet)
|
||||
double frustumShift = zNear * getShift() / vr_screendist; // meters cancel, leaving doom units
|
||||
// double frustumShift = 0; // Turning off shift for debugging
|
||||
double fH = zNear * tan(DEG2RAD(fov) / 2) / fovRatio;
|
||||
double fW = fH * aspectRatio;
|
||||
double left = -fW - frustumShift;
|
||||
double right = fW - frustumShift;
|
||||
double bottom = -fH;
|
||||
double top = fH;
|
||||
|
||||
VSMatrix result(1);
|
||||
result.frustum(left, right, bottom, top, zNear, zFar);
|
||||
return result;
|
||||
}
|
||||
|
||||
|
||||
/* virtual */
|
||||
void ShiftedEyePose::GetViewShift(float yaw, float outViewShift[3]) const
|
||||
{
|
||||
float dx = -cos(DEG2RAD(yaw)) * vr_hunits_per_meter * getShift();
|
||||
float dy = sin(DEG2RAD(yaw)) * vr_hunits_per_meter * getShift();
|
||||
outViewShift[0] = dx;
|
||||
outViewShift[1] = dy;
|
||||
outViewShift[2] = 0;
|
||||
}
|
||||
|
||||
float ShiftedEyePose::getShift() const
|
||||
{
|
||||
return vr_swap_eyes ? -shift : shift;
|
||||
}
|
||||
|
||||
/* static */
|
||||
const LeftEyeView& LeftEyeView::getInstance(float ipd)
|
||||
{
|
||||
static LeftEyeView instance(ipd);
|
||||
instance.setIpd(ipd);
|
||||
return instance;
|
||||
}
|
||||
|
||||
void LeftEyeView::Present() const
|
||||
{
|
||||
GLRenderer->mBuffers->BindOutputFB();
|
||||
GLRenderer->ClearBorders();
|
||||
GLRenderer->mBuffers->BindEyeTexture(0, 0);
|
||||
GLRenderer->DrawPresentTexture(screen->mOutputLetterbox, true);
|
||||
}
|
||||
|
||||
/* static */
|
||||
const RightEyeView& RightEyeView::getInstance(float ipd)
|
||||
{
|
||||
static RightEyeView instance(ipd);
|
||||
instance.setIpd(ipd);
|
||||
return instance;
|
||||
}
|
||||
|
||||
void RightEyeView::Present() const
|
||||
{
|
||||
GLRenderer->mBuffers->BindOutputFB();
|
||||
GLRenderer->ClearBorders();
|
||||
GLRenderer->mBuffers->BindEyeTexture(0, 0);
|
||||
GLRenderer->DrawPresentTexture(screen->mOutputLetterbox, true);
|
||||
}
|
||||
|
||||
|
||||
} /* namespace s3d */
|
|
@ -1,103 +0,0 @@
|
|||
//
|
||||
//---------------------------------------------------------------------------
|
||||
//
|
||||
// Copyright(C) 2015 Christopher Bruns
|
||||
// All rights reserved.
|
||||
//
|
||||
// This program is free software: you can redistribute it and/or modify
|
||||
// it under the terms of the GNU Lesser General Public License as published by
|
||||
// the Free Software Foundation, either version 3 of the License, or
|
||||
// (at your option) any later version.
|
||||
//
|
||||
// This program is distributed in the hope that it will be useful,
|
||||
// but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
// GNU Lesser General Public License for more details.
|
||||
//
|
||||
// You should have received a copy of the GNU Lesser General Public License
|
||||
// along with this program. If not, see http://www.gnu.org/licenses/
|
||||
//
|
||||
//--------------------------------------------------------------------------
|
||||
//
|
||||
/*
|
||||
** gl_stereo_leftright.h
|
||||
** Offsets for left and right eye views
|
||||
**
|
||||
*/
|
||||
|
||||
#ifndef GL_STEREO_LEFTRIGHT_H_
|
||||
#define GL_STEREO_LEFTRIGHT_H_
|
||||
|
||||
#include "gl_stereo3d.h"
|
||||
|
||||
namespace s3d {
|
||||
|
||||
|
||||
class ShiftedEyePose : public EyePose
|
||||
{
|
||||
public:
|
||||
ShiftedEyePose(float shift) : shift(shift) {};
|
||||
float getShift() const;
|
||||
virtual VSMatrix GetProjection(float fov, float aspectRatio, float fovRatio) const;
|
||||
virtual void GetViewShift(float yaw, float outViewShift[3]) const;
|
||||
|
||||
protected:
|
||||
void setShift(float shift) { this->shift = shift; }
|
||||
|
||||
private:
|
||||
float shift;
|
||||
};
|
||||
|
||||
|
||||
class LeftEyePose : public ShiftedEyePose
|
||||
{
|
||||
public:
|
||||
LeftEyePose(float ipd) : ShiftedEyePose( float(-0.5) * ipd) {}
|
||||
float getIpd() const { return float(fabs(2.0f*getShift())); }
|
||||
void setIpd(float ipd) { setShift(float(-0.5)*ipd); }
|
||||
};
|
||||
|
||||
|
||||
class RightEyePose : public ShiftedEyePose
|
||||
{
|
||||
public:
|
||||
RightEyePose(float ipd) : ShiftedEyePose(float(+0.5)*ipd) {}
|
||||
float getIpd() const { return float(fabs(2.0f*getShift())); }
|
||||
void setIpd(float ipd) { setShift(float(+0.5)*ipd); }
|
||||
};
|
||||
|
||||
|
||||
/**
|
||||
* As if viewed through the left eye only
|
||||
*/
|
||||
class LeftEyeView : public Stereo3DMode
|
||||
{
|
||||
public:
|
||||
static const LeftEyeView& getInstance(float ipd);
|
||||
|
||||
LeftEyeView(float ipd) : eye(ipd) { eye_ptrs.Push(&eye); }
|
||||
float getIpd() const { return eye.getIpd(); }
|
||||
void setIpd(float ipd) { eye.setIpd(ipd); }
|
||||
void Present() const override;
|
||||
protected:
|
||||
LeftEyePose eye;
|
||||
};
|
||||
|
||||
|
||||
class RightEyeView : public Stereo3DMode
|
||||
{
|
||||
public:
|
||||
static const RightEyeView& getInstance(float ipd);
|
||||
|
||||
RightEyeView(float ipd) : eye(ipd) { eye_ptrs.Push(&eye); }
|
||||
float getIpd() const { return eye.getIpd(); }
|
||||
void setIpd(float ipd) { eye.setIpd(ipd); }
|
||||
void Present() const override;
|
||||
protected:
|
||||
RightEyePose eye;
|
||||
};
|
||||
|
||||
|
||||
} /* namespace s3d */
|
||||
|
||||
#endif /* GL_STEREO_LEFTRIGHT_H_ */
|
|
@ -1,56 +0,0 @@
|
|||
//
|
||||
//---------------------------------------------------------------------------
|
||||
//
|
||||
// Copyright(C) 2015 Christopher Bruns
|
||||
// All rights reserved.
|
||||
//
|
||||
// This program is free software: you can redistribute it and/or modify
|
||||
// it under the terms of the GNU Lesser General Public License as published by
|
||||
// the Free Software Foundation, either version 3 of the License, or
|
||||
// (at your option) any later version.
|
||||
//
|
||||
// This program is distributed in the hope that it will be useful,
|
||||
// but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
// GNU Lesser General Public License for more details.
|
||||
//
|
||||
// You should have received a copy of the GNU Lesser General Public License
|
||||
// along with this program. If not, see http://www.gnu.org/licenses/
|
||||
//
|
||||
//--------------------------------------------------------------------------
|
||||
//
|
||||
/*
|
||||
** scoped_color_mask.h
|
||||
** Stack-scoped class for temporarily changing the OpenGL color mask setting.
|
||||
**
|
||||
*/
|
||||
|
||||
#ifndef GL_STEREO3D_SCOPED_COLOR_MASK_H_
|
||||
#define GL_STEREO3D_SCOPED_COLOR_MASK_H_
|
||||
|
||||
#include "gl_load/gl_system.h"
|
||||
|
||||
/**
|
||||
* Temporarily change color mask
|
||||
*/
|
||||
class ScopedColorMask
|
||||
{
|
||||
public:
|
||||
ScopedColorMask(bool r, bool g, bool b, bool a)
|
||||
{
|
||||
gl_RenderState.GetColorMask(saved[0], saved[1], saved[2], saved[3]);
|
||||
gl_RenderState.SetColorMask(r, g, b, a);
|
||||
gl_RenderState.ApplyColorMask();
|
||||
gl_RenderState.EnableDrawBuffers(1);
|
||||
}
|
||||
~ScopedColorMask() {
|
||||
gl_RenderState.EnableDrawBuffers(gl_RenderState.GetPassDrawBufferCount());
|
||||
gl_RenderState.SetColorMask(saved[0], saved[1], saved[2], saved[3]);
|
||||
gl_RenderState.ApplyColorMask();
|
||||
}
|
||||
private:
|
||||
bool saved[4];
|
||||
};
|
||||
|
||||
|
||||
#endif // GL_STEREO3D_SCOPED_COLOR_MASK_H_
|
|
@ -37,10 +37,10 @@
|
|||
#include "gl/renderer/gl_renderbuffers.h"
|
||||
#include "gl/textures/gl_samplers.h"
|
||||
#include "hwrenderer/utility/hw_clock.h"
|
||||
#include "hwrenderer/utility/hw_vrmodes.h"
|
||||
#include "gl/data/gl_vertexbuffer.h"
|
||||
#include "gl/data/gl_uniformbuffer.h"
|
||||
#include "gl/models/gl_models.h"
|
||||
#include "gl/stereo3d/gl_stereo3d.h"
|
||||
#include "gl/shaders/gl_shaderprogram.h"
|
||||
#include "gl_debug.h"
|
||||
#include "r_videoscale.h"
|
||||
|
@ -342,7 +342,7 @@ IHardwareTexture *OpenGLFrameBuffer::CreateHardwareTexture(FTexture *tex)
|
|||
|
||||
FModelRenderer *OpenGLFrameBuffer::CreateModelRenderer(int mli)
|
||||
{
|
||||
return new FGLModelRenderer(mli);
|
||||
return new FGLModelRenderer(nullptr, mli);
|
||||
}
|
||||
|
||||
IUniformBuffer *OpenGLFrameBuffer::CreateUniformBuffer(size_t size, bool staticuse)
|
||||
|
@ -361,11 +361,6 @@ void OpenGLFrameBuffer::UnbindTexUnit(int no)
|
|||
FHardwareTexture::Unbind(no);
|
||||
}
|
||||
|
||||
void OpenGLFrameBuffer::FlushTextures()
|
||||
{
|
||||
if (GLRenderer) GLRenderer->FlushTextures();
|
||||
}
|
||||
|
||||
void OpenGLFrameBuffer::TextureFilterChanged()
|
||||
{
|
||||
if (GLRenderer != NULL && GLRenderer->mSamplerManager != NULL) GLRenderer->mSamplerManager->SetTextureFilterMode();
|
||||
|
@ -380,7 +375,10 @@ void OpenGLFrameBuffer::SetViewportRects(IntRect *bounds)
|
|||
{
|
||||
Super::SetViewportRects(bounds);
|
||||
if (!bounds)
|
||||
s3d::Stereo3DMode::getCurrentMode().AdjustViewports();
|
||||
{
|
||||
auto vrmode = VRMode::GetVRMode(true);
|
||||
vrmode->AdjustViewport(this);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
|
|
@ -37,7 +37,6 @@ public:
|
|||
IHardwareTexture *CreateHardwareTexture(FTexture *tex) override;
|
||||
FModelRenderer *CreateModelRenderer(int mli) override;
|
||||
void UnbindTexUnit(int no) override;
|
||||
void FlushTextures() override;
|
||||
void TextureFilterChanged() override;
|
||||
void BeginFrame() override;
|
||||
void SetViewportRects(IntRect *bounds) override;
|
||||
|
|
|
@ -89,7 +89,7 @@ void HWDrawInfo::AddLine (seg_t *seg, bool portalclip)
|
|||
|
||||
if (portalclip)
|
||||
{
|
||||
int clipres = mClipPortal->ClipSeg(seg);
|
||||
int clipres = mClipPortal->ClipSeg(seg, Viewpoint.Pos);
|
||||
if (clipres == PClip_InFront) return;
|
||||
}
|
||||
|
||||
|
@ -353,6 +353,7 @@ void HWDrawInfo::RenderThings(subsector_t * sub, sector_t * sector)
|
|||
SetupSprite.Clock();
|
||||
sector_t * sec=sub->sector;
|
||||
// Handle all things in sector.
|
||||
const auto &vp = Viewpoint;
|
||||
for (auto p = sec->touching_renderthings; p != nullptr; p = p->m_snext)
|
||||
{
|
||||
auto thing = p->m_thing;
|
||||
|
@ -362,7 +363,7 @@ void HWDrawInfo::RenderThings(subsector_t * sub, sector_t * sector)
|
|||
FIntCVar *cvar = thing->GetInfo()->distancecheck;
|
||||
if (cvar != nullptr && *cvar >= 0)
|
||||
{
|
||||
double dist = (thing->Pos() - r_viewpoint.Pos).LengthSquared();
|
||||
double dist = (thing->Pos() - vp.Pos).LengthSquared();
|
||||
double check = (double)**cvar;
|
||||
if (dist >= check * check)
|
||||
{
|
||||
|
@ -383,7 +384,7 @@ void HWDrawInfo::RenderThings(subsector_t * sub, sector_t * sector)
|
|||
FIntCVar *cvar = thing->GetInfo()->distancecheck;
|
||||
if (cvar != nullptr && *cvar >= 0)
|
||||
{
|
||||
double dist = (thing->Pos() - r_viewpoint.Pos).LengthSquared();
|
||||
double dist = (thing->Pos() - vp.Pos).LengthSquared();
|
||||
double check = (double)**cvar;
|
||||
if (dist >= check * check)
|
||||
{
|
||||
|
@ -537,13 +538,13 @@ void HWDrawInfo::DoSubsector(subsector_t * sub)
|
|||
portal = fakesector->GetPortalGroup(sector_t::ceiling);
|
||||
if (portal != nullptr)
|
||||
{
|
||||
portal->AddSubsector(sub);
|
||||
AddSubsectorToPortal(portal, sub);
|
||||
}
|
||||
|
||||
portal = fakesector->GetPortalGroup(sector_t::floor);
|
||||
if (portal != nullptr)
|
||||
{
|
||||
portal->AddSubsector(sub);
|
||||
AddSubsectorToPortal(portal, sub);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -373,10 +373,10 @@ angle_t Clipper::AngleToPseudo(angle_t ang)
|
|||
//
|
||||
//-----------------------------------------------------------------------------
|
||||
|
||||
angle_t R_PointToPseudoAngle(double x, double y)
|
||||
angle_t Clipper::PointToPseudoAngle(double x, double y)
|
||||
{
|
||||
double vecx = x - r_viewpoint.Pos.X;
|
||||
double vecy = y - r_viewpoint.Pos.Y;
|
||||
double vecx = x - viewpoint->Pos.X;
|
||||
double vecy = y - viewpoint->Pos.Y;
|
||||
|
||||
if (vecx == 0 && vecy == 0)
|
||||
{
|
||||
|
@ -427,14 +427,15 @@ bool Clipper::CheckBox(const float *bspcoord)
|
|||
|
||||
// Find the corners of the box
|
||||
// that define the edges from current viewpoint.
|
||||
boxpos = (r_viewpoint.Pos.X <= bspcoord[BOXLEFT] ? 0 : r_viewpoint.Pos.X < bspcoord[BOXRIGHT ] ? 1 : 2) +
|
||||
(r_viewpoint.Pos.Y >= bspcoord[BOXTOP ] ? 0 : r_viewpoint.Pos.Y > bspcoord[BOXBOTTOM] ? 4 : 8);
|
||||
auto &vp = viewpoint;
|
||||
boxpos = (vp->Pos.X <= bspcoord[BOXLEFT] ? 0 : vp->Pos.X < bspcoord[BOXRIGHT ] ? 1 : 2) +
|
||||
(vp->Pos.Y >= bspcoord[BOXTOP ] ? 0 : vp->Pos.Y > bspcoord[BOXBOTTOM] ? 4 : 8);
|
||||
|
||||
if (boxpos == 5) return true;
|
||||
|
||||
check = checkcoord[boxpos];
|
||||
angle1 = R_PointToPseudoAngle (bspcoord[check[0]], bspcoord[check[1]]);
|
||||
angle2 = R_PointToPseudoAngle (bspcoord[check[2]], bspcoord[check[3]]);
|
||||
angle1 = PointToPseudoAngle (bspcoord[check[0]], bspcoord[check[1]]);
|
||||
angle2 = PointToPseudoAngle (bspcoord[check[2]], bspcoord[check[3]]);
|
||||
|
||||
return SafeCheckRange(angle2, angle1);
|
||||
}
|
||||
|
|
|
@ -6,14 +6,6 @@
|
|||
#include "r_utility.h"
|
||||
#include "memarena.h"
|
||||
|
||||
angle_t R_PointToPseudoAngle(double x, double y);
|
||||
|
||||
// Used to speed up angle calculations during clipping
|
||||
inline angle_t vertex_t::GetClipAngle()
|
||||
{
|
||||
return R_PointToPseudoAngle(p.X, p.Y);
|
||||
}
|
||||
|
||||
class ClipNode
|
||||
{
|
||||
friend class Clipper;
|
||||
|
@ -37,6 +29,7 @@ class Clipper
|
|||
ClipNode * clipnodes = nullptr;
|
||||
ClipNode * cliphead = nullptr;
|
||||
ClipNode * silhouette = nullptr; // will be preserved even when RemoveClipRange is called
|
||||
const FRenderViewpoint *viewpoint = nullptr;
|
||||
bool blocked = false;
|
||||
|
||||
static angle_t AngleToPseudo(angle_t ang);
|
||||
|
@ -78,6 +71,11 @@ public:
|
|||
c->next = c->prev = NULL;
|
||||
return c;
|
||||
}
|
||||
|
||||
void SetViewpoint(const FRenderViewpoint &vp)
|
||||
{
|
||||
viewpoint = &vp;
|
||||
}
|
||||
|
||||
void SetSilhouette();
|
||||
|
||||
|
@ -105,6 +103,13 @@ public:
|
|||
AddClipRange(startangle, endangle);
|
||||
}
|
||||
}
|
||||
|
||||
void SafeAddClipRange(const vertex_t *v1, const vertex_t *v2)
|
||||
{
|
||||
angle_t a2 = PointToPseudoAngle(v1->p.X, v1->p.Y);
|
||||
angle_t a1 = PointToPseudoAngle(v2->p.X, v2->p.Y);
|
||||
SafeAddClipRange(a1,a2);
|
||||
}
|
||||
|
||||
void SafeAddClipRangeRealAngles(angle_t startangle, angle_t endangle)
|
||||
{
|
||||
|
@ -141,13 +146,15 @@ public:
|
|||
{
|
||||
return blocked;
|
||||
}
|
||||
|
||||
angle_t PointToPseudoAngle(double x, double y);
|
||||
|
||||
bool CheckBox(const float *bspcoord);
|
||||
|
||||
// Used to speed up angle calculations during clipping
|
||||
inline angle_t GetClipAngle(vertex_t *v)
|
||||
{
|
||||
return unsigned(v->angletime) == starttime ? v->viewangle : (v->angletime = starttime, v->viewangle = R_PointToPseudoAngle(v->p.X, v->p.Y));
|
||||
return unsigned(v->angletime) == starttime ? v->viewangle : (v->angletime = starttime, v->viewangle = PointToPseudoAngle(v->p.X, v->p.Y));
|
||||
}
|
||||
|
||||
};
|
||||
|
|
284
src/hwrenderer/scene/hw_drawinfo.cpp
Normal file
284
src/hwrenderer/scene/hw_drawinfo.cpp
Normal file
|
@ -0,0 +1,284 @@
|
|||
//
|
||||
//---------------------------------------------------------------------------
|
||||
//
|
||||
// Copyright(C) 2000-2018 Christoph Oelckers
|
||||
// All rights reserved.
|
||||
//
|
||||
// This program is free software: you can redistribute it and/or modify
|
||||
// it under the terms of the GNU Lesser General Public License as published by
|
||||
// the Free Software Foundation, either version 3 of the License, or
|
||||
// (at your option) any later version.
|
||||
//
|
||||
// This program is distributed in the hope that it will be useful,
|
||||
// but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
// GNU Lesser General Public License for more details.
|
||||
//
|
||||
// You should have received a copy of the GNU Lesser General Public License
|
||||
// along with this program. If not, see http://www.gnu.org/licenses/
|
||||
//
|
||||
//--------------------------------------------------------------------------
|
||||
//
|
||||
/*
|
||||
** gl_drawinfo.cpp
|
||||
** Basic scene draw info management class
|
||||
**
|
||||
*/
|
||||
|
||||
#include "a_sharedglobal.h"
|
||||
#include "r_utility.h"
|
||||
#include "r_sky.h"
|
||||
#include "d_player.h"
|
||||
#include "g_levellocals.h"
|
||||
#include "hw_fakeflat.h"
|
||||
#include "hw_drawinfo.h"
|
||||
#include "hw_portal.h"
|
||||
#include "hwrenderer/utility/hw_clock.h"
|
||||
#include "hwrenderer/utility/hw_cvars.h"
|
||||
|
||||
EXTERN_CVAR(Float, r_visibility)
|
||||
CVAR(Bool, gl_bandedswlight, false, CVAR_ARCHIVE)
|
||||
|
||||
sector_t * hw_FakeFlat(sector_t * sec, sector_t * dest, area_t in_area, bool back);
|
||||
|
||||
//==========================================================================
|
||||
//
|
||||
//
|
||||
//
|
||||
//==========================================================================
|
||||
|
||||
void HWDrawInfo::ClearBuffers()
|
||||
{
|
||||
for(unsigned int i=0;i< otherfloorplanes.Size();i++)
|
||||
{
|
||||
gl_subsectorrendernode * node = otherfloorplanes[i];
|
||||
while (node)
|
||||
{
|
||||
gl_subsectorrendernode * n = node;
|
||||
node = node->next;
|
||||
delete n;
|
||||
}
|
||||
}
|
||||
otherfloorplanes.Clear();
|
||||
|
||||
for(unsigned int i=0;i< otherceilingplanes.Size();i++)
|
||||
{
|
||||
gl_subsectorrendernode * node = otherceilingplanes[i];
|
||||
while (node)
|
||||
{
|
||||
gl_subsectorrendernode * n = node;
|
||||
node = node->next;
|
||||
delete n;
|
||||
}
|
||||
}
|
||||
otherceilingplanes.Clear();
|
||||
|
||||
// clear all the lists that might not have been cleared already
|
||||
MissingUpperTextures.Clear();
|
||||
MissingLowerTextures.Clear();
|
||||
MissingUpperSegs.Clear();
|
||||
MissingLowerSegs.Clear();
|
||||
SubsectorHacks.Clear();
|
||||
CeilingStacks.Clear();
|
||||
FloorStacks.Clear();
|
||||
HandledSubsectors.Clear();
|
||||
spriteindex = 0;
|
||||
|
||||
CurrentMapSections.Resize(level.NumMapSections);
|
||||
CurrentMapSections.Zero();
|
||||
|
||||
sectorrenderflags.Resize(level.sectors.Size());
|
||||
ss_renderflags.Resize(level.subsectors.Size());
|
||||
no_renderflags.Resize(level.subsectors.Size());
|
||||
|
||||
memset(§orrenderflags[0], 0, level.sectors.Size() * sizeof(sectorrenderflags[0]));
|
||||
memset(&ss_renderflags[0], 0, level.subsectors.Size() * sizeof(ss_renderflags[0]));
|
||||
memset(&no_renderflags[0], 0, level.nodes.Size() * sizeof(no_renderflags[0]));
|
||||
|
||||
mClipPortal = nullptr;
|
||||
mCurrentPortal = nullptr;
|
||||
}
|
||||
|
||||
//==========================================================================
|
||||
//
|
||||
//
|
||||
//
|
||||
//==========================================================================
|
||||
|
||||
void HWDrawInfo::UpdateCurrentMapSection()
|
||||
{
|
||||
const int mapsection = R_PointInSubsector(Viewpoint.Pos)->mapsection;
|
||||
CurrentMapSections.Set(mapsection);
|
||||
}
|
||||
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
//
|
||||
// Sets the area the camera is in
|
||||
//
|
||||
//-----------------------------------------------------------------------------
|
||||
|
||||
void HWDrawInfo::SetViewArea()
|
||||
{
|
||||
auto &vp = Viewpoint;
|
||||
// The render_sector is better suited to represent the current position in GL
|
||||
vp.sector = R_PointInSubsector(vp.Pos)->render_sector;
|
||||
|
||||
// Get the heightsec state from the render sector, not the current one!
|
||||
if (vp.sector->GetHeightSec())
|
||||
{
|
||||
in_area = vp.Pos.Z <= vp.sector->heightsec->floorplane.ZatPoint(vp.Pos) ? area_below :
|
||||
(vp.Pos.Z > vp.sector->heightsec->ceilingplane.ZatPoint(vp.Pos) &&
|
||||
!(vp.sector->heightsec->MoreFlags&SECMF_FAKEFLOORONLY)) ? area_above : area_normal;
|
||||
}
|
||||
else
|
||||
{
|
||||
in_area = level.HasHeightSecs ? area_default : area_normal; // depends on exposed lower sectors, if map contains heightsecs.
|
||||
}
|
||||
}
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
//
|
||||
//
|
||||
//
|
||||
//-----------------------------------------------------------------------------
|
||||
|
||||
int HWDrawInfo::SetFullbrightFlags(player_t *player)
|
||||
{
|
||||
FullbrightFlags = 0;
|
||||
|
||||
// check for special colormaps
|
||||
player_t * cplayer = player? player->camera->player : nullptr;
|
||||
if (cplayer)
|
||||
{
|
||||
int cm = CM_DEFAULT;
|
||||
if (cplayer->extralight == INT_MIN)
|
||||
{
|
||||
cm = CM_FIRSTSPECIALCOLORMAP + INVERSECOLORMAP;
|
||||
Viewpoint.extralight = 0;
|
||||
FullbrightFlags = Fullbright;
|
||||
// This does never set stealth vision.
|
||||
}
|
||||
else if (cplayer->fixedcolormap != NOFIXEDCOLORMAP)
|
||||
{
|
||||
cm = CM_FIRSTSPECIALCOLORMAP + cplayer->fixedcolormap;
|
||||
FullbrightFlags = Fullbright;
|
||||
if (gl_enhanced_nv_stealth > 2) FullbrightFlags |= StealthVision;
|
||||
}
|
||||
else if (cplayer->fixedlightlevel != -1)
|
||||
{
|
||||
auto torchtype = PClass::FindActor(NAME_PowerTorch);
|
||||
auto litetype = PClass::FindActor(NAME_PowerLightAmp);
|
||||
for (AInventory * in = cplayer->mo->Inventory; in; in = in->Inventory)
|
||||
{
|
||||
//PalEntry color = in->CallGetBlend();
|
||||
|
||||
// Need special handling for light amplifiers
|
||||
if (in->IsKindOf(torchtype))
|
||||
{
|
||||
FullbrightFlags = Fullbright;
|
||||
if (gl_enhanced_nv_stealth > 1) FullbrightFlags |= StealthVision;
|
||||
}
|
||||
else if (in->IsKindOf(litetype))
|
||||
{
|
||||
FullbrightFlags = Fullbright;
|
||||
if (gl_enhanced_nightvision) FullbrightFlags |= Nightvision;
|
||||
if (gl_enhanced_nv_stealth > 0) FullbrightFlags |= StealthVision;
|
||||
}
|
||||
}
|
||||
}
|
||||
return cm;
|
||||
}
|
||||
else
|
||||
{
|
||||
return CM_DEFAULT;
|
||||
}
|
||||
}
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
//
|
||||
// R_FrustumAngle
|
||||
//
|
||||
//-----------------------------------------------------------------------------
|
||||
|
||||
angle_t HWDrawInfo::FrustumAngle()
|
||||
{
|
||||
float tilt = fabs(Viewpoint.HWAngles.Pitch.Degrees);
|
||||
|
||||
// If the pitch is larger than this you can look all around at a FOV of 90°
|
||||
if (tilt > 46.0f) return 0xffffffff;
|
||||
|
||||
// ok, this is a gross hack that barely works...
|
||||
// but at least it doesn't overestimate too much...
|
||||
double floatangle = 2.0 + (45.0 + ((tilt / 1.9)))*Viewpoint.FieldOfView.Degrees*48.0 / AspectMultiplier(r_viewwindow.WidescreenRatio) / 90.0;
|
||||
angle_t a1 = DAngle(floatangle).BAMs();
|
||||
if (a1 >= ANGLE_180) return 0xffffffff;
|
||||
return a1;
|
||||
}
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
//
|
||||
// Setup the modelview matrix
|
||||
//
|
||||
//-----------------------------------------------------------------------------
|
||||
|
||||
void HWDrawInfo::SetViewMatrix(const FRotator &angles, float vx, float vy, float vz, bool mirror, bool planemirror)
|
||||
{
|
||||
float mult = mirror ? -1.f : 1.f;
|
||||
float planemult = planemirror ? -level.info->pixelstretch : level.info->pixelstretch;
|
||||
|
||||
VPUniforms.mViewMatrix.loadIdentity();
|
||||
VPUniforms.mViewMatrix.rotate(angles.Roll.Degrees, 0.0f, 0.0f, 1.0f);
|
||||
VPUniforms.mViewMatrix.rotate(angles.Pitch.Degrees, 1.0f, 0.0f, 0.0f);
|
||||
VPUniforms.mViewMatrix.rotate(angles.Yaw.Degrees, 0.0f, mult, 0.0f);
|
||||
VPUniforms.mViewMatrix.translate(vx * mult, -vz * planemult, -vy);
|
||||
VPUniforms.mViewMatrix.scale(-mult, planemult, 1);
|
||||
}
|
||||
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
//
|
||||
// SetupView
|
||||
// Setup the view rotation matrix for the given viewpoint
|
||||
//
|
||||
//-----------------------------------------------------------------------------
|
||||
void HWDrawInfo::SetupView(float vx, float vy, float vz, bool mirror, bool planemirror)
|
||||
{
|
||||
auto &vp = Viewpoint;
|
||||
vp.SetViewAngle(r_viewwindow);
|
||||
SetViewMatrix(vp.HWAngles, vx, vy, vz, mirror, planemirror);
|
||||
SetCameraPos(vp.Pos);
|
||||
ApplyVPUniforms();
|
||||
}
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
//
|
||||
//
|
||||
//
|
||||
//-----------------------------------------------------------------------------
|
||||
|
||||
IPortal * HWDrawInfo::FindPortal(const void * src)
|
||||
{
|
||||
int i = Portals.Size() - 1;
|
||||
|
||||
while (i >= 0 && Portals[i] && Portals[i]->GetSource() != src) i--;
|
||||
return i >= 0 ? Portals[i] : nullptr;
|
||||
}
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
//
|
||||
//
|
||||
//
|
||||
//-----------------------------------------------------------------------------
|
||||
|
||||
void HWViewpointUniforms::SetDefaults()
|
||||
{
|
||||
mProjectionMatrix.loadIdentity();
|
||||
mViewMatrix.loadIdentity();
|
||||
mNormalViewMatrix.loadIdentity();
|
||||
mViewHeight = viewheight;
|
||||
mGlobVis = (float)R_GetGlobVis(r_viewwindow, r_visibility) / 32.f;
|
||||
mPalLightLevels = static_cast<int>(gl_bandedswlight) | (static_cast<int>(gl_fogmode) << 8);
|
||||
mClipLine.X = -10000000.0f;
|
||||
|
||||
}
|
|
@ -1,7 +1,11 @@
|
|||
#pragma once
|
||||
|
||||
#include <atomic>
|
||||
#include "vectors.h"
|
||||
#include "r_defs.h"
|
||||
#include "r_utility.h"
|
||||
#include "hw_viewpointuniforms.h"
|
||||
#include "v_video.h"
|
||||
|
||||
|
||||
struct FSectorPortalGroup;
|
||||
|
@ -18,6 +22,8 @@ struct HUDSprite;
|
|||
class Clipper;
|
||||
class IPortal;
|
||||
class FFlatVertexGenerator;
|
||||
class IRenderQueue;
|
||||
class HWScenePortalBase;
|
||||
|
||||
//==========================================================================
|
||||
//
|
||||
|
@ -53,7 +59,10 @@ enum EPortalClip
|
|||
|
||||
struct HWDrawInfo
|
||||
{
|
||||
virtual ~HWDrawInfo() {}
|
||||
virtual ~HWDrawInfo()
|
||||
{
|
||||
ClearBuffers();
|
||||
}
|
||||
|
||||
struct wallseg
|
||||
{
|
||||
|
@ -91,14 +100,17 @@ struct HWDrawInfo
|
|||
bool isNightvision() const { return !!(FullbrightFlags & Nightvision); }
|
||||
bool isStealthVision() const { return !!(FullbrightFlags & StealthVision); }
|
||||
|
||||
HWDrawInfo * outer = nullptr;
|
||||
int FullbrightFlags;
|
||||
std::atomic<int> spriteindex;
|
||||
IPortal *mClipPortal;
|
||||
FRotator mAngles;
|
||||
FVector2 mViewVector;
|
||||
AActor *mViewActor;
|
||||
HWScenePortalBase *mClipPortal;
|
||||
IPortal *mCurrentPortal;
|
||||
//FRotator mAngles;
|
||||
IShadowMap *mShadowMap;
|
||||
Clipper *mClipper;
|
||||
FRenderViewpoint Viewpoint;
|
||||
HWViewpointUniforms VPUniforms; // per-viewpoint uniform state
|
||||
TArray<IPortal *> Portals;
|
||||
|
||||
TArray<MissingTextureInfo> MissingUpperTextures;
|
||||
TArray<MissingTextureInfo> MissingLowerTextures;
|
||||
|
@ -138,6 +150,7 @@ private:
|
|||
|
||||
sector_t fakesec; // this is a struct member because it gets used in recursively called functions so it cannot be put on the stack.
|
||||
|
||||
|
||||
void UnclipSubsector(subsector_t *sub);
|
||||
void AddLine(seg_t *seg, bool portalclip);
|
||||
void PolySubsector(subsector_t * sub);
|
||||
|
@ -148,6 +161,31 @@ private:
|
|||
void RenderThings(subsector_t * sub, sector_t * sector);
|
||||
void DoSubsector(subsector_t * sub);
|
||||
public:
|
||||
|
||||
void SetCameraPos(const DVector3 &pos)
|
||||
{
|
||||
VPUniforms.mCameraPos = { (float)pos.X, (float)pos.Z, (float)pos.Y, 0.f };
|
||||
}
|
||||
|
||||
void SetClipHeight(float h, float d)
|
||||
{
|
||||
VPUniforms.mClipHeight = h;
|
||||
VPUniforms.mClipHeightDirection = d;
|
||||
VPUniforms.mClipLine.X = -1000001.f;
|
||||
}
|
||||
|
||||
void SetClipLine(line_t *line)
|
||||
{
|
||||
VPUniforms.mClipLine = { (float)line->v1->fX(), (float)line->v1->fY(), (float)line->Delta().X, (float)line->Delta().Y };
|
||||
VPUniforms.mClipHeight = 0;
|
||||
}
|
||||
|
||||
bool ClipLineShouldBeActive()
|
||||
{
|
||||
return (screen->hwcaps & RFL_NO_CLIP_PLANES) && VPUniforms.mClipLine.X > -1000000.f;
|
||||
}
|
||||
|
||||
IPortal * FindPortal(const void * src);
|
||||
void RenderBSPNode(void *node);
|
||||
|
||||
void ClearBuffers();
|
||||
|
@ -188,6 +226,9 @@ public:
|
|||
void PrepareTargeterSprites();
|
||||
|
||||
void UpdateCurrentMapSection();
|
||||
void SetViewMatrix(const FRotator &angles, float vx, float vy, float vz, bool mirror, bool planemirror);
|
||||
void SetupView(float vx, float vy, float vz, bool mirror, bool planemirror);
|
||||
angle_t FrustumAngle();
|
||||
|
||||
virtual void DrawWall(GLWall *wall, int pass) = 0;
|
||||
virtual void DrawFlat(GLFlat *flat, int pass, bool trans) = 0;
|
||||
|
@ -195,7 +236,7 @@ public:
|
|||
|
||||
virtual void FloodUpperGap(seg_t * seg) = 0;
|
||||
virtual void FloodLowerGap(seg_t * seg) = 0;
|
||||
virtual void ProcessLowerMinisegs(TArray<seg_t *> &lowersegs) = 0;
|
||||
void ProcessLowerMinisegs(TArray<seg_t *> &lowersegs);
|
||||
virtual void AddSubsectorToPortal(FSectorPortalGroup *portal, subsector_t *sub) = 0;
|
||||
|
||||
virtual void AddWall(GLWall *w) = 0;
|
||||
|
@ -206,6 +247,8 @@ public:
|
|||
virtual void AddHUDSprite(HUDSprite *huds) = 0;
|
||||
|
||||
virtual int UploadLights(FDynLightData &data) = 0;
|
||||
virtual void ApplyVPUniforms() = 0;
|
||||
virtual bool SetDepthClamp(bool on) = 0;
|
||||
|
||||
virtual GLDecal *AddDecal(bool onmirror) = 0;
|
||||
virtual std::pair<FFlatVertex *, unsigned int> AllocVertices(unsigned int count) = 0;
|
||||
|
|
|
@ -121,7 +121,7 @@ inline void SortNode::AddToEqual(SortNode *child)
|
|||
{
|
||||
child->UnlinkFromChain();
|
||||
child->equal=equal;
|
||||
equal=child;
|
||||
equal=child;
|
||||
}
|
||||
|
||||
//==========================================================================
|
||||
|
@ -269,7 +269,7 @@ void HWDrawList::SortWallIntoPlane(SortNode * head, SortNode * sort)
|
|||
GLFlat * fh = flats[drawitems[head->itemindex].index];
|
||||
GLWall * ws = walls[drawitems[sort->itemindex].index];
|
||||
|
||||
bool ceiling = fh->z > r_viewpoint.Pos.Z;
|
||||
bool ceiling = fh->z > SortZ;
|
||||
|
||||
if ((ws->ztop[0] > fh->z || ws->ztop[1] > fh->z) && (ws->zbottom[0] < fh->z || ws->zbottom[1] < fh->z))
|
||||
{
|
||||
|
@ -327,7 +327,7 @@ void HWDrawList::SortSpriteIntoPlane(SortNode * head, SortNode * sort)
|
|||
GLFlat * fh = flats[drawitems[head->itemindex].index];
|
||||
GLSprite * ss = sprites[drawitems[sort->itemindex].index];
|
||||
|
||||
bool ceiling = fh->z > r_viewpoint.Pos.Z;
|
||||
bool ceiling = fh->z > SortZ;
|
||||
|
||||
auto hiz = ss->z1 > ss->z2 ? ss->z1 : ss->z2;
|
||||
auto loz = ss->z1 < ss->z2 ? ss->z1 : ss->z2;
|
||||
|
@ -688,6 +688,7 @@ SortNode * HWDrawList::DoSort(HWDrawInfo *di, SortNode * head)
|
|||
//==========================================================================
|
||||
void HWDrawList::Sort(HWDrawInfo *di)
|
||||
{
|
||||
SortZ = di->Viewpoint.Pos.Z;
|
||||
MakeSortList();
|
||||
sorted = DoSort(di, SortNodes[SortNodeStart]);
|
||||
}
|
||||
|
|
|
@ -61,6 +61,7 @@ struct HWDrawList
|
|||
TArray<GLSprite*> sprites;
|
||||
TArray<GLDrawItem> drawitems;
|
||||
int SortNodeStart;
|
||||
float SortZ;
|
||||
SortNode * sorted;
|
||||
|
||||
public:
|
||||
|
|
|
@ -384,7 +384,7 @@ public:
|
|||
|
||||
void SplitSprite(HWDrawInfo *di, sector_t * frontsector, bool translucent);
|
||||
void PerformSpriteClipAdjustment(AActor *thing, const DVector2 &thingpos, float spriteheight);
|
||||
bool CalculateVertices(HWDrawInfo *di, FVector3 *v);
|
||||
bool CalculateVertices(HWDrawInfo *di, FVector3 *v, DVector3 *vp);
|
||||
|
||||
public:
|
||||
|
||||
|
|
|
@ -386,79 +386,3 @@ sector_t * hw_FakeFlat(sector_t * sec, sector_t * dest, area_t in_area, bool bac
|
|||
}
|
||||
return dest;
|
||||
}
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
//
|
||||
// Sets the area the camera is in
|
||||
//
|
||||
//-----------------------------------------------------------------------------
|
||||
void HWDrawInfo::SetViewArea()
|
||||
{
|
||||
// The render_sector is better suited to represent the current position in GL
|
||||
r_viewpoint.sector = R_PointInSubsector(r_viewpoint.Pos)->render_sector;
|
||||
|
||||
// Get the heightsec state from the render sector, not the current one!
|
||||
if (r_viewpoint.sector->GetHeightSec())
|
||||
{
|
||||
in_area = r_viewpoint.Pos.Z <= r_viewpoint.sector->heightsec->floorplane.ZatPoint(r_viewpoint.Pos) ? area_below :
|
||||
(r_viewpoint.Pos.Z > r_viewpoint.sector->heightsec->ceilingplane.ZatPoint(r_viewpoint.Pos) &&
|
||||
!(r_viewpoint.sector->heightsec->MoreFlags&SECMF_FAKEFLOORONLY)) ? area_above : area_normal;
|
||||
}
|
||||
else
|
||||
{
|
||||
in_area = level.HasHeightSecs ? area_default : area_normal; // depends on exposed lower sectors, if map contains heightsecs.
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
int HWDrawInfo::SetFullbrightFlags(player_t *player)
|
||||
{
|
||||
FullbrightFlags = 0;
|
||||
|
||||
// check for special colormaps
|
||||
player_t * cplayer = player? player->camera->player : nullptr;
|
||||
if (cplayer)
|
||||
{
|
||||
int cm = CM_DEFAULT;
|
||||
if (cplayer->extralight == INT_MIN)
|
||||
{
|
||||
cm = CM_FIRSTSPECIALCOLORMAP + INVERSECOLORMAP;
|
||||
r_viewpoint.extralight = 0;
|
||||
FullbrightFlags = Fullbright;
|
||||
// This does never set stealth vision.
|
||||
}
|
||||
else if (cplayer->fixedcolormap != NOFIXEDCOLORMAP)
|
||||
{
|
||||
cm = CM_FIRSTSPECIALCOLORMAP + cplayer->fixedcolormap;
|
||||
FullbrightFlags = Fullbright;
|
||||
if (gl_enhanced_nv_stealth > 2) FullbrightFlags |= StealthVision;
|
||||
}
|
||||
else if (cplayer->fixedlightlevel != -1)
|
||||
{
|
||||
auto torchtype = PClass::FindActor(NAME_PowerTorch);
|
||||
auto litetype = PClass::FindActor(NAME_PowerLightAmp);
|
||||
for (AInventory * in = cplayer->mo->Inventory; in; in = in->Inventory)
|
||||
{
|
||||
//PalEntry color = in->CallGetBlend();
|
||||
|
||||
// Need special handling for light amplifiers
|
||||
if (in->IsKindOf(torchtype))
|
||||
{
|
||||
FullbrightFlags = Fullbright;
|
||||
if (gl_enhanced_nv_stealth > 1) FullbrightFlags |= StealthVision;
|
||||
}
|
||||
else if (in->IsKindOf(litetype))
|
||||
{
|
||||
FullbrightFlags = Fullbright;
|
||||
if (gl_enhanced_nightvision) FullbrightFlags |= Nightvision;
|
||||
if (gl_enhanced_nv_stealth > 0) FullbrightFlags |= StealthVision;
|
||||
}
|
||||
}
|
||||
}
|
||||
return cm;
|
||||
}
|
||||
else
|
||||
{
|
||||
return CM_DEFAULT;
|
||||
}
|
||||
}
|
||||
|
|
|
@ -9,7 +9,7 @@ enum area_t : int
|
|||
};
|
||||
|
||||
|
||||
// Global functions. Make them members of GLRenderer later?
|
||||
// Global functions.
|
||||
bool hw_CheckClip(side_t * sidedef, sector_t * frontsector, sector_t * backsector);
|
||||
sector_t * hw_FakeFlat(sector_t * sec, sector_t * dest, area_t in_area, bool back);
|
||||
area_t hw_CheckViewArea(vertex_t *v1, vertex_t *v2, sector_t *frontsector, sector_t *backsector);
|
||||
|
|
|
@ -306,6 +306,7 @@ void GLFlat::ProcessSector(HWDrawInfo *di, sector_t * frontsector)
|
|||
dynlightindex = -1;
|
||||
|
||||
uint8_t &srf = di->sectorrenderflags[sector->sectornum];
|
||||
const auto &vp = di->Viewpoint;
|
||||
|
||||
//
|
||||
//
|
||||
|
@ -314,7 +315,7 @@ void GLFlat::ProcessSector(HWDrawInfo *di, sector_t * frontsector)
|
|||
//
|
||||
//
|
||||
//
|
||||
if (frontsector->floorplane.ZatPoint(r_viewpoint.Pos) <= r_viewpoint.Pos.Z)
|
||||
if (frontsector->floorplane.ZatPoint(vp.Pos) <= vp.Pos.Z)
|
||||
{
|
||||
// process the original floor first.
|
||||
|
||||
|
@ -374,7 +375,7 @@ void GLFlat::ProcessSector(HWDrawInfo *di, sector_t * frontsector)
|
|||
//
|
||||
//
|
||||
//
|
||||
if (frontsector->ceilingplane.ZatPoint(r_viewpoint.Pos) >= r_viewpoint.Pos.Z)
|
||||
if (frontsector->ceilingplane.ZatPoint(vp.Pos) >= vp.Pos.Z)
|
||||
{
|
||||
// process the original ceiling first.
|
||||
|
||||
|
@ -465,7 +466,7 @@ void GLFlat::ProcessSector(HWDrawInfo *di, sector_t * frontsector)
|
|||
double ff_top = rover->top.plane->ZatPoint(sector->centerspot);
|
||||
if (ff_top < lastceilingheight)
|
||||
{
|
||||
if (r_viewpoint.Pos.Z <= rover->top.plane->ZatPoint(r_viewpoint.Pos))
|
||||
if (vp.Pos.Z <= rover->top.plane->ZatPoint(vp.Pos))
|
||||
{
|
||||
SetFrom3DFloor(rover, true, !!(rover->flags&FF_FOG));
|
||||
Colormap.FadeColor = frontsector->Colormap.FadeColor;
|
||||
|
@ -479,7 +480,7 @@ void GLFlat::ProcessSector(HWDrawInfo *di, sector_t * frontsector)
|
|||
double ff_bottom = rover->bottom.plane->ZatPoint(sector->centerspot);
|
||||
if (ff_bottom < lastceilingheight)
|
||||
{
|
||||
if (r_viewpoint.Pos.Z <= rover->bottom.plane->ZatPoint(r_viewpoint.Pos))
|
||||
if (vp.Pos.Z <= rover->bottom.plane->ZatPoint(vp.Pos))
|
||||
{
|
||||
SetFrom3DFloor(rover, false, !(rover->flags&FF_FOG));
|
||||
Colormap.FadeColor = frontsector->Colormap.FadeColor;
|
||||
|
@ -505,7 +506,7 @@ void GLFlat::ProcessSector(HWDrawInfo *di, sector_t * frontsector)
|
|||
double ff_bottom = rover->bottom.plane->ZatPoint(sector->centerspot);
|
||||
if (ff_bottom > lastfloorheight || (rover->flags&FF_FIX))
|
||||
{
|
||||
if (r_viewpoint.Pos.Z >= rover->bottom.plane->ZatPoint(r_viewpoint.Pos))
|
||||
if (vp.Pos.Z >= rover->bottom.plane->ZatPoint(vp.Pos))
|
||||
{
|
||||
SetFrom3DFloor(rover, false, !(rover->flags&FF_FOG));
|
||||
Colormap.FadeColor = frontsector->Colormap.FadeColor;
|
||||
|
@ -526,7 +527,7 @@ void GLFlat::ProcessSector(HWDrawInfo *di, sector_t * frontsector)
|
|||
double ff_top = rover->top.plane->ZatPoint(sector->centerspot);
|
||||
if (ff_top > lastfloorheight)
|
||||
{
|
||||
if (r_viewpoint.Pos.Z >= rover->top.plane->ZatPoint(r_viewpoint.Pos))
|
||||
if (vp.Pos.Z >= rover->top.plane->ZatPoint(vp.Pos))
|
||||
{
|
||||
SetFrom3DFloor(rover, true, !!(rover->flags&FF_FOG));
|
||||
Colormap.FadeColor = frontsector->Colormap.FadeColor;
|
||||
|
|
628
src/hwrenderer/scene/hw_portal.cpp
Normal file
628
src/hwrenderer/scene/hw_portal.cpp
Normal file
|
@ -0,0 +1,628 @@
|
|||
//
|
||||
//---------------------------------------------------------------------------
|
||||
//
|
||||
// Copyright(C) 2004-2018 Christoph Oelckers
|
||||
// All rights reserved.
|
||||
//
|
||||
// This program is free software: you can redistribute it and/or modify
|
||||
// it under the terms of the GNU Lesser General Public License as published by
|
||||
// the Free Software Foundation, either version 3 of the License, or
|
||||
// (at your option) any later version.
|
||||
//
|
||||
// This program is distributed in the hope that it will be useful,
|
||||
// but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
// GNU Lesser General Public License for more details.
|
||||
//
|
||||
// You should have received a copy of the GNU Lesser General Public License
|
||||
// along with this program. If not, see http://www.gnu.org/licenses/
|
||||
//
|
||||
//--------------------------------------------------------------------------
|
||||
//
|
||||
/*
|
||||
** hw_portal.cpp
|
||||
** portal maintenance classes for skyboxes, horizons etc. (API independent parts)
|
||||
**
|
||||
*/
|
||||
|
||||
#include "c_dispatch.h"
|
||||
#include "portal.h"
|
||||
#include "p_maputl.h"
|
||||
#include "hw_portal.h"
|
||||
#include "hw_clipper.h"
|
||||
#include "actor.h"
|
||||
#include "g_levellocals.h"
|
||||
|
||||
EXTERN_CVAR(Int, r_mirror_recursions)
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
//
|
||||
// StartFrame
|
||||
//
|
||||
//-----------------------------------------------------------------------------
|
||||
|
||||
void FPortalSceneState::StartFrame()
|
||||
{
|
||||
if (renderdepth == 0)
|
||||
{
|
||||
inskybox = false;
|
||||
screen->instack[sector_t::floor] = screen->instack[sector_t::ceiling] = 0;
|
||||
}
|
||||
renderdepth++;
|
||||
}
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
//
|
||||
// printing portal info
|
||||
//
|
||||
//-----------------------------------------------------------------------------
|
||||
|
||||
static bool gl_portalinfo;
|
||||
|
||||
CCMD(gl_portalinfo)
|
||||
{
|
||||
gl_portalinfo = true;
|
||||
}
|
||||
|
||||
static FString indent;
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
//
|
||||
// EndFrame
|
||||
//
|
||||
//-----------------------------------------------------------------------------
|
||||
|
||||
void FPortalSceneState::EndFrame(HWDrawInfo *di)
|
||||
{
|
||||
IPortal * p;
|
||||
|
||||
if (gl_portalinfo)
|
||||
{
|
||||
Printf("%s%d portals, depth = %d\n%s{\n", indent.GetChars(), di->Portals.Size(), renderdepth, indent.GetChars());
|
||||
indent += " ";
|
||||
}
|
||||
|
||||
// Only use occlusion query if there are more than 2 portals.
|
||||
// Otherwise there's too much overhead.
|
||||
// (And don't forget to consider the separating null pointers!)
|
||||
bool usequery = di->Portals.Size() > 2 + (unsigned)renderdepth;
|
||||
|
||||
while (di->Portals.Pop(p) && p)
|
||||
{
|
||||
if (gl_portalinfo)
|
||||
{
|
||||
Printf("%sProcessing %s, depth = %d, query = %d\n", indent.GetChars(), p->GetName(), renderdepth, usequery);
|
||||
}
|
||||
if (p->lines.Size() > 0)
|
||||
{
|
||||
p->RenderPortal(true, usequery, di);
|
||||
}
|
||||
delete p;
|
||||
}
|
||||
renderdepth--;
|
||||
|
||||
if (gl_portalinfo)
|
||||
{
|
||||
indent.Truncate(long(indent.Len()-2));
|
||||
Printf("%s}\n", indent.GetChars());
|
||||
if (indent.Len() == 0) gl_portalinfo = false;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
//
|
||||
// Renders one sky portal without a stencil.
|
||||
// In more complex scenes using a stencil for skies can severely stall
|
||||
// the GPU and there's rarely more than one sky visible at a time.
|
||||
//
|
||||
//-----------------------------------------------------------------------------
|
||||
bool FPortalSceneState::RenderFirstSkyPortal(int recursion, HWDrawInfo *outer_di)
|
||||
{
|
||||
IPortal * p;
|
||||
IPortal * best = nullptr;
|
||||
unsigned bestindex = 0;
|
||||
|
||||
// Find the one with the highest amount of lines.
|
||||
// Normally this is also the one that saves the largest amount
|
||||
// of time by drawing it before the scene itself.
|
||||
auto &portals = outer_di->Portals;
|
||||
for (int i = portals.Size() - 1; i >= 0; --i)
|
||||
{
|
||||
p = portals[i];
|
||||
if (p->lines.Size() > 0 && p->IsSky())
|
||||
{
|
||||
// Cannot clear the depth buffer inside a portal recursion
|
||||
if (recursion && p->NeedDepthBuffer()) continue;
|
||||
|
||||
if (!best || p->lines.Size() > best->lines.Size())
|
||||
{
|
||||
best = p;
|
||||
bestindex = i;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (best)
|
||||
{
|
||||
portals.Delete(bestindex);
|
||||
best->RenderPortal(false, false, outer_di);
|
||||
delete best;
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
//
|
||||
//
|
||||
//
|
||||
//-----------------------------------------------------------------------------
|
||||
|
||||
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();
|
||||
|
||||
auto &lines = mOwner->lines;
|
||||
// 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();
|
||||
}
|
||||
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
//-----------------------------------------------------------------------------
|
||||
//
|
||||
//
|
||||
// Common code for line to line and mirror portals
|
||||
//
|
||||
//
|
||||
//-----------------------------------------------------------------------------
|
||||
//-----------------------------------------------------------------------------
|
||||
|
||||
int HWLinePortal::ClipSeg(seg_t *seg, const DVector3 &viewpos)
|
||||
{
|
||||
line_t *linedef = seg->linedef;
|
||||
if (!linedef)
|
||||
{
|
||||
return PClip_Inside; // should be handled properly.
|
||||
}
|
||||
return P_ClipLineToPortal(linedef, line(), viewpos) ? PClip_InFront : PClip_Inside;
|
||||
}
|
||||
|
||||
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;
|
||||
}
|
||||
|
||||
int HWLinePortal::ClipPoint(const DVector2 &pos)
|
||||
{
|
||||
if (P_PointOnLineSidePrecise(pos, line()))
|
||||
{
|
||||
return PClip_InFront;
|
||||
}
|
||||
return PClip_Inside;
|
||||
}
|
||||
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
//-----------------------------------------------------------------------------
|
||||
//
|
||||
//
|
||||
// Mirror Portal
|
||||
//
|
||||
//
|
||||
//-----------------------------------------------------------------------------
|
||||
//-----------------------------------------------------------------------------
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
//
|
||||
//
|
||||
//
|
||||
//-----------------------------------------------------------------------------
|
||||
|
||||
bool HWMirrorPortal::Setup(HWDrawInfo *di, Clipper *clipper)
|
||||
{
|
||||
auto state = mOwner->mState;
|
||||
if (state->renderdepth > r_mirror_recursions)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
auto &vp = di->Viewpoint;
|
||||
di->UpdateCurrentMapSection();
|
||||
|
||||
di->mClipPortal = this;
|
||||
DAngle StartAngle = vp.Angles.Yaw;
|
||||
DVector3 StartPos = vp.Pos;
|
||||
|
||||
vertex_t *v1 = linedef->v1;
|
||||
vertex_t *v2 = linedef->v2;
|
||||
|
||||
// the player is always visible in a mirror.
|
||||
vp.showviewer = true;
|
||||
// Reflect the current view behind the mirror.
|
||||
if (linedef->Delta().X == 0)
|
||||
{
|
||||
// vertical mirror
|
||||
vp.Pos.X = 2 * v1->fX() - StartPos.X;
|
||||
|
||||
// Compensation for reendering inaccuracies
|
||||
if (StartPos.X < v1->fX()) vp.Pos.X -= 0.1;
|
||||
else vp.Pos.X += 0.1;
|
||||
}
|
||||
else if (linedef->Delta().Y == 0)
|
||||
{
|
||||
// horizontal mirror
|
||||
vp.Pos.Y = 2 * v1->fY() - StartPos.Y;
|
||||
|
||||
// Compensation for reendering inaccuracies
|
||||
if (StartPos.Y < v1->fY()) vp.Pos.Y -= 0.1;
|
||||
else vp.Pos.Y += 0.1;
|
||||
}
|
||||
else
|
||||
{
|
||||
// any mirror--use floats to avoid integer overflow.
|
||||
// Use doubles to avoid losing precision which is very important here.
|
||||
|
||||
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);
|
||||
|
||||
vp.Pos.X = (x1 + r * dx) * 2 - x;
|
||||
vp.Pos.Y = (y1 + r * dy) * 2 - y;
|
||||
|
||||
// Compensation for reendering inaccuracies
|
||||
FVector2 v(-dx, dy);
|
||||
v.MakeUnit();
|
||||
|
||||
vp.Pos.X += v[1] * state->renderdepth / 2;
|
||||
vp.Pos.Y += v[0] * state->renderdepth / 2;
|
||||
}
|
||||
vp.Angles.Yaw = linedef->Delta().Angle() * 2. - StartAngle;
|
||||
|
||||
vp.ViewActor = nullptr;
|
||||
|
||||
state->MirrorFlag++;
|
||||
di->SetClipLine(linedef);
|
||||
di->SetupView(vp.Pos.X, vp.Pos.Y, vp.Pos.Z, !!(state->MirrorFlag & 1), !!(state->PlaneMirrorFlag & 1));
|
||||
|
||||
clipper->Clear();
|
||||
|
||||
angle_t af = di->FrustumAngle();
|
||||
if (af < ANGLE_180) clipper->SafeAddClipRangeRealAngles(vp.Angles.Yaw.BAMs() + af, vp.Angles.Yaw.BAMs() - af);
|
||||
|
||||
clipper->SafeAddClipRange(linedef->v1, linedef->v2);
|
||||
return true;
|
||||
}
|
||||
|
||||
void HWMirrorPortal::Shutdown(HWDrawInfo *di)
|
||||
{
|
||||
mOwner->mState->MirrorFlag--;
|
||||
}
|
||||
|
||||
const char *HWMirrorPortal::GetName() { return "Mirror"; }
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
//-----------------------------------------------------------------------------
|
||||
//
|
||||
//
|
||||
// Line to line Portal
|
||||
//
|
||||
//
|
||||
//-----------------------------------------------------------------------------
|
||||
//-----------------------------------------------------------------------------
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
//
|
||||
//
|
||||
//
|
||||
//-----------------------------------------------------------------------------
|
||||
bool HWLineToLinePortal::Setup(HWDrawInfo *di, Clipper *clipper)
|
||||
{
|
||||
// TODO: Handle recursion more intelligently
|
||||
auto &state = mOwner->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;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
auto &lines = mOwner->lines;
|
||||
|
||||
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];
|
||||
di->CurrentMapSections.Set(sub->mapsection);
|
||||
}
|
||||
|
||||
vp.ViewActor = nullptr;
|
||||
di->SetClipLine(glport->lines[0]->mDestination);
|
||||
di->SetupView(vp.Pos.X, vp.Pos.Y, vp.Pos.Z, !!(state->MirrorFlag & 1), !!(state->PlaneMirrorFlag & 1));
|
||||
|
||||
ClearClipper(di, clipper);
|
||||
return true;
|
||||
}
|
||||
|
||||
void HWLineToLinePortal::RenderAttached(HWDrawInfo *di)
|
||||
{
|
||||
di->ProcessActorsInPortal(glport, di->in_area);
|
||||
}
|
||||
|
||||
const char *HWLineToLinePortal::GetName() { return "LineToLine"; }
|
||||
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
//-----------------------------------------------------------------------------
|
||||
//
|
||||
//
|
||||
// Skybox Portal
|
||||
//
|
||||
//
|
||||
//-----------------------------------------------------------------------------
|
||||
//-----------------------------------------------------------------------------
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
//
|
||||
// GLSkyboxPortal::DrawContents
|
||||
//
|
||||
//-----------------------------------------------------------------------------
|
||||
|
||||
bool HWSkyboxPortal::Setup(HWDrawInfo *di, Clipper *clipper)
|
||||
{
|
||||
auto state = mOwner->mState;
|
||||
old_pm = state->PlaneMirrorMode;
|
||||
|
||||
if (mOwner->mState->skyboxrecursion >= 3)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
auto &vp = di->Viewpoint;
|
||||
|
||||
state->skyboxrecursion++;
|
||||
state->PlaneMirrorMode = 0;
|
||||
state->inskybox = true;
|
||||
|
||||
AActor *origin = portal->mSkybox;
|
||||
portal->mFlags |= PORTSF_INSKYBOX;
|
||||
vp.extralight = 0;
|
||||
|
||||
|
||||
oldclamp = di->SetDepthClamp(false);
|
||||
vp.Pos = origin->InterpolatedPosition(vp.TicFrac);
|
||||
vp.ActorPos = origin->Pos();
|
||||
vp.Angles.Yaw += (origin->PrevAngles.Yaw + deltaangle(origin->PrevAngles.Yaw, origin->Angles.Yaw) * vp.TicFrac);
|
||||
|
||||
// Don't let the viewpoint be too close to a floor or ceiling
|
||||
double floorh = origin->Sector->floorplane.ZatPoint(origin->Pos());
|
||||
double ceilh = origin->Sector->ceilingplane.ZatPoint(origin->Pos());
|
||||
if (vp.Pos.Z < floorh + 4) vp.Pos.Z = floorh + 4;
|
||||
if (vp.Pos.Z > ceilh - 4) vp.Pos.Z = ceilh - 4;
|
||||
|
||||
vp.ViewActor = origin;
|
||||
|
||||
di->SetupView(vp.Pos.X, vp.Pos.Y, vp.Pos.Z, !!(state->MirrorFlag & 1), !!(state->PlaneMirrorFlag & 1));
|
||||
di->SetViewArea();
|
||||
ClearClipper(di, clipper);
|
||||
di->UpdateCurrentMapSection();
|
||||
return true;
|
||||
}
|
||||
|
||||
|
||||
void HWSkyboxPortal::Shutdown(HWDrawInfo *di)
|
||||
{
|
||||
auto state = mOwner->mState;
|
||||
portal->mFlags &= ~PORTSF_INSKYBOX;
|
||||
di->SetDepthClamp(oldclamp);
|
||||
state->inskybox = false;
|
||||
state->skyboxrecursion--;
|
||||
state->PlaneMirrorMode = old_pm;
|
||||
}
|
||||
|
||||
const char *HWSkyboxPortal::GetName() { return "Skybox"; }
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
//-----------------------------------------------------------------------------
|
||||
//
|
||||
//
|
||||
// Sector stack Portal
|
||||
//
|
||||
//
|
||||
//-----------------------------------------------------------------------------
|
||||
//-----------------------------------------------------------------------------
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
//
|
||||
// GLSectorStackPortal::SetupCoverage
|
||||
//
|
||||
//-----------------------------------------------------------------------------
|
||||
|
||||
static uint8_t SetCoverage(HWDrawInfo *di, void *node)
|
||||
{
|
||||
if (level.nodes.Size() == 0)
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
if (!((size_t)node & 1)) // Keep going until found a subsector
|
||||
{
|
||||
node_t *bsp = (node_t *)node;
|
||||
uint8_t coverage = SetCoverage(di, bsp->children[0]) | SetCoverage(di, bsp->children[1]);
|
||||
di->no_renderflags[bsp->Index()] = coverage;
|
||||
return coverage;
|
||||
}
|
||||
else
|
||||
{
|
||||
subsector_t *sub = (subsector_t *)((uint8_t *)node - 1);
|
||||
return di->ss_renderflags[sub->Index()] & SSRF_SEEN;
|
||||
}
|
||||
}
|
||||
|
||||
void HWSectorStackPortal::SetupCoverage(HWDrawInfo *di)
|
||||
{
|
||||
for (unsigned i = 0; i<subsectors.Size(); i++)
|
||||
{
|
||||
subsector_t *sub = subsectors[i];
|
||||
int plane = origin->plane;
|
||||
for (int j = 0; j<sub->portalcoverage[plane].sscount; j++)
|
||||
{
|
||||
subsector_t *dsub = &::level.subsectors[sub->portalcoverage[plane].subsectors[j]];
|
||||
di->CurrentMapSections.Set(dsub->mapsection);
|
||||
di->ss_renderflags[dsub->Index()] |= SSRF_SEEN;
|
||||
}
|
||||
}
|
||||
SetCoverage(di, ::level.HeadNode());
|
||||
}
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
//
|
||||
// GLSectorStackPortal::DrawContents
|
||||
//
|
||||
//-----------------------------------------------------------------------------
|
||||
bool HWSectorStackPortal::Setup(HWDrawInfo *di, Clipper *clipper)
|
||||
{
|
||||
auto state = mOwner->mState;
|
||||
FSectorPortalGroup *portal = origin;
|
||||
auto &vp = di->Viewpoint;
|
||||
|
||||
vp.Pos += origin->mDisplacement;
|
||||
vp.ActorPos += origin->mDisplacement;
|
||||
vp.ViewActor = nullptr;
|
||||
|
||||
// avoid recursions!
|
||||
if (origin->plane != -1) screen->instack[origin->plane]++;
|
||||
|
||||
di->SetupView(vp.Pos.X, vp.Pos.Y, vp.Pos.Z, !!(state->MirrorFlag & 1), !!(state->PlaneMirrorFlag & 1));
|
||||
SetupCoverage(di);
|
||||
ClearClipper(di, clipper);
|
||||
|
||||
// If the viewpoint is not within the portal, we need to invalidate the entire clip area.
|
||||
// The portal will re-validate the necessary parts when its subsectors get traversed.
|
||||
subsector_t *sub = R_PointInSubsector(vp.Pos);
|
||||
if (!(di->ss_renderflags[sub->Index()] & SSRF_SEEN))
|
||||
{
|
||||
clipper->SafeAddClipRange(0, ANGLE_MAX);
|
||||
clipper->SetBlocked(true);
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
|
||||
void HWSectorStackPortal::Shutdown(HWDrawInfo *di)
|
||||
{
|
||||
if (origin->plane != -1) screen->instack[origin->plane]--;
|
||||
}
|
||||
|
||||
const char *HWSectorStackPortal::GetName() { return "Sectorstack"; }
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
//-----------------------------------------------------------------------------
|
||||
//
|
||||
//
|
||||
// Plane Mirror Portal
|
||||
//
|
||||
//
|
||||
//-----------------------------------------------------------------------------
|
||||
//-----------------------------------------------------------------------------
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
//
|
||||
// GLPlaneMirrorPortal::DrawContents
|
||||
//
|
||||
//-----------------------------------------------------------------------------
|
||||
|
||||
bool HWPlaneMirrorPortal::Setup(HWDrawInfo *di, Clipper *clipper)
|
||||
{
|
||||
auto state = mOwner->mState;
|
||||
if (state->renderdepth > r_mirror_recursions)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
// A plane mirror needs to flip the portal exclusion logic because inside the mirror, up is down and down is up.
|
||||
std::swap(screen->instack[sector_t::floor], screen->instack[sector_t::ceiling]);
|
||||
|
||||
auto &vp = di->Viewpoint;
|
||||
old_pm = state->PlaneMirrorMode;
|
||||
|
||||
// the player is always visible in a mirror.
|
||||
vp.showviewer = true;
|
||||
|
||||
double planez = origin->ZatPoint(vp.Pos);
|
||||
vp.Pos.Z = 2 * planez - vp.Pos.Z;
|
||||
vp.ViewActor = nullptr;
|
||||
state->PlaneMirrorMode = origin->fC() < 0 ? -1 : 1;
|
||||
|
||||
state->PlaneMirrorFlag++;
|
||||
di->SetClipHeight(planez, state->PlaneMirrorMode < 0 ? -1.f : 1.f);
|
||||
di->SetupView(vp.Pos.X, vp.Pos.Y, vp.Pos.Z, !!(state->MirrorFlag & 1), !!(state->PlaneMirrorFlag & 1));
|
||||
ClearClipper(di, clipper);
|
||||
|
||||
di->UpdateCurrentMapSection();
|
||||
return true;
|
||||
}
|
||||
|
||||
void HWPlaneMirrorPortal::Shutdown(HWDrawInfo *di)
|
||||
{
|
||||
auto state = mOwner->mState;
|
||||
state->PlaneMirrorFlag--;
|
||||
state->PlaneMirrorMode = old_pm;
|
||||
std::swap(screen->instack[sector_t::floor], screen->instack[sector_t::ceiling]);
|
||||
}
|
||||
|
||||
const char *HWPlaneMirrorPortal::GetName() { return origin->fC() < 0? "Planemirror ceiling" : "Planemirror floor"; }
|
|
@ -1,6 +1,8 @@
|
|||
#pragma once
|
||||
|
||||
#include "portal.h"
|
||||
#include "hw_drawinfo.h"
|
||||
#include "hw_drawstructs.h"
|
||||
#include "hwrenderer/textures/hw_material.h"
|
||||
|
||||
struct GLSkyInfo
|
||||
|
@ -33,12 +35,278 @@ struct GLHorizonInfo
|
|||
PalEntry specialcolor;
|
||||
};
|
||||
|
||||
struct FPortalSceneState;
|
||||
|
||||
class IPortal
|
||||
{
|
||||
friend struct FPortalSceneState;
|
||||
public:
|
||||
FPortalSceneState * mState;
|
||||
TArray<GLWall> lines;
|
||||
|
||||
IPortal(FPortalSceneState *s, bool local);
|
||||
virtual ~IPortal() {}
|
||||
virtual int ClipSeg(seg_t *seg) { return PClip_Inside; }
|
||||
virtual void * GetSource() const = 0; // GetSource MUST be implemented!
|
||||
virtual const char *GetName() = 0;
|
||||
virtual bool IsSky() { return false; }
|
||||
virtual bool NeedCap() { return true; }
|
||||
virtual bool NeedDepthBuffer() { return true; }
|
||||
virtual void DrawContents(HWDrawInfo *di) = 0;
|
||||
virtual void RenderAttached(HWDrawInfo *di) {}
|
||||
virtual bool Start(bool usestencil, bool doquery, HWDrawInfo *outer_di, HWDrawInfo **pDi) = 0;
|
||||
virtual void End(HWDrawInfo *di, bool usestencil) = 0;
|
||||
|
||||
void AddLine(GLWall * l)
|
||||
{
|
||||
lines.Push(*l);
|
||||
}
|
||||
|
||||
void RenderPortal(bool usestencil, bool doquery, HWDrawInfo *outer_di)
|
||||
{
|
||||
// Start may perform an occlusion query. If that returns 0 there
|
||||
// is no need to draw the stencil's contents and there's also no
|
||||
// need to restore the affected area becasue there is none!
|
||||
HWDrawInfo *di;
|
||||
if (Start(usestencil, doquery, outer_di, &di))
|
||||
{
|
||||
DrawContents(di);
|
||||
End(di, usestencil);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
};
|
||||
|
||||
struct FPortalSceneState
|
||||
{
|
||||
int recursion = 0;
|
||||
|
||||
int MirrorFlag = 0;
|
||||
int PlaneMirrorFlag = 0;
|
||||
int renderdepth = 0;
|
||||
|
||||
int PlaneMirrorMode = 0;
|
||||
bool inskybox = 0;
|
||||
|
||||
UniqueList<GLSkyInfo> UniqueSkies;
|
||||
UniqueList<GLHorizonInfo> UniqueHorizons;
|
||||
UniqueList<secplane_t> UniquePlaneMirrors;
|
||||
|
||||
int skyboxrecursion = 0;
|
||||
|
||||
void BeginScene()
|
||||
{
|
||||
UniqueSkies.Clear();
|
||||
UniqueHorizons.Clear();
|
||||
UniquePlaneMirrors.Clear();
|
||||
}
|
||||
|
||||
int GetRecursion() const
|
||||
{
|
||||
return recursion;
|
||||
}
|
||||
|
||||
bool isMirrored() const
|
||||
{
|
||||
return !!((MirrorFlag ^ PlaneMirrorFlag) & 1);
|
||||
}
|
||||
|
||||
void StartFrame();
|
||||
bool RenderFirstSkyPortal(int recursion, HWDrawInfo *outer_di);
|
||||
void EndFrame(HWDrawInfo *outer_di);
|
||||
|
||||
|
||||
};
|
||||
|
||||
inline IPortal::IPortal(FPortalSceneState *s, bool local) : mState(s)
|
||||
{
|
||||
//if (!local) s->portals.Push(this);
|
||||
}
|
||||
|
||||
|
||||
class HWScenePortalBase
|
||||
{
|
||||
protected:
|
||||
IPortal *mOwner;
|
||||
public:
|
||||
HWScenePortalBase() {}
|
||||
virtual ~HWScenePortalBase() {}
|
||||
void SetOwner(IPortal *p) { mOwner = p; }
|
||||
void ClearClipper(HWDrawInfo *di, Clipper *clipper);
|
||||
|
||||
virtual int ClipSeg(seg_t *seg, const DVector3 &viewpos) { return PClip_Inside; }
|
||||
virtual int ClipSubsector(subsector_t *sub) { return PClip_Inside; }
|
||||
virtual int ClipPoint(const DVector2 &pos) { return PClip_Inside; }
|
||||
virtual line_t *ClipLine() { return nullptr; }
|
||||
|
||||
virtual bool IsSky() { return false; }
|
||||
virtual bool NeedCap() { return false; }
|
||||
virtual bool NeedDepthBuffer() { return true; }
|
||||
virtual void * GetSource() const = 0; // GetSource MUST be implemented!
|
||||
virtual const char *GetName() = 0;
|
||||
|
||||
virtual bool Setup(HWDrawInfo *di, Clipper *clipper) = 0;
|
||||
virtual void Shutdown(HWDrawInfo *di) {}
|
||||
virtual void RenderAttached(HWDrawInfo *di) {}
|
||||
|
||||
};
|
||||
|
||||
struct HWLinePortal : public HWScenePortalBase
|
||||
{
|
||||
// this must be the same as at the start of line_t, so that we can pass in this structure directly to P_ClipLineToPortal.
|
||||
vertex_t *v1, *v2; // vertices, from v1 to v2
|
||||
DVector2 delta; // precalculated v2 - v1 for side checking
|
||||
|
||||
angle_t angv1, angv2; // for quick comparisons with a line or subsector
|
||||
|
||||
HWLinePortal(line_t *line)
|
||||
{
|
||||
v1 = line->v1;
|
||||
v2 = line->v2;
|
||||
CalcDelta();
|
||||
}
|
||||
|
||||
HWLinePortal(FLinePortalSpan *line)
|
||||
{
|
||||
if (line->lines[0]->mType != PORTT_LINKED || line->v1 == nullptr)
|
||||
{
|
||||
// For non-linked portals we must check the actual linedef.
|
||||
line_t *lline = line->lines[0]->mDestination;
|
||||
v1 = lline->v1;
|
||||
v2 = lline->v2;
|
||||
}
|
||||
else
|
||||
{
|
||||
// For linked portals we can check the merged span.
|
||||
v1 = line->v1;
|
||||
v2 = line->v2;
|
||||
}
|
||||
CalcDelta();
|
||||
}
|
||||
|
||||
void CalcDelta()
|
||||
{
|
||||
delta = v2->fPos() - v1->fPos();
|
||||
}
|
||||
|
||||
line_t *line()
|
||||
{
|
||||
vertex_t **pv = &v1;
|
||||
return reinterpret_cast<line_t*>(pv);
|
||||
}
|
||||
|
||||
int ClipSeg(seg_t *seg, const DVector3 &viewpos) override;
|
||||
int ClipSubsector(subsector_t *sub) override;
|
||||
int ClipPoint(const DVector2 &pos);
|
||||
bool NeedCap() override { return false; }
|
||||
};
|
||||
|
||||
struct HWMirrorPortal : public HWLinePortal
|
||||
{
|
||||
// mirror portals always consist of single linedefs!
|
||||
line_t * linedef;
|
||||
|
||||
protected:
|
||||
bool Setup(HWDrawInfo *di, Clipper *clipper) override;
|
||||
void Shutdown(HWDrawInfo *di) override;
|
||||
void * GetSource() const override { return linedef; }
|
||||
const char *GetName() override;
|
||||
|
||||
public:
|
||||
|
||||
HWMirrorPortal(line_t * line)
|
||||
: HWLinePortal(line)
|
||||
{
|
||||
linedef = line;
|
||||
}
|
||||
};
|
||||
|
||||
|
||||
struct HWLineToLinePortal : public HWLinePortal
|
||||
{
|
||||
FLinePortalSpan *glport;
|
||||
protected:
|
||||
bool Setup(HWDrawInfo *di, Clipper *clipper) override;
|
||||
virtual void * GetSource() const override { return glport; }
|
||||
virtual const char *GetName() override;
|
||||
virtual line_t *ClipLine() override { return line(); }
|
||||
virtual void RenderAttached(HWDrawInfo *di) override;
|
||||
|
||||
public:
|
||||
|
||||
HWLineToLinePortal(FLinePortalSpan *ll)
|
||||
: HWLinePortal(ll)
|
||||
{
|
||||
glport = ll;
|
||||
}
|
||||
};
|
||||
|
||||
|
||||
struct HWSkyboxPortal : public HWScenePortalBase
|
||||
{
|
||||
bool oldclamp;
|
||||
int old_pm;
|
||||
FSectorPortal * portal;
|
||||
|
||||
protected:
|
||||
bool Setup(HWDrawInfo *di, Clipper *clipper) override;
|
||||
void Shutdown(HWDrawInfo *di) override;
|
||||
virtual void * GetSource() const { return portal; }
|
||||
virtual bool IsSky() { return true; }
|
||||
virtual const char *GetName();
|
||||
|
||||
public:
|
||||
|
||||
|
||||
HWSkyboxPortal(FSectorPortal * pt)
|
||||
{
|
||||
portal = pt;
|
||||
}
|
||||
|
||||
};
|
||||
|
||||
|
||||
struct HWSectorStackPortal : public HWScenePortalBase
|
||||
{
|
||||
TArray<subsector_t *> subsectors;
|
||||
protected:
|
||||
bool Setup(HWDrawInfo *di, Clipper *clipper) override;
|
||||
void Shutdown(HWDrawInfo *di) override;
|
||||
virtual void * GetSource() const { return origin; }
|
||||
virtual bool IsSky() { return true; } // although this isn't a real sky it can be handled as one.
|
||||
virtual const char *GetName();
|
||||
FSectorPortalGroup *origin;
|
||||
|
||||
public:
|
||||
|
||||
HWSectorStackPortal(FSectorPortalGroup *pt)
|
||||
{
|
||||
origin = pt;
|
||||
}
|
||||
void SetupCoverage(HWDrawInfo *di);
|
||||
void AddSubsector(subsector_t *sub)
|
||||
{
|
||||
subsectors.Push(sub);
|
||||
}
|
||||
|
||||
};
|
||||
|
||||
struct HWPlaneMirrorPortal : public HWScenePortalBase
|
||||
{
|
||||
int old_pm;
|
||||
protected:
|
||||
bool Setup(HWDrawInfo *di, Clipper *clipper) override;
|
||||
void Shutdown(HWDrawInfo *di) override;
|
||||
virtual void * GetSource() const { return origin; }
|
||||
virtual const char *GetName();
|
||||
secplane_t * origin;
|
||||
|
||||
public:
|
||||
|
||||
HWPlaneMirrorPortal(secplane_t * pt)
|
||||
{
|
||||
origin = pt;
|
||||
}
|
||||
|
||||
};
|
||||
|
||||
|
|
|
@ -30,68 +30,12 @@
|
|||
#include "r_sky.h"
|
||||
#include "g_levellocals.h"
|
||||
|
||||
#include "hwrenderer/scene/hw_drawinfo.h"
|
||||
#include "hw_drawinfo.h"
|
||||
#include "hw_drawstructs.h"
|
||||
#include "hwrenderer/utility/hw_clock.h"
|
||||
|
||||
sector_t * hw_FakeFlat(sector_t * sec, sector_t * dest, area_t in_area, bool back);
|
||||
|
||||
void HWDrawInfo::ClearBuffers()
|
||||
{
|
||||
for(unsigned int i=0;i< otherfloorplanes.Size();i++)
|
||||
{
|
||||
gl_subsectorrendernode * node = otherfloorplanes[i];
|
||||
while (node)
|
||||
{
|
||||
gl_subsectorrendernode * n = node;
|
||||
node = node->next;
|
||||
delete n;
|
||||
}
|
||||
}
|
||||
otherfloorplanes.Clear();
|
||||
|
||||
for(unsigned int i=0;i< otherceilingplanes.Size();i++)
|
||||
{
|
||||
gl_subsectorrendernode * node = otherceilingplanes[i];
|
||||
while (node)
|
||||
{
|
||||
gl_subsectorrendernode * n = node;
|
||||
node = node->next;
|
||||
delete n;
|
||||
}
|
||||
}
|
||||
otherceilingplanes.Clear();
|
||||
|
||||
// clear all the lists that might not have been cleared already
|
||||
MissingUpperTextures.Clear();
|
||||
MissingLowerTextures.Clear();
|
||||
MissingUpperSegs.Clear();
|
||||
MissingLowerSegs.Clear();
|
||||
SubsectorHacks.Clear();
|
||||
CeilingStacks.Clear();
|
||||
FloorStacks.Clear();
|
||||
HandledSubsectors.Clear();
|
||||
spriteindex = 0;
|
||||
|
||||
CurrentMapSections.Resize(level.NumMapSections);
|
||||
CurrentMapSections.Zero();
|
||||
|
||||
sectorrenderflags.Resize(level.sectors.Size());
|
||||
ss_renderflags.Resize(level.subsectors.Size());
|
||||
no_renderflags.Resize(level.subsectors.Size());
|
||||
|
||||
memset(§orrenderflags[0], 0, level.sectors.Size() * sizeof(sectorrenderflags[0]));
|
||||
memset(&ss_renderflags[0], 0, level.subsectors.Size() * sizeof(ss_renderflags[0]));
|
||||
memset(&no_renderflags[0], 0, level.nodes.Size() * sizeof(no_renderflags[0]));
|
||||
|
||||
mClipPortal = nullptr;
|
||||
}
|
||||
|
||||
void HWDrawInfo::UpdateCurrentMapSection()
|
||||
{
|
||||
const int mapsection = R_PointInSubsector(r_viewpoint.Pos)->mapsection;
|
||||
CurrentMapSections.Set(mapsection);
|
||||
}
|
||||
|
||||
//==========================================================================
|
||||
//
|
||||
// Adds a subsector plane to a sector's render list
|
||||
|
@ -484,7 +428,7 @@ void HWDrawInfo::HandleMissingTextures(area_t in_area)
|
|||
HandledSubsectors.Clear();
|
||||
validcount++;
|
||||
|
||||
if (MissingUpperTextures[i].Planez > r_viewpoint.Pos.Z)
|
||||
if (MissingUpperTextures[i].Planez > Viewpoint.Pos.Z)
|
||||
{
|
||||
// close the hole only if all neighboring sectors are an exact height match
|
||||
// Otherwise just fill in the missing textures.
|
||||
|
@ -556,7 +500,7 @@ void HWDrawInfo::HandleMissingTextures(area_t in_area)
|
|||
HandledSubsectors.Clear();
|
||||
validcount++;
|
||||
|
||||
if (MissingLowerTextures[i].Planez < r_viewpoint.Pos.Z)
|
||||
if (MissingLowerTextures[i].Planez < Viewpoint.Pos.Z)
|
||||
{
|
||||
// close the hole only if all neighboring sectors are an exact height match
|
||||
// Otherwise just fill in the missing textures.
|
||||
|
@ -642,7 +586,7 @@ void HWDrawInfo::DrawUnhandledMissingTextures()
|
|||
// already done!
|
||||
if (seg->linedef->validcount == validcount) continue; // already done
|
||||
seg->linedef->validcount = validcount;
|
||||
if (seg->frontsector->GetPlaneTexZ(sector_t::ceiling) < r_viewpoint.Pos.Z) continue; // out of sight
|
||||
if (seg->frontsector->GetPlaneTexZ(sector_t::ceiling) < Viewpoint.Pos.Z) continue; // out of sight
|
||||
|
||||
// FIXME: The check for degenerate subsectors should be more precise
|
||||
if (seg->PartnerSeg && (seg->PartnerSeg->Subsector->flags & SSECF_DEGENERATE)) continue;
|
||||
|
@ -664,7 +608,7 @@ void HWDrawInfo::DrawUnhandledMissingTextures()
|
|||
if (seg->linedef->validcount == validcount) continue; // already done
|
||||
seg->linedef->validcount = validcount;
|
||||
if (!(sectorrenderflags[seg->backsector->sectornum] & SSRF_RENDERFLOOR)) continue;
|
||||
if (seg->frontsector->GetPlaneTexZ(sector_t::floor) > r_viewpoint.Pos.Z) continue; // out of sight
|
||||
if (seg->frontsector->GetPlaneTexZ(sector_t::floor) > Viewpoint.Pos.Z) continue; // out of sight
|
||||
if (seg->backsector->transdoor) continue;
|
||||
if (seg->backsector->GetTexture(sector_t::floor) == skyflatnum) continue;
|
||||
if (seg->backsector->ValidatePortal(sector_t::floor) != NULL) continue;
|
||||
|
@ -757,7 +701,7 @@ bool HWDrawInfo::CollectSubsectorsFloor(subsector_t * sub, sector_t * anchor)
|
|||
sub->render_sector->GetPlaneTexZ(sector_t::floor) != anchor->GetPlaneTexZ(sector_t::floor) ||
|
||||
sub->render_sector->GetFloorLight() != anchor->GetFloorLight())
|
||||
{
|
||||
if (sub == viewsubsector && r_viewpoint.Pos.Z < anchor->GetPlaneTexZ(sector_t::floor)) inview = true;
|
||||
if (sub == viewsubsector && Viewpoint.Pos.Z < anchor->GetPlaneTexZ(sector_t::floor)) inview = true;
|
||||
HandledSubsectors.Push(sub);
|
||||
}
|
||||
}
|
||||
|
@ -901,9 +845,21 @@ bool HWDrawInfo::CollectSubsectorsCeiling(subsector_t * sub, sector_t * anchor)
|
|||
//
|
||||
//==========================================================================
|
||||
|
||||
void HWDrawInfo::ProcessLowerMinisegs(TArray<seg_t *> &lowersegs)
|
||||
{
|
||||
for(unsigned int j=0;j<lowersegs.Size();j++)
|
||||
{
|
||||
seg_t * seg=lowersegs[j];
|
||||
GLWall wall;
|
||||
wall.ProcessLowerMiniseg(this, seg, seg->Subsector->render_sector, seg->PartnerSeg->Subsector->render_sector);
|
||||
rendered_lines++;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
void HWDrawInfo::HandleHackedSubsectors()
|
||||
{
|
||||
viewsubsector = R_PointInSubsector(r_viewpoint.Pos);
|
||||
viewsubsector = R_PointInSubsector(Viewpoint.Pos);
|
||||
|
||||
// Each subsector may only be processed once in this loop!
|
||||
validcount++;
|
||||
|
|
|
@ -154,8 +154,9 @@ void GLWall::SkyPlane(HWDrawInfo *di, sector_t *sector, int plane, bool allowref
|
|||
}
|
||||
else if (allowreflect && sector->GetReflect(plane) > 0)
|
||||
{
|
||||
if ((plane == sector_t::ceiling && r_viewpoint.Pos.Z > sector->ceilingplane.fD()) ||
|
||||
(plane == sector_t::floor && r_viewpoint.Pos.Z < -sector->floorplane.fD())) return;
|
||||
auto vpz = di->Viewpoint.Pos.Z;
|
||||
if ((plane == sector_t::ceiling && vpz > sector->ceilingplane.fD()) ||
|
||||
(plane == sector_t::floor && vpz < -sector->floorplane.fD())) return;
|
||||
ptype = PORTALTYPE_PLANEMIRROR;
|
||||
planemirror = plane == sector_t::ceiling ? §or->ceilingplane : §or->floorplane;
|
||||
}
|
||||
|
@ -340,7 +341,7 @@ void GLWall::SkyBottom(HWDrawInfo *di, seg_t * seg,sector_t * fs,sector_t * bs,v
|
|||
else
|
||||
{
|
||||
// Special hack for Vrack2b
|
||||
if (bs->floorplane.ZatPoint(r_viewpoint.Pos) > r_viewpoint.Pos.Z) return;
|
||||
if (bs->floorplane.ZatPoint(di->Viewpoint.Pos) > di->Viewpoint.Pos.Z) return;
|
||||
}
|
||||
}
|
||||
zbottom[0]=zbottom[1]=-32768.0f;
|
||||
|
|
|
@ -289,7 +289,7 @@ void FSkyDomeCreator::SetupMatrices(FMaterial *tex, float x_offset, float y_offs
|
|||
// smaller sky textures must be tiled. We restrict it to 128 sky pixels, though
|
||||
modelMatrix.translate(0.f, -1250.f, 0.f);
|
||||
modelMatrix.scale(1.f, 128 / 230.f, 1.f);
|
||||
yscale = 128 / texh; // intentionally left as integer.
|
||||
yscale = float(128 / texh); // intentionally left as integer.
|
||||
}
|
||||
else if (texh < 200)
|
||||
{
|
||||
|
|
|
@ -68,8 +68,9 @@ EXTERN_CVAR(Float, transsouls)
|
|||
//
|
||||
//==========================================================================
|
||||
|
||||
bool GLSprite::CalculateVertices(HWDrawInfo *di, FVector3 *v)
|
||||
bool GLSprite::CalculateVertices(HWDrawInfo *di, FVector3 *v, DVector3 *vp)
|
||||
{
|
||||
const auto &HWAngles = di->Viewpoint.HWAngles;
|
||||
if (actor != nullptr && (actor->renderflags & RF_SPRITETYPEMASK) == RF_FLATSPRITE)
|
||||
{
|
||||
Matrix3x4 mat;
|
||||
|
@ -146,10 +147,10 @@ bool GLSprite::CalculateVertices(HWDrawInfo *di, FVector3 *v)
|
|||
{
|
||||
// [CMB] Rotate relative to camera XY position, not just camera direction,
|
||||
// which is nicer in VR
|
||||
float xrel = xcenter - r_viewpoint.Pos.X;
|
||||
float yrel = ycenter - r_viewpoint.Pos.Y;
|
||||
float xrel = xcenter - vp->X;
|
||||
float yrel = ycenter - vp->Y;
|
||||
float absAngleDeg = RAD2DEG(atan2(-yrel, xrel));
|
||||
float counterRotationDeg = 270. - di->mAngles.Yaw.Degrees; // counteracts existing sprite rotation
|
||||
float counterRotationDeg = 270. - HWAngles.Yaw.Degrees; // counteracts existing sprite rotation
|
||||
float relAngleDeg = counterRotationDeg + absAngleDeg;
|
||||
|
||||
mat.Rotate(0, 1, 0, relAngleDeg);
|
||||
|
@ -157,7 +158,7 @@ bool GLSprite::CalculateVertices(HWDrawInfo *di, FVector3 *v)
|
|||
|
||||
// [fgsfds] calculate yaw vectors
|
||||
float yawvecX = 0, yawvecY = 0, rollDegrees = 0;
|
||||
float angleRad = (270. - di->mAngles.Yaw).Radians();
|
||||
float angleRad = (270. - HWAngles.Yaw).Radians();
|
||||
if (actor) rollDegrees = Angles.Roll.Degrees;
|
||||
if (isFlatSprite)
|
||||
{
|
||||
|
@ -181,7 +182,7 @@ bool GLSprite::CalculateVertices(HWDrawInfo *di, FVector3 *v)
|
|||
if (useOffsets) mat.Translate(xx, zz, yy);
|
||||
if (drawWithXYBillboard)
|
||||
{
|
||||
mat.Rotate(-sin(angleRad), 0, cos(angleRad), -di->mAngles.Pitch.Degrees);
|
||||
mat.Rotate(-sin(angleRad), 0, cos(angleRad), -HWAngles.Pitch.Degrees);
|
||||
}
|
||||
mat.Rotate(cos(angleRad), 0, sin(angleRad), rollDegrees);
|
||||
if (useOffsets) mat.Translate(-xx, -zz, -yy);
|
||||
|
@ -191,7 +192,7 @@ bool GLSprite::CalculateVertices(HWDrawInfo *di, FVector3 *v)
|
|||
// Rotate the sprite about the vector starting at the center of the sprite
|
||||
// triangle strip and with direction orthogonal to where the player is looking
|
||||
// in the x/y plane.
|
||||
mat.Rotate(-sin(angleRad), 0, cos(angleRad), -di->mAngles.Pitch.Degrees);
|
||||
mat.Rotate(-sin(angleRad), 0, cos(angleRad), -HWAngles.Pitch.Degrees);
|
||||
}
|
||||
|
||||
mat.Translate(-xcenter, -zcenter, -ycenter); // retreat from sprite center
|
||||
|
@ -403,7 +404,8 @@ void GLSprite::Process(HWDrawInfo *di, AActor* thing, sector_t * sector, area_t
|
|||
return;
|
||||
}
|
||||
|
||||
AActor *camera = r_viewpoint.camera;
|
||||
const auto &vp = di->Viewpoint;
|
||||
AActor *camera = vp.camera;
|
||||
|
||||
if (thing->renderflags & RF_INVISIBLE || !thing->RenderStyle.IsVisible(thing->Alpha))
|
||||
{
|
||||
|
@ -425,26 +427,26 @@ void GLSprite::Process(HWDrawInfo *di, AActor* thing, sector_t * sector, area_t
|
|||
}
|
||||
|
||||
// [RH] Interpolate the sprite's position to make it look smooth
|
||||
DVector3 thingpos = thing->InterpolatedPosition(r_viewpoint.TicFrac);
|
||||
DVector3 thingpos = thing->InterpolatedPosition(vp.TicFrac);
|
||||
if (thruportal == 1) thingpos += level.Displacements.getOffset(thing->Sector->PortalGroup, sector->PortalGroup);
|
||||
|
||||
// Some added checks if the camera actor is not supposed to be seen. It can happen that some portal setup has this actor in view in which case it may not be skipped here
|
||||
if (thing == camera && !r_viewpoint.showviewer)
|
||||
if (thing == camera && !vp.showviewer)
|
||||
{
|
||||
DVector3 thingorigin = thing->Pos();
|
||||
if (thruportal == 1) thingorigin += level.Displacements.getOffset(thing->Sector->PortalGroup, sector->PortalGroup);
|
||||
if (fabs(thingorigin.X - r_viewpoint.ActorPos.X) < 2 && fabs(thingorigin.Y - r_viewpoint.ActorPos.Y) < 2) return;
|
||||
if (fabs(thingorigin.X - vp.ActorPos.X) < 2 && fabs(thingorigin.Y - vp.ActorPos.Y) < 2) return;
|
||||
}
|
||||
// Thing is invisible if close to the camera.
|
||||
if (thing->renderflags & RF_MAYBEINVISIBLE)
|
||||
{
|
||||
if (fabs(thingpos.X - r_viewpoint.Pos.X) < 32 && fabs(thingpos.Y - r_viewpoint.Pos.Y) < 32) return;
|
||||
if (fabs(thingpos.X - vp.Pos.X) < 32 && fabs(thingpos.Y - vp.Pos.Y) < 32) return;
|
||||
}
|
||||
|
||||
// Too close to the camera. This doesn't look good if it is a sprite.
|
||||
if (fabs(thingpos.X - r_viewpoint.Pos.X) < 2 && fabs(thingpos.Y - r_viewpoint.Pos.Y) < 2)
|
||||
if (fabs(thingpos.X - vp.Pos.X) < 2 && fabs(thingpos.Y - vp.Pos.Y) < 2)
|
||||
{
|
||||
if (r_viewpoint.Pos.Z >= thingpos.Z - 2 && r_viewpoint.Pos.Z <= thingpos.Z + thing->Height + 2)
|
||||
if (vp.Pos.Z >= thingpos.Z - 2 && vp.Pos.Z <= thingpos.Z + thing->Height + 2)
|
||||
{
|
||||
// exclude vertically moving objects from this check.
|
||||
if (!thing->Vel.isZero())
|
||||
|
@ -460,13 +462,13 @@ void GLSprite::Process(HWDrawInfo *di, AActor* thing, sector_t * sector, area_t
|
|||
// don't draw first frame of a player missile
|
||||
if (thing->flags&MF_MISSILE)
|
||||
{
|
||||
if (!(thing->flags7 & MF7_FLYCHEAT) && thing->target == di->mViewActor && di->mViewActor != nullptr)
|
||||
if (!(thing->flags7 & MF7_FLYCHEAT) && thing->target == vp.ViewActor && vp.ViewActor != nullptr)
|
||||
{
|
||||
double speed = thing->Vel.Length();
|
||||
if (speed >= thing->target->radius / 2)
|
||||
{
|
||||
double clipdist = clamp(thing->Speed, thing->target->radius, thing->target->radius * 2);
|
||||
if ((thingpos - r_viewpoint.Pos).LengthSquared() < clipdist * clipdist) return;
|
||||
if ((thingpos - vp.Pos).LengthSquared() < clipdist * clipdist) return;
|
||||
}
|
||||
}
|
||||
thing->flags7 |= MF7_FLYCHEAT; // do this only once for the very first frame, but not if it gets into range again.
|
||||
|
@ -479,7 +481,7 @@ void GLSprite::Process(HWDrawInfo *di, AActor* thing, sector_t * sector, area_t
|
|||
}
|
||||
// disabled because almost none of the actual game code is even remotely prepared for this. If desired, use the INTERPOLATE flag.
|
||||
if (thing->renderflags & RF_INTERPOLATEANGLES)
|
||||
Angles = thing->InterpolatedAngles(r_viewpoint.TicFrac);
|
||||
Angles = thing->InterpolatedAngles(vp.TicFrac);
|
||||
else
|
||||
Angles = thing->Angles;
|
||||
|
||||
|
@ -506,7 +508,7 @@ void GLSprite::Process(HWDrawInfo *di, AActor* thing, sector_t * sector, area_t
|
|||
// [RH] Make floatbobbing a renderer-only effect.
|
||||
if (thing->flags2 & MF2_FLOATBOB)
|
||||
{
|
||||
float fz = thing->GetBobOffset(r_viewpoint.TicFrac);
|
||||
float fz = thing->GetBobOffset(vp.TicFrac);
|
||||
z += fz;
|
||||
}
|
||||
|
||||
|
@ -514,7 +516,7 @@ void GLSprite::Process(HWDrawInfo *di, AActor* thing, sector_t * sector, area_t
|
|||
if (!modelframe)
|
||||
{
|
||||
bool mirror;
|
||||
DAngle ang = (thingpos - r_viewpoint.Pos).Angle();
|
||||
DAngle ang = (thingpos - vp.Pos).Angle();
|
||||
FTextureID patch;
|
||||
// [ZZ] add direct picnum override
|
||||
if (isPicnumOverride)
|
||||
|
@ -531,7 +533,7 @@ void GLSprite::Process(HWDrawInfo *di, AActor* thing, sector_t * sector, area_t
|
|||
int rot;
|
||||
if (!(thing->renderflags & RF_FLATSPRITE) || thing->flags7 & MF7_SPRITEANGLE)
|
||||
{
|
||||
sprangle = thing->GetSpriteAngle(ang, r_viewpoint.TicFrac);
|
||||
sprangle = thing->GetSpriteAngle(ang, vp.TicFrac);
|
||||
rot = -1;
|
||||
}
|
||||
else
|
||||
|
@ -596,8 +598,8 @@ void GLSprite::Process(HWDrawInfo *di, AActor* thing, sector_t * sector, area_t
|
|||
switch (spritetype)
|
||||
{
|
||||
case RF_FACESPRITE:
|
||||
viewvecX = di->mViewVector.X;
|
||||
viewvecY = di->mViewVector.Y;
|
||||
viewvecX = vp.ViewVector.X;
|
||||
viewvecY = vp.ViewVector.Y;
|
||||
|
||||
x1 = x - viewvecY*leftfac;
|
||||
x2 = x - viewvecY*rightfac;
|
||||
|
@ -632,7 +634,7 @@ void GLSprite::Process(HWDrawInfo *di, AActor* thing, sector_t * sector, area_t
|
|||
gltexture = nullptr;
|
||||
}
|
||||
|
||||
depth = FloatToFixed((x - r_viewpoint.Pos.X) * r_viewpoint.TanCos + (y - r_viewpoint.Pos.Y) * r_viewpoint.TanSin);
|
||||
depth = FloatToFixed((x - vp.Pos.X) * vp.TanCos + (y - vp.Pos.Y) * vp.TanSin);
|
||||
|
||||
// light calculation
|
||||
|
||||
|
@ -923,7 +925,8 @@ void GLSprite::ProcessParticle (HWDrawInfo *di, particle_t *particle, sector_t *
|
|||
}
|
||||
}
|
||||
|
||||
double timefrac = r_viewpoint.TicFrac;
|
||||
const auto &vp = di->Viewpoint;
|
||||
double timefrac = vp.TicFrac;
|
||||
if (paused || bglobal.freeze || (level.flags2 & LEVEL2_FROZEN))
|
||||
timefrac = 0.;
|
||||
float xvf = (particle->Vel.X) * timefrac;
|
||||
|
@ -940,8 +943,8 @@ void GLSprite::ProcessParticle (HWDrawInfo *di, particle_t *particle, sector_t *
|
|||
else factor = 1 / 7.f;
|
||||
float scalefac=particle->size * factor;
|
||||
|
||||
float viewvecX = di->mViewVector.X;
|
||||
float viewvecY = di->mViewVector.Y;
|
||||
float viewvecX = vp.ViewVector.X;
|
||||
float viewvecY = vp.ViewVector.Y;
|
||||
|
||||
x1=x+viewvecY*scalefac;
|
||||
x2=x-viewvecY*scalefac;
|
||||
|
@ -950,7 +953,7 @@ void GLSprite::ProcessParticle (HWDrawInfo *di, particle_t *particle, sector_t *
|
|||
z1=z-scalefac;
|
||||
z2=z+scalefac;
|
||||
|
||||
depth = FloatToFixed((x - r_viewpoint.Pos.X) * r_viewpoint.TanCos + (y - r_viewpoint.Pos.Y) * r_viewpoint.TanSin);
|
||||
depth = FloatToFixed((x - vp.Pos.X) * vp.TanCos + (y - vp.Pos.Y) * vp.TanSin);
|
||||
|
||||
actor=nullptr;
|
||||
this->particle=particle;
|
||||
|
@ -980,6 +983,7 @@ void HWDrawInfo::ProcessActorsInPortal(FLinePortalSpan *glport, area_t in_area)
|
|||
TMap<AActor*, bool> processcheck;
|
||||
if (glport->validcount == validcount) return; // only process once per frame
|
||||
glport->validcount = validcount;
|
||||
const auto &vp = Viewpoint;
|
||||
for (auto port : glport->lines)
|
||||
{
|
||||
line_t *line = port->mOrigin;
|
||||
|
@ -1003,9 +1007,9 @@ void HWDrawInfo::ProcessActorsInPortal(FLinePortalSpan *glport, area_t in_area)
|
|||
DVector3 newpos = savedpos;
|
||||
sector_t fakesector;
|
||||
|
||||
if (!r_viewpoint.showviewer && th == r_viewpoint.camera)
|
||||
if (!vp.showviewer && th == vp.camera)
|
||||
{
|
||||
if (fabs(savedpos.X - r_viewpoint.ActorPos.X) < 2 && fabs(savedpos.Y - r_viewpoint.ActorPos.Y) < 2)
|
||||
if (fabs(savedpos.X - vp.ActorPos.X) < 2 && fabs(savedpos.Y - vp.ActorPos.Y) < 2)
|
||||
{
|
||||
continue;
|
||||
}
|
||||
|
|
30
src/hwrenderer/scene/hw_viewpointuniforms.h
Normal file
30
src/hwrenderer/scene/hw_viewpointuniforms.h
Normal file
|
@ -0,0 +1,30 @@
|
|||
#pragma once
|
||||
|
||||
#include "r_data/matrix.h"
|
||||
#include "r_utility.h"
|
||||
|
||||
struct HWViewpointUniforms
|
||||
{
|
||||
VSMatrix mProjectionMatrix;
|
||||
VSMatrix mViewMatrix;
|
||||
VSMatrix mNormalViewMatrix;
|
||||
FVector4 mCameraPos;
|
||||
FVector4 mClipLine;
|
||||
|
||||
float mGlobVis = 1.f;
|
||||
int mPalLightLevels = 0;
|
||||
int mViewHeight = 0;
|
||||
float mClipHeight = 0.f;
|
||||
float mClipHeightDirection = 0.f;
|
||||
|
||||
void CalcDependencies()
|
||||
{
|
||||
mNormalViewMatrix.computeNormalMatrix(mViewMatrix);
|
||||
}
|
||||
|
||||
void SetDefaults();
|
||||
|
||||
};
|
||||
|
||||
|
||||
|
|
@ -169,7 +169,7 @@ void GLWall::PutWall(HWDrawInfo *di, bool translucent)
|
|||
if (translucent)
|
||||
{
|
||||
flags |= GLWF_TRANSLUCENT;
|
||||
ViewDistance = (r_viewpoint.Pos - (seg->linedef->v1->fPos() + seg->linedef->Delta() / 2)).XY().LengthSquared();
|
||||
ViewDistance = (di->Viewpoint.Pos - (seg->linedef->v1->fPos() + seg->linedef->Delta() / 2)).XY().LengthSquared();
|
||||
}
|
||||
|
||||
if (di->isFullbrightScene())
|
||||
|
@ -443,10 +443,11 @@ bool GLWall::DoHorizon(HWDrawInfo *di, seg_t * seg,sector_t * fs, vertex_t * v1,
|
|||
ztop[1] = ztop[0] = fs->GetPlaneTexZ(sector_t::ceiling);
|
||||
zbottom[1] = zbottom[0] = fs->GetPlaneTexZ(sector_t::floor);
|
||||
|
||||
if (r_viewpoint.Pos.Z < fs->GetPlaneTexZ(sector_t::ceiling))
|
||||
auto vpz = di->Viewpoint.Pos.Z;
|
||||
if (vpz < fs->GetPlaneTexZ(sector_t::ceiling))
|
||||
{
|
||||
if (r_viewpoint.Pos.Z > fs->GetPlaneTexZ(sector_t::floor))
|
||||
zbottom[1] = zbottom[0] = r_viewpoint.Pos.Z;
|
||||
if (vpz > fs->GetPlaneTexZ(sector_t::floor))
|
||||
zbottom[1] = zbottom[0] = vpz;
|
||||
|
||||
if (fs->GetTexture(sector_t::ceiling) == skyflatnum)
|
||||
{
|
||||
|
@ -474,7 +475,7 @@ bool GLWall::DoHorizon(HWDrawInfo *di, seg_t * seg,sector_t * fs, vertex_t * v1,
|
|||
ztop[1] = ztop[0] = zbottom[0];
|
||||
}
|
||||
|
||||
if (r_viewpoint.Pos.Z > fs->GetPlaneTexZ(sector_t::floor))
|
||||
if (vpz > fs->GetPlaneTexZ(sector_t::floor))
|
||||
{
|
||||
zbottom[1] = zbottom[0] = fs->GetPlaneTexZ(sector_t::floor);
|
||||
if (fs->GetTexture(sector_t::floor) == skyflatnum)
|
||||
|
@ -1457,7 +1458,7 @@ void GLWall::Process(HWDrawInfo *di, seg_t *seg, sector_t * frontsector, sector_
|
|||
sector_t * segback;
|
||||
|
||||
#ifdef _DEBUG
|
||||
if (seg->linedef->Index() == 10)
|
||||
if (seg->linedef->Index() == 3407)
|
||||
{
|
||||
int a = 0;
|
||||
}
|
||||
|
|
|
@ -76,10 +76,10 @@ static bool isBright(DPSprite *psp)
|
|||
//
|
||||
//==========================================================================
|
||||
|
||||
static WeaponPosition GetWeaponPosition(player_t *player)
|
||||
static WeaponPosition GetWeaponPosition(player_t *player, double ticFrac)
|
||||
{
|
||||
WeaponPosition w;
|
||||
P_BobWeapon(player, &w.bobx, &w.boby, r_viewpoint.TicFrac);
|
||||
P_BobWeapon(player, &w.bobx, &w.boby, ticFrac);
|
||||
|
||||
// Interpolate the main weapon layer once so as to be able to add it to other layers.
|
||||
if ((w.weapon = player->FindPSprite(PSP_WEAPON)) != nullptr)
|
||||
|
@ -91,8 +91,8 @@ static WeaponPosition GetWeaponPosition(player_t *player)
|
|||
}
|
||||
else
|
||||
{
|
||||
w.wx = (float)(w.weapon->oldx + (w.weapon->x - w.weapon->oldx) * r_viewpoint.TicFrac);
|
||||
w.wy = (float)(w.weapon->oldy + (w.weapon->y - w.weapon->oldy) * r_viewpoint.TicFrac);
|
||||
w.wx = (float)(w.weapon->oldx + (w.weapon->x - w.weapon->oldx) * ticFrac);
|
||||
w.wy = (float)(w.weapon->oldy + (w.weapon->y - w.weapon->oldy) * ticFrac);
|
||||
}
|
||||
}
|
||||
else
|
||||
|
@ -109,7 +109,7 @@ static WeaponPosition GetWeaponPosition(player_t *player)
|
|||
//
|
||||
//==========================================================================
|
||||
|
||||
static FVector2 BobWeapon(WeaponPosition &weap, DPSprite *psp)
|
||||
static FVector2 BobWeapon(WeaponPosition &weap, DPSprite *psp, double ticFrac)
|
||||
{
|
||||
if (psp->firstTic)
|
||||
{ // Can't interpolate the first tic.
|
||||
|
@ -118,8 +118,8 @@ static FVector2 BobWeapon(WeaponPosition &weap, DPSprite *psp)
|
|||
psp->oldy = psp->y;
|
||||
}
|
||||
|
||||
float sx = float(psp->oldx + (psp->x - psp->oldx) * r_viewpoint.TicFrac);
|
||||
float sy = float(psp->oldy + (psp->y - psp->oldy) * r_viewpoint.TicFrac);
|
||||
float sx = float(psp->oldx + (psp->x - psp->oldx) * ticFrac);
|
||||
float sy = float(psp->oldy + (psp->y - psp->oldy) * ticFrac);
|
||||
|
||||
if (psp->Flags & PSPF_ADDBOB)
|
||||
{
|
||||
|
@ -169,14 +169,14 @@ static WeaponLighting GetWeaponLighting(sector_t *viewsector, const DVector3 &po
|
|||
|
||||
if (i<lightlist.Size() - 1)
|
||||
{
|
||||
lightbottom = lightlist[i + 1].plane.ZatPoint(r_viewpoint.Pos);
|
||||
lightbottom = lightlist[i + 1].plane.ZatPoint(pos);
|
||||
}
|
||||
else
|
||||
{
|
||||
lightbottom = viewsector->floorplane.ZatPoint(r_viewpoint.Pos);
|
||||
lightbottom = viewsector->floorplane.ZatPoint(pos);
|
||||
}
|
||||
|
||||
if (lightbottom<r_viewpoint.Pos.Z)
|
||||
if (lightbottom < pos.Z)
|
||||
{
|
||||
l.cm = lightlist[i].extra_colormap;
|
||||
l.lightlevel = hw_ClampLight(*lightlist[i].p_lightlevel);
|
||||
|
@ -426,8 +426,10 @@ void HWDrawInfo::PreparePlayerSprites(sector_t * viewsector, area_t in_area)
|
|||
AActor * playermo = players[consoleplayer].camera;
|
||||
player_t * player = playermo->player;
|
||||
const bool hudModelStep = IsHUDModelForPlayerAvailable(player);
|
||||
|
||||
const auto &vp = Viewpoint;
|
||||
|
||||
AActor *camera = r_viewpoint.camera;
|
||||
AActor *camera = vp.camera;
|
||||
|
||||
// this is the same as the software renderer
|
||||
if (!player ||
|
||||
|
@ -437,8 +439,8 @@ void HWDrawInfo::PreparePlayerSprites(sector_t * viewsector, area_t in_area)
|
|||
(r_deathcamera && camera->health <= 0))
|
||||
return;
|
||||
|
||||
WeaponPosition weap = GetWeaponPosition(camera->player);
|
||||
WeaponLighting light = GetWeaponLighting(viewsector, r_viewpoint.Pos, isFullbrightScene(), in_area, camera->Pos());
|
||||
WeaponPosition weap = GetWeaponPosition(camera->player, vp.TicFrac);
|
||||
WeaponLighting light = GetWeaponLighting(viewsector, vp.Pos, isFullbrightScene(), in_area, camera->Pos());
|
||||
|
||||
// hack alert! Rather than changing everything in the underlying lighting code let's just temporarily change
|
||||
// light mode here to draw the weapon sprite.
|
||||
|
@ -460,7 +462,7 @@ void HWDrawInfo::PreparePlayerSprites(sector_t * viewsector, area_t in_area)
|
|||
|
||||
if (!hudsprite.GetWeaponRenderStyle(psp, camera, viewsector, light)) continue;
|
||||
|
||||
FVector2 spos = BobWeapon(weap, psp);
|
||||
FVector2 spos = BobWeapon(weap, psp, vp.TicFrac);
|
||||
|
||||
hudsprite.dynrgb[0] = hudsprite.dynrgb[1] = hudsprite.dynrgb[2] = 0;
|
||||
hudsprite.lightindex = -1;
|
||||
|
@ -505,7 +507,7 @@ void HWDrawInfo::PrepareTargeterSprites()
|
|||
{
|
||||
AActor * playermo = players[consoleplayer].camera;
|
||||
player_t * player = playermo->player;
|
||||
AActor *camera = r_viewpoint.camera;
|
||||
AActor *camera = Viewpoint.camera;
|
||||
|
||||
// this is the same as above
|
||||
if (!player ||
|
||||
|
|
|
@ -8,6 +8,7 @@ class AActor;
|
|||
enum area_t : int;
|
||||
struct FSpriteModelFrame;
|
||||
struct HWDrawInfo;
|
||||
class FMaterial;
|
||||
|
||||
|
||||
struct WeaponPosition
|
||||
|
|
|
@ -160,8 +160,9 @@ void CheckBench()
|
|||
|
||||
FString compose;
|
||||
|
||||
auto &vp = r_viewpoint;
|
||||
compose.Format("Map %s: \"%s\",\nx = %1.4f, y = %1.4f, z = %1.4f, angle = %1.4f, pitch = %1.4f\n",
|
||||
level.MapName.GetChars(), level.LevelName.GetChars(), r_viewpoint.Pos.X, r_viewpoint.Pos.Y, r_viewpoint.Pos.Z, r_viewpoint.Angles.Yaw.Degrees, r_viewpoint.Angles.Pitch.Degrees);
|
||||
level.MapName.GetChars(), level.LevelName.GetChars(), vp.Pos.X, vp.Pos.Y, vp.Pos.Z, vp.Angles.Yaw.Degrees, vp.Angles.Pitch.Degrees);
|
||||
|
||||
AppendRenderStats(compose);
|
||||
AppendRenderTimes(compose);
|
||||
|
|
|
@ -25,6 +25,7 @@
|
|||
#include "c_dispatch.h"
|
||||
#include "v_video.h"
|
||||
#include "hw_cvars.h"
|
||||
#include "hwrenderer/textures/hw_material.h"
|
||||
#include "menu/menu.h"
|
||||
|
||||
|
||||
|
@ -91,7 +92,7 @@ CUSTOM_CVAR(Float,gl_texture_filter_anisotropic,8.0f,CVAR_ARCHIVE|CVAR_GLOBALCON
|
|||
|
||||
CCMD(gl_flush)
|
||||
{
|
||||
screen->FlushTextures();
|
||||
FMaterial::FlushAll();
|
||||
}
|
||||
|
||||
CUSTOM_CVAR(Int, gl_texture_filter, 4, CVAR_ARCHIVE|CVAR_GLOBALCONFIG|CVAR_NOINITCALL)
|
||||
|
@ -102,7 +103,7 @@ CUSTOM_CVAR(Int, gl_texture_filter, 4, CVAR_ARCHIVE|CVAR_GLOBALCONFIG|CVAR_NOINI
|
|||
|
||||
CUSTOM_CVAR(Bool, gl_texture_usehires, true, CVAR_ARCHIVE|CVAR_NOINITCALL)
|
||||
{
|
||||
screen->FlushTextures();
|
||||
FMaterial::FlushAll();
|
||||
}
|
||||
|
||||
CVAR(Bool, gl_precache, false, CVAR_ARCHIVE)
|
||||
|
|
176
src/hwrenderer/utility/hw_vrmodes.cpp
Normal file
176
src/hwrenderer/utility/hw_vrmodes.cpp
Normal file
|
@ -0,0 +1,176 @@
|
|||
//
|
||||
//---------------------------------------------------------------------------
|
||||
//
|
||||
// Copyright(C) 2015 Christopher Bruns
|
||||
// All rights reserved.
|
||||
//
|
||||
// This program is free software: you can redistribute it and/or modify
|
||||
// it under the terms of the GNU Lesser General Public License as published by
|
||||
// the Free Software Foundation, either version 3 of the License, or
|
||||
// (at your option) any later version.
|
||||
//
|
||||
// This program is distributed in the hope that it will be useful,
|
||||
// but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
// GNU Lesser General Public License for more details.
|
||||
//
|
||||
// You should have received a copy of the GNU Lesser General Public License
|
||||
// along with this program. If not, see http://www.gnu.org/licenses/
|
||||
//
|
||||
//--------------------------------------------------------------------------
|
||||
//
|
||||
/*
|
||||
** gl_stereo_leftright.cpp
|
||||
** Offsets for left and right eye views
|
||||
**
|
||||
*/
|
||||
|
||||
#include "vectors.h" // RAD2DEG
|
||||
#include "doomtype.h" // M_PI
|
||||
#include "hwrenderer/utility/hw_cvars.h"
|
||||
#include "hw_vrmodes.h"
|
||||
#include "v_video.h"
|
||||
|
||||
// Set up 3D-specific console variables:
|
||||
CVAR(Int, vr_mode, 0, CVAR_GLOBALCONFIG)
|
||||
|
||||
// switch left and right eye views
|
||||
CVAR(Bool, vr_swap_eyes, false, CVAR_GLOBALCONFIG)
|
||||
|
||||
// intraocular distance in meters
|
||||
CVAR(Float, vr_ipd, 0.062f, CVAR_ARCHIVE|CVAR_GLOBALCONFIG) // METERS
|
||||
|
||||
// distance between viewer and the display screen
|
||||
CVAR(Float, vr_screendist, 0.80f, CVAR_ARCHIVE | CVAR_GLOBALCONFIG) // METERS
|
||||
|
||||
// default conversion between (vertical) DOOM units and meters
|
||||
CVAR(Float, vr_hunits_per_meter, 41.0f, CVAR_ARCHIVE | CVAR_GLOBALCONFIG) // METERS
|
||||
|
||||
|
||||
#define isqrt2 0.7071067812f
|
||||
static VRMode vrmi_mono = { 1, 1.f, 1.f, 1.f,{ { 0.f, 1.f },{ 0.f, 0.f } } };
|
||||
static VRMode vrmi_stereo = { 2, 1.f, 1.f, 1.f,{ { -.5f, 1.f },{ .5f, 1.f } } };
|
||||
static VRMode vrmi_sbsfull = { 2, .5f, 1.f, 2.f,{ { -.5f, .5f },{ .5f, .5f } } };
|
||||
static VRMode vrmi_sbssquished = { 2, .5f, 1.f, 1.f,{ { -.5f, 1.f },{ .5f, 1.f } } };
|
||||
static VRMode vrmi_lefteye = { 1, 1.f, 1.f, 1.f, { { -.5f, 1.f },{ 0.f, 0.f } } };
|
||||
static VRMode vrmi_righteye = { 1, 1.f, 1.f, 1.f,{ { .5f, 1.f },{ 0.f, 0.f } } };
|
||||
static VRMode vrmi_topbottom = { 2, 1.f, .5f, 1.f,{ { -.5f, 1.f },{ .5f, 1.f } } };
|
||||
static VRMode vrmi_checker = { 2, isqrt2, isqrt2, 1.f,{ { -.5f, 1.f },{ .5f, 1.f } } };
|
||||
|
||||
const VRMode *VRMode::GetVRMode(bool toscreen)
|
||||
{
|
||||
switch (toscreen && vid_rendermode == 4 ? vr_mode : 0)
|
||||
{
|
||||
default:
|
||||
case VR_MONO:
|
||||
return &vrmi_mono;
|
||||
|
||||
case VR_GREENMAGENTA:
|
||||
case VR_REDCYAN:
|
||||
case VR_QUADSTEREO:
|
||||
case VR_AMBERBLUE:
|
||||
return &vrmi_stereo;
|
||||
|
||||
case VR_SIDEBYSIDESQUISHED:
|
||||
case VR_COLUMNINTERLEAVED:
|
||||
return &vrmi_sbssquished;
|
||||
|
||||
case VR_SIDEBYSIDEFULL:
|
||||
return &vrmi_sbsfull;
|
||||
|
||||
case VR_TOPBOTTOM:
|
||||
case VR_ROWINTERLEAVED:
|
||||
return &vrmi_topbottom;
|
||||
|
||||
case VR_LEFTEYEVIEW:
|
||||
return &vrmi_lefteye;
|
||||
|
||||
case VR_RIGHTEYEVIEW:
|
||||
return &vrmi_righteye;
|
||||
|
||||
case VR_CHECKERINTERLEAVED:
|
||||
return &vrmi_checker;
|
||||
}
|
||||
}
|
||||
|
||||
void VRMode::AdjustViewport(DFrameBuffer *screen) const
|
||||
{
|
||||
screen->mSceneViewport.height = (int)(screen->mSceneViewport.height * mVerticalViewportScale);
|
||||
screen->mSceneViewport.top = (int)(screen->mSceneViewport.top * mVerticalViewportScale);
|
||||
screen->mSceneViewport.width = (int)(screen->mSceneViewport.width * mHorizontalViewportScale);
|
||||
screen->mSceneViewport.left = (int)(screen->mSceneViewport.left * mHorizontalViewportScale);
|
||||
|
||||
screen->mScreenViewport.height = (int)(screen->mScreenViewport.height * mVerticalViewportScale);
|
||||
screen->mScreenViewport.top = (int)(screen->mScreenViewport.top * mVerticalViewportScale);
|
||||
screen->mScreenViewport.width = (int)(screen->mScreenViewport.width * mHorizontalViewportScale);
|
||||
screen->mScreenViewport.left = (int)(screen->mScreenViewport.left * mHorizontalViewportScale);
|
||||
}
|
||||
|
||||
VSMatrix VRMode::GetHUDSpriteProjection() const
|
||||
{
|
||||
VSMatrix mat;
|
||||
int w = screen->GetWidth();
|
||||
int h = screen->GetHeight();
|
||||
float scaled_w = w / mWeaponProjectionScale;
|
||||
float left_ofs = (w - scaled_w) / 2.f;
|
||||
mat.ortho(left_ofs, left_ofs + scaled_w, (float)h, 0, -1.0f, 1.0f);
|
||||
return mat;
|
||||
}
|
||||
|
||||
float VREyeInfo::getShift() const
|
||||
{
|
||||
auto res = mShiftFactor * vr_ipd;
|
||||
return vr_swap_eyes ? -res : res;
|
||||
}
|
||||
|
||||
VSMatrix VREyeInfo::GetProjection(float fov, float aspectRatio, float fovRatio) const
|
||||
{
|
||||
VSMatrix result;
|
||||
|
||||
if (mShiftFactor == 0)
|
||||
{
|
||||
float fovy = (float)(2 * RAD2DEG(atan(tan(DEG2RAD(fov) / 2) / fovRatio)));
|
||||
result.perspective(fovy, aspectRatio, screen->GetZNear(), screen->GetZFar());
|
||||
return result;
|
||||
}
|
||||
else
|
||||
{
|
||||
double zNear = screen->GetZNear();
|
||||
double zFar = screen->GetZFar();
|
||||
|
||||
// For stereo 3D, use asymmetric frustum shift in projection matrix
|
||||
// Q: shouldn't shift vary with roll angle, at least for desktop display?
|
||||
// A: No. (lab) roll is not measured on desktop display (yet)
|
||||
double frustumShift = zNear * getShift() / vr_screendist; // meters cancel, leaving doom units
|
||||
// double frustumShift = 0; // Turning off shift for debugging
|
||||
double fH = zNear * tan(DEG2RAD(fov) / 2) / fovRatio;
|
||||
double fW = fH * aspectRatio * mScaleFactor;
|
||||
double left = -fW - frustumShift;
|
||||
double right = fW - frustumShift;
|
||||
double bottom = -fH;
|
||||
double top = fH;
|
||||
|
||||
VSMatrix result(1);
|
||||
result.frustum((float)left, (float)right, (float)bottom, (float)top, (float)zNear, (float)zFar);
|
||||
return result;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
/* virtual */
|
||||
DVector3 VREyeInfo::GetViewShift(float yaw) const
|
||||
{
|
||||
if (mShiftFactor == 0)
|
||||
{
|
||||
// pass-through for Mono view
|
||||
return { 0,0,0 };
|
||||
}
|
||||
else
|
||||
{
|
||||
double dx = -cos(DEG2RAD(yaw)) * vr_hunits_per_meter * getShift();
|
||||
double dy = sin(DEG2RAD(yaw)) * vr_hunits_per_meter * getShift();
|
||||
return { dx, dy, 0 };
|
||||
}
|
||||
}
|
||||
|
47
src/hwrenderer/utility/hw_vrmodes.h
Normal file
47
src/hwrenderer/utility/hw_vrmodes.h
Normal file
|
@ -0,0 +1,47 @@
|
|||
#pragma once
|
||||
|
||||
#include "r_data/matrix.h"
|
||||
|
||||
class DFrameBuffer;
|
||||
|
||||
enum
|
||||
{
|
||||
VR_MONO = 0,
|
||||
VR_GREENMAGENTA = 1,
|
||||
VR_REDCYAN = 2,
|
||||
VR_SIDEBYSIDEFULL = 3,
|
||||
VR_SIDEBYSIDESQUISHED = 4,
|
||||
VR_LEFTEYEVIEW = 5,
|
||||
VR_RIGHTEYEVIEW = 6,
|
||||
VR_QUADSTEREO = 7,
|
||||
VR_AMBERBLUE = 9,
|
||||
VR_TOPBOTTOM = 11,
|
||||
VR_ROWINTERLEAVED = 12,
|
||||
VR_COLUMNINTERLEAVED = 13,
|
||||
VR_CHECKERINTERLEAVED = 14
|
||||
};
|
||||
|
||||
struct VREyeInfo
|
||||
{
|
||||
float mShiftFactor;
|
||||
float mScaleFactor;
|
||||
|
||||
VSMatrix GetProjection(float fov, float aspectRatio, float fovRatio) const;
|
||||
DVector3 GetViewShift(float yaw) const;
|
||||
private:
|
||||
float getShift() const;
|
||||
|
||||
};
|
||||
|
||||
struct VRMode
|
||||
{
|
||||
int mEyeCount;
|
||||
float mHorizontalViewportScale;
|
||||
float mVerticalViewportScale;
|
||||
float mWeaponProjectionScale;
|
||||
VREyeInfo mEyes[2];
|
||||
|
||||
static const VRMode *GetVRMode(bool toscreen = true);
|
||||
void AdjustViewport(DFrameBuffer *fb) const;
|
||||
VSMatrix GetHUDSpriteProjection() const;
|
||||
};
|
|
@ -1,62 +0,0 @@
|
|||
//
|
||||
//---------------------------------------------------------------------------
|
||||
//
|
||||
// Copyright(C) 2015 Christopher Bruns
|
||||
// All rights reserved.
|
||||
//
|
||||
// This program is free software: you can redistribute it and/or modify
|
||||
// it under the terms of the GNU Lesser General Public License as published by
|
||||
// the Free Software Foundation, either version 3 of the License, or
|
||||
// (at your option) any later version.
|
||||
//
|
||||
// This program is distributed in the hope that it will be useful,
|
||||
// but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
// GNU Lesser General Public License for more details.
|
||||
//
|
||||
// You should have received a copy of the GNU Lesser General Public License
|
||||
// along with this program. If not, see http://www.gnu.org/licenses/
|
||||
//
|
||||
//--------------------------------------------------------------------------
|
||||
//
|
||||
/*
|
||||
** scoped_view_shifter.h
|
||||
** Stack-scoped class for temporarily changing camera viewpoint
|
||||
** Used for stereoscopic 3D.
|
||||
**
|
||||
*/
|
||||
|
||||
#ifndef GL_STEREO3D_SCOPED_VIEW_SHIFTER_H_
|
||||
#define GL_STEREO3D_SCOPED_VIEW_SHIFTER_H_
|
||||
|
||||
#include "basictypes.h"
|
||||
#include "vectors.h"
|
||||
|
||||
/**
|
||||
* Temporarily shift
|
||||
*/
|
||||
class ScopedViewShifter
|
||||
{
|
||||
public:
|
||||
ScopedViewShifter(DVector3 &var, float dxyz[3]) // in meters
|
||||
{
|
||||
// save original values
|
||||
mVar = &var;
|
||||
cachedView = var;
|
||||
// modify values
|
||||
var += DVector3(dxyz[0], dxyz[1], dxyz[2]);
|
||||
}
|
||||
|
||||
~ScopedViewShifter()
|
||||
{
|
||||
// restore original values
|
||||
*mVar = cachedView;
|
||||
}
|
||||
|
||||
private:
|
||||
DVector3 *mVar;
|
||||
DVector3 cachedView;
|
||||
};
|
||||
|
||||
|
||||
#endif // GL_STEREO3D_SCOPED_VIEW_SHIFTER_H_
|
|
@ -36,6 +36,25 @@
|
|||
struct MapData
|
||||
{
|
||||
private:
|
||||
struct ResourceHolder
|
||||
{
|
||||
FResourceFile *data = nullptr;
|
||||
|
||||
~ResourceHolder()
|
||||
{
|
||||
delete data;
|
||||
}
|
||||
|
||||
ResourceHolder &operator=(FResourceFile *other) { data = other; return *this; }
|
||||
FResourceFile *operator->() { return data; }
|
||||
operator FResourceFile *() const { return data; }
|
||||
};
|
||||
|
||||
// The order of members here is important
|
||||
// Resource should be destructed after MapLumps as readers may share FResourceLump objects
|
||||
// For example, this is the case when map .wad is loaded from .pk3 file
|
||||
ResourceHolder resource;
|
||||
|
||||
struct MapLump
|
||||
{
|
||||
char Name[8] = { 0 };
|
||||
|
@ -48,13 +67,6 @@ public:
|
|||
bool isText = false;
|
||||
bool InWad = false;
|
||||
int lumpnum = -1;
|
||||
FResourceFile * resource = nullptr;
|
||||
|
||||
~MapData()
|
||||
{
|
||||
if (resource != nullptr) delete resource;
|
||||
resource = nullptr;
|
||||
}
|
||||
|
||||
/*
|
||||
void Seek(unsigned int lumpindex)
|
||||
|
|
|
@ -37,7 +37,7 @@ void PolyRenderModel(PolyRenderThread *thread, const Mat4f &worldToClip, uint32_
|
|||
{
|
||||
PolyModelRenderer renderer(thread, worldToClip, stencilValue);
|
||||
renderer.AddLights(actor);
|
||||
renderer.RenderModel(x, y, z, smf, actor);
|
||||
renderer.RenderModel(x, y, z, smf, actor, r_viewpoint.TicFrac);
|
||||
PolyTriangleDrawer::SetModelVertexShader(thread->DrawQueue, -1, -1, 0.0f);
|
||||
}
|
||||
|
||||
|
|
|
@ -88,7 +88,7 @@ void PolyDrawSectorPortal::SaveGlobals()
|
|||
|
||||
viewpoint.camera = nullptr;
|
||||
viewpoint.sector = Portal->mDestination;
|
||||
R_SetViewAngle(viewpoint, viewwindow);
|
||||
viewpoint.SetViewAngle(viewwindow);
|
||||
|
||||
Portal->mFlags |= PORTSF_INSKYBOX;
|
||||
if (Portal->mPartner > 0) level.sectorPortals[Portal->mPartner].mFlags |= PORTSF_INSKYBOX;
|
||||
|
@ -114,7 +114,7 @@ void PolyDrawSectorPortal::RestoreGlobals()
|
|||
|
||||
//PolyRenderer::Instance()->Light.SetVisibility(savedvisibility);
|
||||
|
||||
R_SetViewAngle(viewpoint, viewwindow);
|
||||
viewpoint.SetViewAngle(viewwindow);
|
||||
}
|
||||
|
||||
/////////////////////////////////////////////////////////////////////////////
|
||||
|
@ -236,7 +236,7 @@ void PolyDrawLinePortal::SaveGlobals()
|
|||
viewpoint.camera = nullptr;
|
||||
viewpoint.sector = R_PointInSubsector(viewpoint.Pos)->sector;
|
||||
|
||||
R_SetViewAngle(viewpoint, viewwindow);
|
||||
viewpoint.SetViewAngle(viewwindow);
|
||||
}
|
||||
|
||||
void PolyDrawLinePortal::RestoreGlobals()
|
||||
|
@ -254,5 +254,5 @@ void PolyDrawLinePortal::RestoreGlobals()
|
|||
viewpoint.camera->renderflags &= ~RF_INVISIBLE;
|
||||
}
|
||||
|
||||
R_SetViewAngle(viewpoint, viewwindow);
|
||||
viewpoint.SetViewAngle(viewwindow);
|
||||
}
|
||||
|
|
|
@ -254,11 +254,6 @@ struct FSectorPortalGroup
|
|||
{
|
||||
DVector2 mDisplacement;
|
||||
int plane;
|
||||
GLSectorStackPortal *glportal; // for quick access to the render data. This is only valid during BSP traversal!
|
||||
|
||||
GLSectorStackPortal *GetRenderState();
|
||||
|
||||
void AddSubsector(subsector_t *sub);
|
||||
};
|
||||
|
||||
|
||||
|
|
|
@ -36,6 +36,14 @@
|
|||
|
||||
#include "v_video.h"
|
||||
|
||||
#ifdef __OBJC__
|
||||
@class NSCursor;
|
||||
@class CocoaWindow;
|
||||
#else
|
||||
typedef struct objc_object NSCursor;
|
||||
typedef struct objc_object CocoaWindow;
|
||||
#endif
|
||||
|
||||
class SystemFrameBuffer : public DFrameBuffer
|
||||
{
|
||||
public:
|
||||
|
@ -50,8 +58,18 @@ public:
|
|||
int GetClientHeight() override;
|
||||
void ToggleFullscreen(bool yes) override;
|
||||
|
||||
void SetMode(bool fullscreen, bool hiDPI);
|
||||
|
||||
static void UseHiDPI(bool hiDPI);
|
||||
static void SetCursor(NSCursor* cursor);
|
||||
static void SetWindowVisible(bool visible);
|
||||
static void SetWindowTitle(const char* title);
|
||||
|
||||
protected:
|
||||
bool UpdatePending;
|
||||
CocoaWindow* m_window;
|
||||
|
||||
bool m_fullscreen;
|
||||
bool m_hiDPI;
|
||||
|
||||
static const uint32_t GAMMA_CHANNEL_SIZE = 256;
|
||||
static const uint32_t GAMMA_CHANNEL_COUNT = 3;
|
||||
|
@ -60,7 +78,10 @@ protected:
|
|||
bool m_supportsGamma;
|
||||
uint16_t m_originalGamma[GAMMA_TABLE_SIZE];
|
||||
|
||||
SystemFrameBuffer();
|
||||
SystemFrameBuffer() {}
|
||||
|
||||
void SetFullscreenMode();
|
||||
void SetWindowedMode();
|
||||
|
||||
void InitializeState();
|
||||
|
||||
|
|
|
@ -487,11 +487,6 @@ void NSEventToGameMousePosition(NSEvent* inEvent, event_t* outEvent)
|
|||
outEvent->data1 = static_cast<int16_t>( viewPos.x);
|
||||
outEvent->data2 = static_cast<int16_t>(frameHeight - viewPos.y);
|
||||
|
||||
// Compensate letterbox adjustment done by cross-platform code
|
||||
// More elegant solution is a bit problematic due to HiDPI/Retina support
|
||||
// What does this do? Add 0?
|
||||
//outEvent->data2 += (screen->GetTrueHeight() - screen->ClientHeight()) / 2;
|
||||
|
||||
screen->ScaleCoordsFromWindow(outEvent->data1, outEvent->data2);
|
||||
}
|
||||
|
||||
|
|
|
@ -2,7 +2,7 @@
|
|||
** i_video.mm
|
||||
**
|
||||
**---------------------------------------------------------------------------
|
||||
** Copyright 2012-2015 Alexey Lysiuk
|
||||
** Copyright 2012-2018 Alexey Lysiuk
|
||||
** All rights reserved.
|
||||
**
|
||||
** Redistribution and use in source and binary forms, with or without
|
||||
|
@ -49,7 +49,6 @@
|
|||
#include "st_console.h"
|
||||
#include "v_text.h"
|
||||
#include "version.h"
|
||||
#include "videomodes.h"
|
||||
|
||||
#include "gl/renderer/gl_renderer.h"
|
||||
#include "gl/system/gl_framebuffer.h"
|
||||
|
@ -96,6 +95,11 @@ EXTERN_CVAR(Int, vid_defwidth)
|
|||
EXTERN_CVAR(Int, vid_defheight)
|
||||
EXTERN_CVAR(Bool, fullscreen)
|
||||
|
||||
CVAR(Int, win_x, -1, CVAR_ARCHIVE | CVAR_GLOBALCONFIG)
|
||||
CVAR(Int, win_y, -1, CVAR_ARCHIVE | CVAR_GLOBALCONFIG)
|
||||
CVAR(Int, win_w, -1, CVAR_ARCHIVE | CVAR_GLOBALCONFIG)
|
||||
CVAR(Int, win_h, -1, CVAR_ARCHIVE | CVAR_GLOBALCONFIG)
|
||||
|
||||
CUSTOM_CVAR(Bool, vid_autoswitch, true, CVAR_ARCHIVE | CVAR_GLOBALCONFIG | CVAR_NOINITCALL)
|
||||
{
|
||||
Printf("You must restart " GAMENAME " to apply graphics switching mode\n");
|
||||
|
@ -154,6 +158,15 @@ namespace
|
|||
[super setTitle:m_title];
|
||||
}
|
||||
|
||||
- (void)frameDidChange:(NSNotification*)notification
|
||||
{
|
||||
const NSRect frame = [self frame];
|
||||
win_x = frame.origin.x;
|
||||
win_y = frame.origin.y;
|
||||
win_w = frame.size.width;
|
||||
win_h = frame.size.height;
|
||||
}
|
||||
|
||||
@end
|
||||
|
||||
|
||||
|
@ -200,28 +213,15 @@ namespace
|
|||
class CocoaVideo : public IVideo
|
||||
{
|
||||
public:
|
||||
CocoaVideo();
|
||||
virtual DFrameBuffer* CreateFrameBuffer() override
|
||||
{
|
||||
auto fb = new OpenGLFrameBuffer(nullptr, fullscreen);
|
||||
|
||||
virtual DFrameBuffer* CreateFrameBuffer();
|
||||
fb->SetMode(fullscreen, vid_hidpi);
|
||||
fb->SetSize(fb->GetClientWidth(), fb->GetClientHeight());
|
||||
|
||||
static void ToggleFullscreen(bool yes);
|
||||
static bool IsFullscreen();
|
||||
static void UseHiDPI(bool hiDPI);
|
||||
static void SetCursor(NSCursor* cursor);
|
||||
static void SetWindowVisible(bool visible);
|
||||
static void SetWindowTitle(const char* title);
|
||||
|
||||
private:
|
||||
CocoaWindow* m_window;
|
||||
|
||||
bool m_fullscreen;
|
||||
bool m_hiDPI;
|
||||
|
||||
void SetFullscreenMode();
|
||||
void SetWindowedMode();
|
||||
void SetMode(bool fullscreen, bool hiDPI);
|
||||
|
||||
static CocoaVideo* GetInstance();
|
||||
return fb;
|
||||
}
|
||||
};
|
||||
|
||||
|
||||
|
@ -264,13 +264,10 @@ extern id appCtrl;
|
|||
namespace
|
||||
{
|
||||
|
||||
CocoaWindow* CreateCocoaWindow(const NSUInteger styleMask)
|
||||
CocoaWindow* CreateWindow(const NSUInteger styleMask)
|
||||
{
|
||||
static const CGFloat TEMP_WIDTH = VideoModes[0].width - 1;
|
||||
static const CGFloat TEMP_HEIGHT = VideoModes[0].height - 1;
|
||||
|
||||
CocoaWindow* const window = [CocoaWindow alloc];
|
||||
[window initWithContentRect:NSMakeRect(0, 0, TEMP_WIDTH, TEMP_HEIGHT)
|
||||
[window initWithContentRect:NSMakeRect(0, 0, vid_defwidth, vid_defheight)
|
||||
styleMask:styleMask
|
||||
backing:NSBackingStoreBuffered
|
||||
defer:NO];
|
||||
|
@ -278,6 +275,16 @@ CocoaWindow* CreateCocoaWindow(const NSUInteger styleMask)
|
|||
[window makeFirstResponder:appCtrl];
|
||||
[window setAcceptsMouseMovedEvents:YES];
|
||||
|
||||
NSNotificationCenter* nc = [NSNotificationCenter defaultCenter];
|
||||
[nc addObserver:window
|
||||
selector:@selector(frameDidChange:)
|
||||
name:NSWindowDidEndLiveResizeNotification
|
||||
object:nil];
|
||||
[nc addObserver:window
|
||||
selector:@selector(frameDidChange:)
|
||||
name:NSWindowDidMoveNotification
|
||||
object:nil];
|
||||
|
||||
return window;
|
||||
}
|
||||
|
||||
|
@ -312,11 +319,14 @@ NSOpenGLPixelFormat* CreatePixelFormat(const NSOpenGLPixelFormatAttribute profil
|
|||
// ---------------------------------------------------------------------------
|
||||
|
||||
|
||||
CocoaVideo::CocoaVideo()
|
||||
: m_window(CreateCocoaWindow(STYLE_MASK_WINDOWED))
|
||||
SystemFrameBuffer::SystemFrameBuffer(void*, const bool fullscreen)
|
||||
: DFrameBuffer(vid_defwidth, vid_defheight)
|
||||
, m_window(CreateWindow(STYLE_MASK_WINDOWED))
|
||||
, m_fullscreen(false)
|
||||
, m_hiDPI(false)
|
||||
{
|
||||
SetFlash(0, 0);
|
||||
|
||||
// Create OpenGL pixel format
|
||||
NSOpenGLPixelFormatAttribute defaultProfile = NSOpenGLProfileVersion3_2Core;
|
||||
|
||||
|
@ -356,183 +366,8 @@ CocoaVideo::CocoaVideo()
|
|||
|
||||
[m_window setContentView:glView];
|
||||
|
||||
FConsoleWindow::GetInstance().Show(false);
|
||||
}
|
||||
// Create table for system-wide gamma correction
|
||||
|
||||
DFrameBuffer* CocoaVideo::CreateFrameBuffer()
|
||||
{
|
||||
PalEntry flashColor = 0;
|
||||
int flashAmount = 0;
|
||||
|
||||
DFrameBuffer* fb = NULL;
|
||||
|
||||
fb = new OpenGLFrameBuffer(NULL, fullscreen);
|
||||
|
||||
fb->SetFlash(flashColor, flashAmount);
|
||||
|
||||
SetMode(fullscreen, vid_hidpi);
|
||||
|
||||
return fb;
|
||||
}
|
||||
|
||||
void CocoaVideo::ToggleFullscreen(bool yes)
|
||||
{
|
||||
if (CocoaVideo* const video = GetInstance())
|
||||
{
|
||||
video->SetMode(yes, video->m_hiDPI);
|
||||
}
|
||||
}
|
||||
|
||||
bool CocoaVideo::IsFullscreen()
|
||||
{
|
||||
CocoaVideo* const video = GetInstance();
|
||||
return NULL == video
|
||||
? false
|
||||
: video->m_fullscreen;
|
||||
}
|
||||
|
||||
void CocoaVideo::UseHiDPI(const bool hiDPI)
|
||||
{
|
||||
if (CocoaVideo* const video = GetInstance())
|
||||
{
|
||||
video->SetMode(video->m_fullscreen, hiDPI);
|
||||
}
|
||||
}
|
||||
|
||||
void CocoaVideo::SetCursor(NSCursor* cursor)
|
||||
{
|
||||
if (CocoaVideo* const video = GetInstance())
|
||||
{
|
||||
NSWindow* const window = video->m_window;
|
||||
CocoaView* const view = [window contentView];
|
||||
|
||||
[view setCursor:cursor];
|
||||
[window invalidateCursorRectsForView:view];
|
||||
}
|
||||
}
|
||||
|
||||
void CocoaVideo::SetWindowVisible(bool visible)
|
||||
{
|
||||
if (CocoaVideo* const video = GetInstance())
|
||||
{
|
||||
if (visible)
|
||||
{
|
||||
[video->m_window orderFront:nil];
|
||||
}
|
||||
else
|
||||
{
|
||||
[video->m_window orderOut:nil];
|
||||
}
|
||||
|
||||
I_SetNativeMouse(!visible);
|
||||
}
|
||||
}
|
||||
|
||||
void CocoaVideo::SetWindowTitle(const char* title)
|
||||
{
|
||||
if (CocoaVideo* const video = GetInstance())
|
||||
{
|
||||
NSString* const nsTitle = nullptr == title ? nil :
|
||||
[NSString stringWithCString:title encoding:NSISOLatin1StringEncoding];
|
||||
[video->m_window setTitle:nsTitle];
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
void CocoaVideo::SetFullscreenMode()
|
||||
{
|
||||
NSScreen* screen = [m_window screen];
|
||||
|
||||
const NSRect screenFrame = [screen frame];
|
||||
const NSRect displayRect = vid_hidpi
|
||||
? [screen convertRectToBacking:screenFrame]
|
||||
: screenFrame;
|
||||
|
||||
if (!m_fullscreen)
|
||||
{
|
||||
[m_window setLevel:LEVEL_FULLSCREEN];
|
||||
[m_window setStyleMask:STYLE_MASK_FULLSCREEN];
|
||||
|
||||
[m_window setHidesOnDeactivate:YES];
|
||||
}
|
||||
|
||||
[m_window setFrame:screenFrame display:YES];
|
||||
}
|
||||
|
||||
void CocoaVideo::SetWindowedMode()
|
||||
{
|
||||
const NSSize windowPixelSize = NSMakeSize(vid_defwidth, vid_defheight);
|
||||
const NSSize windowSize = vid_hidpi
|
||||
? [[m_window contentView] convertSizeFromBacking:windowPixelSize]
|
||||
: windowPixelSize;
|
||||
|
||||
if (m_fullscreen)
|
||||
{
|
||||
[m_window setLevel:LEVEL_WINDOWED];
|
||||
[m_window setStyleMask:STYLE_MASK_WINDOWED];
|
||||
|
||||
[m_window setHidesOnDeactivate:NO];
|
||||
}
|
||||
|
||||
[m_window setContentSize:windowSize];
|
||||
[m_window center];
|
||||
[m_window enterFullscreenOnZoom];
|
||||
[m_window exitAppOnClose];
|
||||
}
|
||||
|
||||
void CocoaVideo::SetMode(const bool fullscreen, const bool hiDPI)
|
||||
{
|
||||
if (fullscreen == m_fullscreen
|
||||
&& hiDPI == m_hiDPI)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
NSOpenGLView* const glView = [m_window contentView];
|
||||
[glView setWantsBestResolutionOpenGLSurface:hiDPI];
|
||||
|
||||
if (fullscreen)
|
||||
{
|
||||
SetFullscreenMode();
|
||||
}
|
||||
else
|
||||
{
|
||||
SetWindowedMode();
|
||||
}
|
||||
|
||||
const NSSize viewSize = I_GetContentViewSize(m_window);
|
||||
|
||||
glViewport(0, 0, static_cast<GLsizei>(viewSize.width), static_cast<GLsizei>(viewSize.height));
|
||||
glClearColor(0.0f, 0.0f, 0.0f, 1.0f);
|
||||
glClear(GL_COLOR_BUFFER_BIT);
|
||||
|
||||
[[NSOpenGLContext currentContext] flushBuffer];
|
||||
|
||||
[m_window updateTitle];
|
||||
|
||||
if (![m_window isKeyWindow])
|
||||
{
|
||||
[m_window makeKeyAndOrderFront:nil];
|
||||
}
|
||||
|
||||
m_fullscreen = fullscreen;
|
||||
m_hiDPI = hiDPI;
|
||||
}
|
||||
|
||||
|
||||
CocoaVideo* CocoaVideo::GetInstance()
|
||||
{
|
||||
return static_cast<CocoaVideo*>(Video);
|
||||
}
|
||||
|
||||
|
||||
// ---------------------------------------------------------------------------
|
||||
|
||||
|
||||
SystemFrameBuffer::SystemFrameBuffer(void*, const bool fullscreen)
|
||||
: DFrameBuffer(vid_defwidth, vid_defheight)
|
||||
, UpdatePending(false)
|
||||
{
|
||||
CGGammaValue gammaTable[GAMMA_TABLE_SIZE];
|
||||
uint32_t actualChannelSize;
|
||||
|
||||
|
@ -547,24 +382,29 @@ SystemFrameBuffer::SystemFrameBuffer(void*, const bool fullscreen)
|
|||
m_originalGamma[i] = static_cast<uint16_t>(gammaTable[i] * 65535.0f);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
SystemFrameBuffer::SystemFrameBuffer()
|
||||
{
|
||||
FConsoleWindow::GetInstance().Show(false);
|
||||
}
|
||||
|
||||
SystemFrameBuffer::~SystemFrameBuffer()
|
||||
{
|
||||
NSNotificationCenter* nc = [NSNotificationCenter defaultCenter];
|
||||
[nc removeObserver:m_window
|
||||
name:NSWindowDidMoveNotification
|
||||
object:nil];
|
||||
[nc removeObserver:m_window
|
||||
name:NSWindowDidEndLiveResizeNotification
|
||||
object:nil];
|
||||
}
|
||||
|
||||
bool SystemFrameBuffer::IsFullscreen()
|
||||
{
|
||||
return CocoaVideo::IsFullscreen();
|
||||
return m_fullscreen;
|
||||
}
|
||||
|
||||
void SystemFrameBuffer::ToggleFullscreen(bool yes)
|
||||
{
|
||||
CocoaVideo::ToggleFullscreen(yes);
|
||||
SetMode(yes, m_hiDPI);
|
||||
}
|
||||
|
||||
|
||||
|
@ -610,23 +450,141 @@ void SystemFrameBuffer::ResetGammaTable()
|
|||
}
|
||||
}
|
||||
|
||||
|
||||
int SystemFrameBuffer::GetClientWidth()
|
||||
{
|
||||
NSView *view = [[NSOpenGLContext currentContext] view];
|
||||
NSRect backingBounds = [view convertRectToBacking: [view bounds]];
|
||||
int clientWidth = (int)backingBounds.size.width;
|
||||
const int clientWidth = I_GetContentViewSize(m_window).width;
|
||||
return clientWidth > 0 ? clientWidth : GetWidth();
|
||||
}
|
||||
|
||||
int SystemFrameBuffer::GetClientHeight()
|
||||
{
|
||||
NSView *view = [[NSOpenGLContext currentContext] view];
|
||||
NSRect backingBounds = [view convertRectToBacking: [view bounds]];
|
||||
int clientHeight = (int)backingBounds.size.height;
|
||||
const int clientHeight = I_GetContentViewSize(m_window).height;
|
||||
return clientHeight > 0 ? clientHeight : GetHeight();
|
||||
}
|
||||
|
||||
|
||||
void SystemFrameBuffer::SetFullscreenMode()
|
||||
{
|
||||
if (!m_fullscreen)
|
||||
{
|
||||
[m_window setLevel:LEVEL_FULLSCREEN];
|
||||
[m_window setStyleMask:STYLE_MASK_FULLSCREEN];
|
||||
|
||||
[m_window setHidesOnDeactivate:YES];
|
||||
}
|
||||
|
||||
const NSRect screenFrame = [[m_window screen] frame];
|
||||
[m_window setFrame:screenFrame display:YES];
|
||||
}
|
||||
|
||||
void SystemFrameBuffer::SetWindowedMode()
|
||||
{
|
||||
if (m_fullscreen)
|
||||
{
|
||||
[m_window setLevel:LEVEL_WINDOWED];
|
||||
[m_window setStyleMask:STYLE_MASK_WINDOWED];
|
||||
|
||||
[m_window setHidesOnDeactivate:NO];
|
||||
}
|
||||
|
||||
const bool isFrameValid = win_x >= 0 && win_y >= 0 && win_w > 320 && win_h > 200;
|
||||
const NSRect frameSize = isFrameValid
|
||||
? NSMakeRect(win_x, win_y, win_w, win_h)
|
||||
: NSMakeRect(0, 0, vid_defwidth, vid_defheight);
|
||||
|
||||
[m_window setFrame:frameSize display:YES];
|
||||
[m_window enterFullscreenOnZoom];
|
||||
[m_window exitAppOnClose];
|
||||
}
|
||||
|
||||
void SystemFrameBuffer::SetMode(const bool fullscreen, const bool hiDPI)
|
||||
{
|
||||
NSOpenGLView* const glView = [m_window contentView];
|
||||
[glView setWantsBestResolutionOpenGLSurface:hiDPI];
|
||||
|
||||
if (fullscreen)
|
||||
{
|
||||
SetFullscreenMode();
|
||||
}
|
||||
else
|
||||
{
|
||||
SetWindowedMode();
|
||||
}
|
||||
|
||||
const NSSize viewSize = I_GetContentViewSize(m_window);
|
||||
|
||||
glViewport(0, 0, static_cast<GLsizei>(viewSize.width), static_cast<GLsizei>(viewSize.height));
|
||||
glClearColor(0.0f, 0.0f, 0.0f, 1.0f);
|
||||
glClear(GL_COLOR_BUFFER_BIT);
|
||||
|
||||
[[NSOpenGLContext currentContext] flushBuffer];
|
||||
|
||||
[m_window updateTitle];
|
||||
|
||||
if (![m_window isKeyWindow])
|
||||
{
|
||||
[m_window makeKeyAndOrderFront:nil];
|
||||
}
|
||||
|
||||
m_fullscreen = fullscreen;
|
||||
m_hiDPI = hiDPI;
|
||||
}
|
||||
|
||||
|
||||
static SystemFrameBuffer* GetSystemFrameBuffer()
|
||||
{
|
||||
return static_cast<SystemFrameBuffer*>(screen);
|
||||
}
|
||||
|
||||
void SystemFrameBuffer::UseHiDPI(const bool hiDPI)
|
||||
{
|
||||
if (auto fb = GetSystemFrameBuffer())
|
||||
{
|
||||
fb->SetMode(fb->m_fullscreen, hiDPI);
|
||||
}
|
||||
}
|
||||
|
||||
void SystemFrameBuffer::SetCursor(NSCursor* cursor)
|
||||
{
|
||||
if (auto fb = GetSystemFrameBuffer())
|
||||
{
|
||||
NSWindow* const window = fb->m_window;
|
||||
CocoaView* const view = [window contentView];
|
||||
|
||||
[view setCursor:cursor];
|
||||
[window invalidateCursorRectsForView:view];
|
||||
}
|
||||
}
|
||||
|
||||
void SystemFrameBuffer::SetWindowVisible(bool visible)
|
||||
{
|
||||
if (auto fb = GetSystemFrameBuffer())
|
||||
{
|
||||
if (visible)
|
||||
{
|
||||
[fb->m_window orderFront:nil];
|
||||
}
|
||||
else
|
||||
{
|
||||
[fb->m_window orderOut:nil];
|
||||
}
|
||||
|
||||
I_SetNativeMouse(!visible);
|
||||
}
|
||||
}
|
||||
|
||||
void SystemFrameBuffer::SetWindowTitle(const char* title)
|
||||
{
|
||||
if (auto fb = GetSystemFrameBuffer())
|
||||
{
|
||||
NSString* const nsTitle = nullptr == title ? nil :
|
||||
[NSString stringWithCString:title encoding:NSISOLatin1StringEncoding];
|
||||
[fb->m_window setTitle:nsTitle];
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
// ---------------------------------------------------------------------------
|
||||
|
||||
|
||||
|
@ -667,9 +625,9 @@ void I_SetFPSLimit(int limit)
|
|||
{
|
||||
}
|
||||
|
||||
CUSTOM_CVAR(Bool, vid_hidpi, true, CVAR_ARCHIVE | CVAR_GLOBALCONFIG)
|
||||
CUSTOM_CVAR(Bool, vid_hidpi, true, CVAR_ARCHIVE | CVAR_GLOBALCONFIG | CVAR_NOINITCALL)
|
||||
{
|
||||
CocoaVideo::UseHiDPI(self);
|
||||
SystemFrameBuffer::UseHiDPI(self);
|
||||
}
|
||||
|
||||
|
||||
|
@ -730,7 +688,7 @@ bool I_SetCursor(FTexture* cursorpic)
|
|||
hotSpot:NSMakePoint(0.0f, 0.0f)];
|
||||
}
|
||||
|
||||
CocoaVideo::SetCursor(cursor);
|
||||
SystemFrameBuffer::SetCursor(cursor);
|
||||
|
||||
[pool release];
|
||||
|
||||
|
@ -750,11 +708,11 @@ NSSize I_GetContentViewSize(const NSWindow* const window)
|
|||
|
||||
void I_SetMainWindowVisible(bool visible)
|
||||
{
|
||||
CocoaVideo::SetWindowVisible(visible);
|
||||
SystemFrameBuffer::SetWindowVisible(visible);
|
||||
}
|
||||
|
||||
// each platform has its own specific version of this function.
|
||||
void I_SetWindowTitle(const char* title)
|
||||
{
|
||||
CocoaVideo::SetWindowTitle(title);
|
||||
SystemFrameBuffer::SetWindowTitle(title);
|
||||
}
|
||||
|
|
|
@ -43,7 +43,6 @@
|
|||
#include "c_console.h"
|
||||
#include "c_dispatch.h"
|
||||
#include "dikeys.h"
|
||||
#include "s_sound.h"
|
||||
#include "events.h"
|
||||
|
||||
static void I_CheckGUICapture ();
|
||||
|
@ -57,7 +56,6 @@ extern int paused;
|
|||
CVAR (Bool, use_mouse, true, CVAR_ARCHIVE|CVAR_GLOBALCONFIG)
|
||||
CVAR (Bool, m_noprescale, false, CVAR_ARCHIVE|CVAR_GLOBALCONFIG)
|
||||
CVAR (Bool, m_filter, false, CVAR_ARCHIVE|CVAR_GLOBALCONFIG)
|
||||
CVAR (Bool, i_soundinbackground, false, CVAR_ARCHIVE|CVAR_GLOBALCONFIG)
|
||||
|
||||
EXTERN_CVAR (Bool, fullscreen)
|
||||
|
||||
|
@ -305,20 +303,8 @@ void MessagePump (const SDL_Event &sev)
|
|||
exit (0);
|
||||
|
||||
case SDL_WINDOWEVENT:
|
||||
switch (sev.window.event)
|
||||
{
|
||||
extern bool AppActive;
|
||||
|
||||
case SDL_WINDOWEVENT_FOCUS_GAINED:
|
||||
S_SetSoundPaused(1);
|
||||
AppActive = true;
|
||||
break;
|
||||
|
||||
case SDL_WINDOWEVENT_FOCUS_LOST:
|
||||
S_SetSoundPaused(i_soundinbackground);
|
||||
AppActive = false;
|
||||
break;
|
||||
}
|
||||
extern void ProcessSDLWindowEvent(const SDL_WindowEvent &);
|
||||
ProcessSDLWindowEvent(sev.window);
|
||||
break;
|
||||
|
||||
case SDL_MOUSEBUTTONDOWN:
|
||||
|
|
|
@ -169,10 +169,11 @@ static int DoomSpecificInfo (char *buffer, char *end)
|
|||
}
|
||||
else
|
||||
{
|
||||
p += snprintf (buffer+p, size-p, "\n\nviewx = %f", r_viewpoint.Pos.X);
|
||||
p += snprintf (buffer+p, size-p, "\nviewy = %f", r_viewpoint.Pos.Y);
|
||||
p += snprintf (buffer+p, size-p, "\nviewz = %f", r_viewpoint.Pos.Z);
|
||||
p += snprintf (buffer+p, size-p, "\nviewangle = %f", r_viewpoint.Angles.Yaw.Degrees);
|
||||
auto &vp = r_viewpoint;
|
||||
p += snprintf (buffer+p, size-p, "\n\nviewx = %f", vp.Pos.X);
|
||||
p += snprintf (buffer+p, size-p, "\nviewy = %f", vp.Pos.Y);
|
||||
p += snprintf (buffer+p, size-p, "\nviewz = %f", vp.Pos.Z);
|
||||
p += snprintf (buffer+p, size-p, "\nviewangle = %f", vp.Angles.Yaw.Degrees);
|
||||
}
|
||||
}
|
||||
buffer[p++] = '\n';
|
||||
|
|
|
@ -41,6 +41,7 @@
|
|||
#include "v_video.h"
|
||||
#include "version.h"
|
||||
#include "c_console.h"
|
||||
#include "s_sound.h"
|
||||
|
||||
#include "videomodes.h"
|
||||
#include "hardware.h"
|
||||
|
@ -84,6 +85,13 @@ CUSTOM_CVAR(Bool, gl_es, false, CVAR_ARCHIVE | CVAR_GLOBALCONFIG | CVAR_NOINITCA
|
|||
Printf("This won't take effect until " GAMENAME " is restarted.\n");
|
||||
}
|
||||
|
||||
CVAR(Int, win_x, -1, CVAR_ARCHIVE | CVAR_GLOBALCONFIG)
|
||||
CVAR(Int, win_y, -1, CVAR_ARCHIVE | CVAR_GLOBALCONFIG)
|
||||
CVAR(Int, win_w, -1, CVAR_ARCHIVE | CVAR_GLOBALCONFIG)
|
||||
CVAR(Int, win_h, -1, CVAR_ARCHIVE | CVAR_GLOBALCONFIG)
|
||||
|
||||
CVAR(Bool, i_soundinbackground, false, CVAR_ARCHIVE | CVAR_GLOBALCONFIG)
|
||||
|
||||
CVAR (Int, vid_adapter, 0, CVAR_ARCHIVE | CVAR_GLOBALCONFIG)
|
||||
|
||||
// PRIVATE DATA DEFINITIONS ------------------------------------------------
|
||||
|
@ -111,7 +119,6 @@ SDLGLVideo::SDLGLVideo (int parm)
|
|||
|
||||
SDLGLVideo::~SDLGLVideo ()
|
||||
{
|
||||
if (GLRenderer != NULL) GLRenderer->FlushTextures();
|
||||
}
|
||||
|
||||
DFrameBuffer *SDLGLVideo::CreateFrameBuffer ()
|
||||
|
@ -227,6 +234,20 @@ SystemFrameBuffer::SystemFrameBuffer (void *, bool fullscreen)
|
|||
m_supportsGamma = -1 != SDL_GetWindowGammaRamp(Screen,
|
||||
m_origGamma[0], m_origGamma[1], m_origGamma[2]
|
||||
);
|
||||
|
||||
if (!fullscreen)
|
||||
{
|
||||
if (win_x >= 0 && win_y >= 0)
|
||||
{
|
||||
SDL_SetWindowPosition(Screen, win_x, win_y);
|
||||
}
|
||||
|
||||
if (win_h > 320 && win_w > 200)
|
||||
{
|
||||
SDL_SetWindowSize(Screen, win_w, win_h);
|
||||
}
|
||||
}
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
|
@ -329,6 +350,41 @@ int SystemFrameBuffer::GetClientHeight()
|
|||
}
|
||||
|
||||
|
||||
void ProcessSDLWindowEvent(const SDL_WindowEvent &event)
|
||||
{
|
||||
switch (event.event)
|
||||
{
|
||||
extern bool AppActive;
|
||||
|
||||
case SDL_WINDOWEVENT_FOCUS_GAINED:
|
||||
S_SetSoundPaused(1);
|
||||
AppActive = true;
|
||||
break;
|
||||
|
||||
case SDL_WINDOWEVENT_FOCUS_LOST:
|
||||
S_SetSoundPaused(i_soundinbackground);
|
||||
AppActive = false;
|
||||
break;
|
||||
|
||||
case SDL_WINDOWEVENT_MOVED:
|
||||
if (!fullscreen)
|
||||
{
|
||||
win_x = event.data1;
|
||||
win_y = event.data2;
|
||||
}
|
||||
break;
|
||||
|
||||
case SDL_WINDOWEVENT_RESIZED:
|
||||
if (!fullscreen)
|
||||
{
|
||||
win_w = event.data1;
|
||||
win_h = event.data2;
|
||||
}
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
// each platform has its own specific version of this function.
|
||||
void I_SetWindowTitle(const char* caption)
|
||||
{
|
||||
|
|
|
@ -54,7 +54,7 @@ extern TDeletingArray<FVoxelDef *> VoxelDefs;
|
|||
|
||||
DeletingModelArray Models;
|
||||
|
||||
void FModelRenderer::RenderModel(float x, float y, float z, FSpriteModelFrame *smf, AActor *actor)
|
||||
void FModelRenderer::RenderModel(float x, float y, float z, FSpriteModelFrame *smf, AActor *actor, double ticFrac)
|
||||
{
|
||||
// Setup transformation.
|
||||
|
||||
|
@ -128,7 +128,7 @@ void FModelRenderer::RenderModel(float x, float y, float z, FSpriteModelFrame *s
|
|||
if (actor->renderflags & RF_INTERPOLATEANGLES)
|
||||
{
|
||||
// [Nash] use interpolated angles
|
||||
DRotator Angles = actor->InterpolatedAngles(r_viewpoint.TicFrac);
|
||||
DRotator Angles = actor->InterpolatedAngles(ticFrac);
|
||||
angle = Angles.Yaw.Degrees;
|
||||
}
|
||||
|
||||
|
|
|
@ -60,7 +60,7 @@ class FModelRenderer
|
|||
public:
|
||||
virtual ~FModelRenderer() { }
|
||||
|
||||
void RenderModel(float x, float y, float z, FSpriteModelFrame *modelframe, AActor *actor);
|
||||
void RenderModel(float x, float y, float z, FSpriteModelFrame *modelframe, AActor *actor, double ticFrac);
|
||||
void RenderHUDModel(DPSprite *psp, float ofsx, float ofsy);
|
||||
|
||||
virtual ModelRendererType GetType() const = 0;
|
||||
|
|
|
@ -363,7 +363,6 @@ static void GroupSectorPortals()
|
|||
FSectorPortalGroup *portal = new FSectorPortalGroup;
|
||||
portal->mDisplacement = pair->Key.mDisplacement;
|
||||
portal->plane = (i == 1 ? sector_t::floor : sector_t::ceiling); /**/
|
||||
portal->glportal = NULL;
|
||||
level.portalGroups.Push(portal);
|
||||
for (unsigned j = 0; j < pair->Value.Size(); j++)
|
||||
{
|
||||
|
|
|
@ -180,8 +180,6 @@ struct vertex_t
|
|||
{
|
||||
p.Zero();
|
||||
}
|
||||
|
||||
angle_t GetClipAngle();
|
||||
};
|
||||
|
||||
// Forward of LineDefs, for Sectors.
|
||||
|
|
|
@ -598,17 +598,24 @@ void R_ResetViewInterpolation ()
|
|||
|
||||
//==========================================================================
|
||||
//
|
||||
// R_SetViewAngle
|
||||
// R_SetViewAngle
|
||||
// sets all values derived from the view angle.
|
||||
//
|
||||
//==========================================================================
|
||||
|
||||
void R_SetViewAngle (FRenderViewpoint &viewpoint, const FViewWindow &viewwindow)
|
||||
void FRenderViewpoint::SetViewAngle (const FViewWindow &viewwindow)
|
||||
{
|
||||
viewpoint.Sin = viewpoint.Angles.Yaw.Sin();
|
||||
viewpoint.Cos = viewpoint.Angles.Yaw.Cos();
|
||||
Sin = Angles.Yaw.Sin();
|
||||
Cos = Angles.Yaw.Cos();
|
||||
|
||||
TanSin = viewwindow.FocalTangent * Sin;
|
||||
TanCos = viewwindow.FocalTangent * Cos;
|
||||
|
||||
DVector2 v = Angles.Yaw.ToVector();
|
||||
ViewVector.X = v.X;
|
||||
ViewVector.Y = v.Y;
|
||||
HWAngles.Yaw = float(270.0 - Angles.Yaw.Degrees);
|
||||
|
||||
viewpoint.TanSin = viewwindow.FocalTangent * viewpoint.Sin;
|
||||
viewpoint.TanCos = viewwindow.FocalTangent * viewpoint.Cos;
|
||||
}
|
||||
|
||||
//==========================================================================
|
||||
|
@ -844,7 +851,7 @@ void R_SetupFrame (FRenderViewpoint &viewpoint, FViewWindow &viewwindow, AActor
|
|||
}
|
||||
R_InterpolateView (viewpoint, player, viewpoint.TicFrac, iview);
|
||||
|
||||
R_SetViewAngle (viewpoint, viewwindow);
|
||||
viewpoint.SetViewAngle (viewwindow);
|
||||
|
||||
interpolator.DoInterpolations (viewpoint.TicFrac);
|
||||
|
||||
|
@ -872,7 +879,7 @@ void R_SetupFrame (FRenderViewpoint &viewpoint, FViewWindow &viewwindow, AActor
|
|||
FQuakeJiggers jiggers;
|
||||
|
||||
memset(&jiggers, 0, sizeof(jiggers));
|
||||
if (DEarthquake::StaticGetQuakeIntensities(viewpoint.camera, jiggers) > 0)
|
||||
if (DEarthquake::StaticGetQuakeIntensities(viewpoint.TicFrac, viewpoint.camera, jiggers) > 0)
|
||||
{
|
||||
double quakefactor = r_quakeintensity;
|
||||
DAngle an;
|
||||
|
@ -1009,6 +1016,35 @@ void R_SetupFrame (FRenderViewpoint &viewpoint, FViewWindow &viewwindow, AActor
|
|||
screen->SetClearColor(color);
|
||||
SWRenderer->SetClearColor(color);
|
||||
}
|
||||
else
|
||||
{
|
||||
screen->SetClearColor(GPalette.BlackIndex);
|
||||
}
|
||||
|
||||
|
||||
// And finally some info that is needed for the hardware renderer
|
||||
|
||||
// Scale the pitch to account for the pixel stretching, because the playsim doesn't know about this and treats it as 1:1.
|
||||
// However, to set up a projection matrix this needs to be adjusted.
|
||||
double radPitch = viewpoint.Angles.Pitch.Normalized180().Radians();
|
||||
double angx = cos(radPitch);
|
||||
double angy = sin(radPitch) * level.info->pixelstretch;
|
||||
double alen = sqrt(angx*angx + angy*angy);
|
||||
viewpoint.HWAngles.Pitch = RAD2DEG((float)asin(angy / alen));
|
||||
|
||||
viewpoint.HWAngles.Roll.Degrees = (float)viewpoint.Angles.Roll.Degrees; // copied for convenience.
|
||||
|
||||
// ViewActor only gets set, if the camera actor should not be rendered
|
||||
if (actor->player && actor->player - players == consoleplayer &&
|
||||
((actor->player->cheats & CF_CHASECAM) || (r_deathcamera && actor->health <= 0)) && actor == actor->player->mo)
|
||||
{
|
||||
viewpoint.ViewActor = nullptr;
|
||||
}
|
||||
else
|
||||
{
|
||||
viewpoint.ViewActor = actor;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
|
||||
|
|
|
@ -5,6 +5,7 @@
|
|||
#include "vectors.h"
|
||||
|
||||
class FSerializer;
|
||||
struct FViewWindow;
|
||||
//
|
||||
// Stuff from r_main.h that's needed outside the rendering code.
|
||||
|
||||
|
@ -20,6 +21,9 @@ struct FRenderViewpoint
|
|||
DVector3 Pos; // Camera position
|
||||
DVector3 ActorPos; // Camera actor's position
|
||||
DRotator Angles; // Camera angles
|
||||
FRotator HWAngles; // Actual rotation angles for the hardware renderer
|
||||
DVector2 ViewVector; // HWR only: direction the camera is facing.
|
||||
AActor *ViewActor; // either the same as camera or nullptr
|
||||
|
||||
DVector3 Path[2]; // View path for portal calculations
|
||||
double Cos; // cos(Angles.Yaw)
|
||||
|
@ -36,6 +40,10 @@ struct FRenderViewpoint
|
|||
|
||||
int extralight; // extralight to be added to this viewpoint
|
||||
bool showviewer; // show the camera actor?
|
||||
|
||||
|
||||
void SetViewAngle(const FViewWindow &viewwindow);
|
||||
|
||||
};
|
||||
|
||||
extern FRenderViewpoint r_viewpoint;
|
||||
|
|
File diff suppressed because it is too large
Load diff
|
@ -24,8 +24,16 @@
|
|||
#ifndef ADLDATA_H
|
||||
#define ADLDATA_H
|
||||
|
||||
#include <string.h>
|
||||
#include <stdint.h>
|
||||
|
||||
#pragma pack(push, 1)
|
||||
#define ADLDATA_BYTE_COMPARABLE(T) \
|
||||
inline bool operator==(const T &a, const T &b) \
|
||||
{ return !memcmp(&a, &b, sizeof(T)); } \
|
||||
inline bool operator!=(const T &a, const T &b) \
|
||||
{ return !operator==(a, b); }
|
||||
|
||||
extern const struct adldata
|
||||
{
|
||||
uint32_t modulator_E862, carrier_E862; // See below
|
||||
|
@ -34,22 +42,46 @@ extern const struct adldata
|
|||
|
||||
int8_t finetune;
|
||||
} adl[];
|
||||
ADLDATA_BYTE_COMPARABLE(struct adldata)
|
||||
enum { adlDefaultNumber = 189 };
|
||||
|
||||
extern const struct adlinsdata
|
||||
{
|
||||
enum { Flag_Pseudo4op = 0x01, Flag_NoSound = 0x02 };
|
||||
enum { Flag_Pseudo4op = 0x01, Flag_NoSound = 0x02, Flag_Real4op = 0x04 };
|
||||
|
||||
uint16_t adlno1, adlno2;
|
||||
uint8_t tone;
|
||||
uint8_t flags;
|
||||
uint16_t ms_sound_kon; // Number of milliseconds it produces sound;
|
||||
uint16_t ms_sound_koff;
|
||||
double voice2_fine_tune;
|
||||
double voice2_fine_tune;
|
||||
} adlins[];
|
||||
ADLDATA_BYTE_COMPARABLE(struct adlinsdata)
|
||||
int maxAdlBanks();
|
||||
extern const unsigned short banks[][256];
|
||||
extern const char* const banknames[];
|
||||
|
||||
enum { adlNoteOnMaxTime = 40000 };
|
||||
|
||||
/**
|
||||
* @brief Instrument data with operators included
|
||||
*/
|
||||
struct adlinsdata2
|
||||
{
|
||||
adldata adl[2];
|
||||
uint8_t tone;
|
||||
uint8_t flags;
|
||||
uint16_t ms_sound_kon; // Number of milliseconds it produces sound;
|
||||
uint16_t ms_sound_koff;
|
||||
double voice2_fine_tune;
|
||||
adlinsdata2() {}
|
||||
explicit adlinsdata2(const adlinsdata &d);
|
||||
};
|
||||
ADLDATA_BYTE_COMPARABLE(struct adlinsdata2)
|
||||
|
||||
#undef ADLDATA_BYTE_COMPARABLE
|
||||
#pragma pack(pop)
|
||||
|
||||
/**
|
||||
* @brief Bank global setup
|
||||
*/
|
||||
|
@ -62,4 +94,26 @@ extern const struct AdlBankSetup
|
|||
bool scaleModulators;
|
||||
} adlbanksetup[];
|
||||
|
||||
/**
|
||||
* @brief Conversion of storage formats
|
||||
*/
|
||||
inline adlinsdata2::adlinsdata2(const adlinsdata &d)
|
||||
: tone(d.tone), flags(d.flags),
|
||||
ms_sound_kon(d.ms_sound_kon), ms_sound_koff(d.ms_sound_koff),
|
||||
voice2_fine_tune(d.voice2_fine_tune)
|
||||
{
|
||||
adl[0] = ::adl[d.adlno1];
|
||||
adl[1] = ::adl[d.adlno2];
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Convert external instrument to internal instrument
|
||||
*/
|
||||
void cvt_ADLI_to_FMIns(adlinsdata2 &dst, const struct ADL_Instrument &src);
|
||||
|
||||
/**
|
||||
* @brief Convert internal instrument to external instrument
|
||||
*/
|
||||
void cvt_FMIns_to_ADLI(struct ADL_Instrument &dst, const adlinsdata2 &src);
|
||||
|
||||
#endif //ADLDATA_H
|
||||
|
|
|
@ -37,6 +37,13 @@ static ADL_Version adl_version = {
|
|||
ADLMIDI_VERSION_PATCHLEVEL
|
||||
};
|
||||
|
||||
static const ADLMIDI_AudioFormat adl_DefaultAudioFormat =
|
||||
{
|
||||
ADLMIDI_SampleType_S16,
|
||||
sizeof(int16_t),
|
||||
2 * sizeof(int16_t),
|
||||
};
|
||||
|
||||
/*---------------------------EXPORTS---------------------------*/
|
||||
|
||||
ADLMIDI_EXPORT struct ADL_MIDIPlayer *adl_init(long sample_rate)
|
||||
|
@ -67,7 +74,12 @@ ADLMIDI_EXPORT int adl_setNumChips(ADL_MIDIPlayer *device, int numCards)
|
|||
return -2;
|
||||
|
||||
MIDIplay *play = reinterpret_cast<MIDIplay *>(device->adl_midiPlayer);
|
||||
#ifdef ADLMIDI_HW_OPL
|
||||
(void)numCards;
|
||||
play->m_setup.NumCards = 1;
|
||||
#else
|
||||
play->m_setup.NumCards = static_cast<unsigned int>(numCards);
|
||||
#endif
|
||||
if(play->m_setup.NumCards < 1 || play->m_setup.NumCards > MaxCards)
|
||||
{
|
||||
play->setErrorString("number of chips may only be 1.." MaxCards_STR ".\n");
|
||||
|
@ -108,7 +120,7 @@ ADLMIDI_EXPORT int adl_setBank(ADL_MIDIPlayer *device, int bank)
|
|||
if(static_cast<uint32_t>(bankno) >= NumBanks)
|
||||
{
|
||||
char errBuf[150];
|
||||
snprintf(errBuf, 150, "Embedded bank number may only be 0..%u!\n", (NumBanks - 1));
|
||||
snprintf(errBuf, 150, "Embedded bank number may only be 0..%u!\n", static_cast<unsigned int>(NumBanks - 1));
|
||||
play->setErrorString(errBuf);
|
||||
return -1;
|
||||
}
|
||||
|
@ -131,6 +143,142 @@ ADLMIDI_EXPORT const char *const *adl_getBankNames()
|
|||
return banknames;
|
||||
}
|
||||
|
||||
ADLMIDI_EXPORT int adl_reserveBanks(ADL_MIDIPlayer *device, unsigned banks)
|
||||
{
|
||||
if(!device)
|
||||
return -1;
|
||||
MIDIplay *play = reinterpret_cast<MIDIplay *>(device->adl_midiPlayer);
|
||||
OPL3::BankMap &map = play->opl.dynamic_banks;
|
||||
map.reserve(banks);
|
||||
return (int)map.capacity();
|
||||
}
|
||||
|
||||
ADLMIDI_EXPORT int adl_getBank(ADL_MIDIPlayer *device, const ADL_BankId *idp, int flags, ADL_Bank *bank)
|
||||
{
|
||||
if(!device || !idp || !bank)
|
||||
return -1;
|
||||
|
||||
ADL_BankId id = *idp;
|
||||
if(id.lsb > 127 || id.msb > 127 || id.percussive > 1)
|
||||
return -1;
|
||||
unsigned idnumber = (id.msb << 8) | id.lsb | (id.percussive ? OPL3::PercussionTag : 0);
|
||||
|
||||
MIDIplay *play = reinterpret_cast<MIDIplay *>(device->adl_midiPlayer);
|
||||
OPL3::BankMap &map = play->opl.dynamic_banks;
|
||||
|
||||
OPL3::BankMap::iterator it;
|
||||
if(!(flags & ADLMIDI_Bank_Create))
|
||||
{
|
||||
it = map.find(idnumber);
|
||||
if(it == map.end())
|
||||
return -1;
|
||||
}
|
||||
else
|
||||
{
|
||||
std::pair<uint16_t, OPL3::Bank> value;
|
||||
value.first = idnumber;
|
||||
memset(&value.second, 0, sizeof(value.second));
|
||||
for (unsigned i = 0; i < 128; ++i)
|
||||
value.second.ins[i].flags = adlinsdata::Flag_NoSound;
|
||||
|
||||
std::pair<OPL3::BankMap::iterator, bool> ir;
|
||||
if(flags & ADLMIDI_Bank_CreateRt)
|
||||
{
|
||||
ir = map.insert(value, OPL3::BankMap::do_not_expand_t());
|
||||
if(ir.first == map.end())
|
||||
return -1;
|
||||
}
|
||||
else
|
||||
ir = map.insert(value);
|
||||
it = ir.first;
|
||||
}
|
||||
|
||||
it.to_ptrs(bank->pointer);
|
||||
return 0;
|
||||
}
|
||||
|
||||
ADLMIDI_EXPORT int adl_getBankId(ADL_MIDIPlayer *device, const ADL_Bank *bank, ADL_BankId *id)
|
||||
{
|
||||
if(!device || !bank)
|
||||
return -1;
|
||||
|
||||
OPL3::BankMap::iterator it = OPL3::BankMap::iterator::from_ptrs(bank->pointer);
|
||||
unsigned idnumber = it->first;
|
||||
id->msb = (idnumber >> 8) & 127;
|
||||
id->lsb = idnumber & 127;
|
||||
id->percussive = (idnumber & OPL3::PercussionTag) ? 1 : 0;
|
||||
return 0;
|
||||
}
|
||||
|
||||
ADLMIDI_EXPORT int adl_removeBank(ADL_MIDIPlayer *device, ADL_Bank *bank)
|
||||
{
|
||||
if(!device || !bank)
|
||||
return -1;
|
||||
|
||||
MIDIplay *play = reinterpret_cast<MIDIplay *>(device->adl_midiPlayer);
|
||||
OPL3::BankMap &map = play->opl.dynamic_banks;
|
||||
OPL3::BankMap::iterator it = OPL3::BankMap::iterator::from_ptrs(bank->pointer);
|
||||
size_t size = map.size();
|
||||
map.erase(it);
|
||||
return (map.size() != size) ? 0 : -1;
|
||||
}
|
||||
|
||||
ADLMIDI_EXPORT int adl_getFirstBank(ADL_MIDIPlayer *device, ADL_Bank *bank)
|
||||
{
|
||||
if(!device)
|
||||
return -1;
|
||||
|
||||
MIDIplay *play = reinterpret_cast<MIDIplay *>(device->adl_midiPlayer);
|
||||
OPL3::BankMap &map = play->opl.dynamic_banks;
|
||||
|
||||
OPL3::BankMap::iterator it = map.begin();
|
||||
if(it == map.end())
|
||||
return -1;
|
||||
|
||||
it.to_ptrs(bank->pointer);
|
||||
return 0;
|
||||
}
|
||||
|
||||
ADLMIDI_EXPORT int adl_getNextBank(ADL_MIDIPlayer *device, ADL_Bank *bank)
|
||||
{
|
||||
if(!device)
|
||||
return -1;
|
||||
|
||||
MIDIplay *play = reinterpret_cast<MIDIplay *>(device->adl_midiPlayer);
|
||||
OPL3::BankMap &map = play->opl.dynamic_banks;
|
||||
|
||||
OPL3::BankMap::iterator it = OPL3::BankMap::iterator::from_ptrs(bank->pointer);
|
||||
if(++it == map.end())
|
||||
return -1;
|
||||
|
||||
it.to_ptrs(bank->pointer);
|
||||
return 0;
|
||||
}
|
||||
|
||||
ADLMIDI_EXPORT int adl_getInstrument(ADL_MIDIPlayer *device, const ADL_Bank *bank, unsigned index, ADL_Instrument *ins)
|
||||
{
|
||||
if(!device || !bank || index > 127 || !ins)
|
||||
return 1;
|
||||
|
||||
OPL3::BankMap::iterator it = OPL3::BankMap::iterator::from_ptrs(bank->pointer);
|
||||
cvt_FMIns_to_ADLI(*ins, it->second.ins[index]);
|
||||
ins->version = 0;
|
||||
return 0;
|
||||
}
|
||||
|
||||
ADLMIDI_EXPORT int adl_setInstrument(ADL_MIDIPlayer *device, ADL_Bank *bank, unsigned index, const ADL_Instrument *ins)
|
||||
{
|
||||
if(!device || !bank || index > 127 || !ins)
|
||||
return 1;
|
||||
|
||||
if(ins->version != 0)
|
||||
return 1;
|
||||
|
||||
OPL3::BankMap::iterator it = OPL3::BankMap::iterator::from_ptrs(bank->pointer);
|
||||
cvt_ADLI_to_FMIns(it->second.ins[index], *ins);
|
||||
return 0;
|
||||
}
|
||||
|
||||
ADLMIDI_EXPORT int adl_setNumFourOpsChn(ADL_MIDIPlayer *device, int ops4)
|
||||
{
|
||||
if(!device)
|
||||
|
@ -165,7 +313,9 @@ ADLMIDI_EXPORT void adl_setPercMode(ADL_MIDIPlayer *device, int percmod)
|
|||
if(!device) return;
|
||||
MIDIplay *play = reinterpret_cast<MIDIplay *>(device->adl_midiPlayer);
|
||||
play->m_setup.AdlPercussionMode = percmod;
|
||||
play->opl.AdlPercussionMode = play->m_setup.AdlPercussionMode;
|
||||
play->opl.AdlPercussionMode = play->m_setup.AdlPercussionMode < 0 ?
|
||||
play->opl.dynamic_bank_setup.adLibPercussions :
|
||||
(play->m_setup.AdlPercussionMode != 0);
|
||||
play->opl.updateFlags();
|
||||
}
|
||||
|
||||
|
@ -174,7 +324,9 @@ ADLMIDI_EXPORT void adl_setHVibrato(ADL_MIDIPlayer *device, int hvibro)
|
|||
if(!device) return;
|
||||
MIDIplay *play = reinterpret_cast<MIDIplay *>(device->adl_midiPlayer);
|
||||
play->m_setup.HighVibratoMode = hvibro;
|
||||
play->opl.HighVibratoMode = play->m_setup.HighVibratoMode;
|
||||
play->opl.HighVibratoMode = play->m_setup.HighVibratoMode < 0 ?
|
||||
play->opl.dynamic_bank_setup.deepVibrato :
|
||||
(play->m_setup.HighVibratoMode != 0);
|
||||
play->opl.updateDeepFlags();
|
||||
}
|
||||
|
||||
|
@ -183,7 +335,9 @@ ADLMIDI_EXPORT void adl_setHTremolo(ADL_MIDIPlayer *device, int htremo)
|
|||
if(!device) return;
|
||||
MIDIplay *play = reinterpret_cast<MIDIplay *>(device->adl_midiPlayer);
|
||||
play->m_setup.HighTremoloMode = htremo;
|
||||
play->opl.HighTremoloMode = play->m_setup.HighTremoloMode;
|
||||
play->opl.HighTremoloMode = play->m_setup.HighTremoloMode < 0 ?
|
||||
play->opl.dynamic_bank_setup.deepTremolo :
|
||||
(play->m_setup.HighTremoloMode != 0);
|
||||
play->opl.updateDeepFlags();
|
||||
}
|
||||
|
||||
|
@ -192,7 +346,16 @@ ADLMIDI_EXPORT void adl_setScaleModulators(ADL_MIDIPlayer *device, int smod)
|
|||
if(!device) return;
|
||||
MIDIplay *play = reinterpret_cast<MIDIplay *>(device->adl_midiPlayer);
|
||||
play->m_setup.ScaleModulators = smod;
|
||||
play->opl.ScaleModulators = play->m_setup.ScaleModulators;
|
||||
play->opl.ScaleModulators = play->m_setup.ScaleModulators < 0 ?
|
||||
play->opl.dynamic_bank_setup.scaleModulators :
|
||||
(play->m_setup.ScaleModulators != 0);
|
||||
}
|
||||
|
||||
ADLMIDI_EXPORT void adl_setFullRangeBrightness(struct ADL_MIDIPlayer *device, int fr_brightness)
|
||||
{
|
||||
if(!device) return;
|
||||
MIDIplay *play = reinterpret_cast<MIDIplay *>(device->adl_midiPlayer);
|
||||
play->m_setup.fullRangeBrightnessCC74 = (fr_brightness != 0);
|
||||
}
|
||||
|
||||
ADLMIDI_EXPORT void adl_setLoopEnabled(ADL_MIDIPlayer *device, int loopEn)
|
||||
|
@ -202,12 +365,16 @@ ADLMIDI_EXPORT void adl_setLoopEnabled(ADL_MIDIPlayer *device, int loopEn)
|
|||
play->m_setup.loopingIsEnabled = (loopEn != 0);
|
||||
}
|
||||
|
||||
/* !!!DEPRECATED!!! */
|
||||
ADLMIDI_EXPORT void adl_setLogarithmicVolumes(struct ADL_MIDIPlayer *device, int logvol)
|
||||
{
|
||||
if(!device) return;
|
||||
MIDIplay *play = reinterpret_cast<MIDIplay *>(device->adl_midiPlayer);
|
||||
play->m_setup.LogarithmicVolumes = logvol;
|
||||
play->opl.LogarithmicVolumes = play->m_setup.LogarithmicVolumes;
|
||||
play->m_setup.LogarithmicVolumes = (logvol != 0);
|
||||
if(play->m_setup.LogarithmicVolumes)
|
||||
play->opl.ChangeVolumeRangesModel(ADLMIDI_VolumeModel_NativeOPL3);
|
||||
else
|
||||
play->opl.ChangeVolumeRangesModel(static_cast<ADLMIDI_VolumeModels>(play->opl.m_volumeScale));
|
||||
}
|
||||
|
||||
ADLMIDI_EXPORT void adl_setVolumeRangeModel(struct ADL_MIDIPlayer *device, int volumeModel)
|
||||
|
@ -215,7 +382,10 @@ ADLMIDI_EXPORT void adl_setVolumeRangeModel(struct ADL_MIDIPlayer *device, int v
|
|||
if(!device) return;
|
||||
MIDIplay *play = reinterpret_cast<MIDIplay *>(device->adl_midiPlayer);
|
||||
play->m_setup.VolumeModel = volumeModel;
|
||||
play->opl.ChangeVolumeRangesModel(static_cast<ADLMIDI_VolumeModels>(volumeModel));
|
||||
if(play->m_setup.VolumeModel == ADLMIDI_VolumeModel_AUTO)//Use bank default volume model
|
||||
play->opl.m_volumeScale = (OPL3::VolumesScale)play->opl.dynamic_bank_setup.volumeModel;
|
||||
else
|
||||
play->opl.ChangeVolumeRangesModel(static_cast<ADLMIDI_VolumeModels>(volumeModel));
|
||||
}
|
||||
|
||||
ADLMIDI_EXPORT int adl_openBankFile(struct ADL_MIDIPlayer *device, const char *filePath)
|
||||
|
@ -312,16 +482,64 @@ ADLMIDI_EXPORT int adl_openData(ADL_MIDIPlayer *device, const void *mem, unsigne
|
|||
|
||||
ADLMIDI_EXPORT const char *adl_emulatorName()
|
||||
{
|
||||
#ifdef ADLMIDI_USE_DOSBOX_OPL
|
||||
return "DosBox";
|
||||
#else
|
||||
return "Nuked";
|
||||
#endif
|
||||
return "<adl_emulatorName() is deprecated! Use adl_chipEmulatorName() instead!>";
|
||||
}
|
||||
|
||||
ADLMIDI_EXPORT const char *adl_chipEmulatorName(struct ADL_MIDIPlayer *device)
|
||||
{
|
||||
if(device)
|
||||
{
|
||||
#ifndef ADLMIDI_HW_OPL
|
||||
MIDIplay *play = reinterpret_cast<MIDIplay *>(device->adl_midiPlayer);
|
||||
if(play && !play->opl.cardsOP2.empty())
|
||||
return play->opl.cardsOP2[0]->emulatorName();
|
||||
#else
|
||||
return "Hardware OPL3 chip on 0x330";
|
||||
#endif
|
||||
}
|
||||
return "Unknown";
|
||||
}
|
||||
|
||||
ADLMIDI_EXPORT int adl_switchEmulator(struct ADL_MIDIPlayer *device, int emulator)
|
||||
{
|
||||
if(device)
|
||||
{
|
||||
MIDIplay *play = reinterpret_cast<MIDIplay *>(device->adl_midiPlayer);
|
||||
if(play && (emulator >= 0) && (emulator < ADLMIDI_EMU_end))
|
||||
{
|
||||
play->m_setup.emulator = emulator;
|
||||
adl_reset(device);
|
||||
return 0;
|
||||
}
|
||||
play->setErrorString("OPL3 MIDI: Unknown emulation core!");
|
||||
}
|
||||
return -1;
|
||||
}
|
||||
|
||||
|
||||
ADLMIDI_EXPORT int adl_setRunAtPcmRate(ADL_MIDIPlayer *device, int enabled)
|
||||
{
|
||||
if(device)
|
||||
{
|
||||
MIDIplay *play = reinterpret_cast<MIDIplay *>(device->adl_midiPlayer);
|
||||
if(play)
|
||||
{
|
||||
play->m_setup.runAtPcmRate = (enabled != 0);
|
||||
adl_reset(device);
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
return -1;
|
||||
}
|
||||
|
||||
|
||||
ADLMIDI_EXPORT const char *adl_linkedLibraryVersion()
|
||||
{
|
||||
#if !defined(ADLMIDI_ENABLE_HQ_RESAMPLER)
|
||||
return ADLMIDI_VERSION;
|
||||
#else
|
||||
return ADLMIDI_VERSION " (HQ)";
|
||||
#endif
|
||||
}
|
||||
|
||||
ADLMIDI_EXPORT const ADL_Version *adl_linkedVersion()
|
||||
|
@ -373,9 +591,10 @@ ADLMIDI_EXPORT void adl_reset(struct ADL_MIDIPlayer *device)
|
|||
return;
|
||||
MIDIplay *play = reinterpret_cast<MIDIplay *>(device->adl_midiPlayer);
|
||||
play->m_setup.tick_skip_samples_delay = 0;
|
||||
play->opl.Reset(play->m_setup.PCM_RATE);
|
||||
play->opl.runAtPcmRate = play->m_setup.runAtPcmRate;
|
||||
play->opl.Reset(play->m_setup.emulator, play->m_setup.PCM_RATE, play);
|
||||
play->ch.clear();
|
||||
play->ch.resize(play->opl.NumChannels);
|
||||
play->ch.resize((size_t)play->opl.NumChannels);
|
||||
}
|
||||
|
||||
ADLMIDI_EXPORT double adl_totalTimeLength(struct ADL_MIDIPlayer *device)
|
||||
|
@ -568,31 +787,156 @@ ADLMIDI_EXPORT void adl_setDebugMessageHook(struct ADL_MIDIPlayer *device, ADL_D
|
|||
play->hooks.onDebugMessage_userData = userData;
|
||||
}
|
||||
|
||||
|
||||
|
||||
inline static void SendStereoAudio(int &samples_requested,
|
||||
ssize_t &in_size,
|
||||
short *_in,
|
||||
ssize_t out_pos,
|
||||
short *_out)
|
||||
#ifndef ADLMIDI_HW_OPL
|
||||
template <class Dst>
|
||||
static void CopySamplesRaw(ADL_UInt8 *dstLeft, ADL_UInt8 *dstRight, const int32_t *src,
|
||||
size_t frameCount, unsigned sampleOffset)
|
||||
{
|
||||
if(!in_size)
|
||||
return;
|
||||
size_t offset = static_cast<size_t>(out_pos);
|
||||
size_t inSamples = static_cast<size_t>(in_size * 2);
|
||||
size_t maxSamples = static_cast<size_t>(samples_requested) - offset;
|
||||
size_t toCopy = std::min(maxSamples, inSamples);
|
||||
std::memcpy(_out + out_pos, _in, toCopy * sizeof(short));
|
||||
for(size_t i = 0; i < frameCount; ++i) {
|
||||
*(Dst *)(dstLeft + (i * sampleOffset)) = src[2 * i];
|
||||
*(Dst *)(dstRight + (i * sampleOffset)) = src[(2 * i) + 1];
|
||||
}
|
||||
}
|
||||
|
||||
template <class Dst, class Ret>
|
||||
static void CopySamplesTransformed(ADL_UInt8 *dstLeft, ADL_UInt8 *dstRight, const int32_t *src,
|
||||
size_t frameCount, unsigned sampleOffset,
|
||||
Ret(&transform)(int32_t))
|
||||
{
|
||||
for(size_t i = 0; i < frameCount; ++i) {
|
||||
*(Dst *)(dstLeft + (i * sampleOffset)) = (Dst)transform(src[2 * i]);
|
||||
*(Dst *)(dstRight + (i * sampleOffset)) = (Dst)transform(src[(2 * i) + 1]);
|
||||
}
|
||||
}
|
||||
|
||||
ADLMIDI_EXPORT int adl_play(ADL_MIDIPlayer *device, int sampleCount, short *out)
|
||||
static int SendStereoAudio(int samples_requested,
|
||||
ssize_t in_size,
|
||||
int32_t *_in,
|
||||
ssize_t out_pos,
|
||||
ADL_UInt8 *left,
|
||||
ADL_UInt8 *right,
|
||||
const ADLMIDI_AudioFormat *format)
|
||||
{
|
||||
if(!in_size)
|
||||
return 0;
|
||||
size_t outputOffset = static_cast<size_t>(out_pos);
|
||||
size_t inSamples = static_cast<size_t>(in_size * 2);
|
||||
size_t maxSamples = static_cast<size_t>(samples_requested) - outputOffset;
|
||||
size_t toCopy = std::min(maxSamples, inSamples);
|
||||
|
||||
ADLMIDI_SampleType sampleType = format->type;
|
||||
const unsigned containerSize = format->containerSize;
|
||||
const unsigned sampleOffset = format->sampleOffset;
|
||||
|
||||
left += (outputOffset / 2) * sampleOffset;
|
||||
right += (outputOffset / 2) * sampleOffset;
|
||||
|
||||
typedef int32_t(&pfnConvert)(int32_t);
|
||||
typedef float(&ffnConvert)(int32_t);
|
||||
typedef double(&dfnConvert)(int32_t);
|
||||
|
||||
switch(sampleType) {
|
||||
case ADLMIDI_SampleType_S8:
|
||||
case ADLMIDI_SampleType_U8:
|
||||
{
|
||||
pfnConvert cvt = (sampleType == ADLMIDI_SampleType_S8) ? adl_cvtS8 : adl_cvtU8;
|
||||
switch(containerSize) {
|
||||
case sizeof(int8_t):
|
||||
CopySamplesTransformed<int8_t>(left, right, _in, toCopy / 2, sampleOffset, cvt);
|
||||
break;
|
||||
case sizeof(int16_t):
|
||||
CopySamplesTransformed<int16_t>(left, right, _in, toCopy / 2, sampleOffset, cvt);
|
||||
break;
|
||||
case sizeof(int32_t):
|
||||
CopySamplesTransformed<int32_t>(left, right, _in, toCopy / 2, sampleOffset, cvt);
|
||||
break;
|
||||
default:
|
||||
return -1;
|
||||
}
|
||||
break;
|
||||
}
|
||||
case ADLMIDI_SampleType_S16:
|
||||
case ADLMIDI_SampleType_U16:
|
||||
{
|
||||
pfnConvert cvt = (sampleType == ADLMIDI_SampleType_S16) ? adl_cvtS16 : adl_cvtU16;
|
||||
switch(containerSize) {
|
||||
case sizeof(int16_t):
|
||||
CopySamplesTransformed<int16_t>(left, right, _in, toCopy / 2, sampleOffset, cvt);
|
||||
break;
|
||||
case sizeof(int32_t):
|
||||
CopySamplesRaw<int32_t>(left, right, _in, toCopy / 2, sampleOffset);
|
||||
break;
|
||||
default:
|
||||
return -1;
|
||||
}
|
||||
break;
|
||||
}
|
||||
case ADLMIDI_SampleType_S24:
|
||||
case ADLMIDI_SampleType_U24:
|
||||
{
|
||||
pfnConvert cvt = (sampleType == ADLMIDI_SampleType_S24) ? adl_cvtS24 : adl_cvtU24;
|
||||
switch(containerSize) {
|
||||
case sizeof(int32_t):
|
||||
CopySamplesTransformed<int32_t>(left, right, _in, toCopy / 2, sampleOffset, cvt);
|
||||
break;
|
||||
default:
|
||||
return -1;
|
||||
}
|
||||
break;
|
||||
}
|
||||
case ADLMIDI_SampleType_S32:
|
||||
case ADLMIDI_SampleType_U32:
|
||||
{
|
||||
pfnConvert cvt = (sampleType == ADLMIDI_SampleType_S32) ? adl_cvtS32 : adl_cvtU32;
|
||||
switch(containerSize) {
|
||||
case sizeof(int32_t):
|
||||
CopySamplesTransformed<int32_t>(left, right, _in, toCopy / 2, sampleOffset, cvt);
|
||||
break;
|
||||
default:
|
||||
return -1;
|
||||
}
|
||||
break;
|
||||
}
|
||||
case ADLMIDI_SampleType_F32:
|
||||
{
|
||||
if(containerSize != sizeof(float))
|
||||
return -1;
|
||||
ffnConvert cvt = adl_cvtReal<float>;
|
||||
CopySamplesTransformed<float>(left, right, _in, toCopy / 2, sampleOffset, cvt);
|
||||
break;
|
||||
}
|
||||
case ADLMIDI_SampleType_F64:
|
||||
{
|
||||
if(containerSize != sizeof(double))
|
||||
return -1;
|
||||
dfnConvert cvt = adl_cvtReal<double>;
|
||||
CopySamplesTransformed<double>(left, right, _in, toCopy / 2, sampleOffset, cvt);
|
||||
break;
|
||||
}
|
||||
default:
|
||||
return -1;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
#endif
|
||||
|
||||
ADLMIDI_EXPORT int adl_play(struct ADL_MIDIPlayer *device, int sampleCount, short *out)
|
||||
{
|
||||
return adl_playFormat(device, sampleCount, (ADL_UInt8 *)out, (ADL_UInt8 *)(out + 1), &adl_DefaultAudioFormat);
|
||||
}
|
||||
|
||||
ADLMIDI_EXPORT int adl_playFormat(ADL_MIDIPlayer *device, int sampleCount,
|
||||
ADL_UInt8 *out_left, ADL_UInt8 *out_right,
|
||||
const ADLMIDI_AudioFormat *format)
|
||||
{
|
||||
#ifndef ADLMIDI_DISABLE_MIDI_SEQUENCER
|
||||
#ifdef ADLMIDI_HW_OPL
|
||||
(void)device;
|
||||
(void)sampleCount;
|
||||
(void)out;
|
||||
(void)out_left;
|
||||
(void)out_right;
|
||||
(void)format;
|
||||
return 0;
|
||||
#else
|
||||
sampleCount -= sampleCount % 2; //Avoid even sample requests
|
||||
|
@ -646,33 +990,23 @@ ADLMIDI_EXPORT int adl_play(ADL_MIDIPlayer *device, int sampleCount, short *out)
|
|||
ssize_t in_generatedPhys = in_generatedStereo * 2;
|
||||
//! Unsigned total sample count
|
||||
//fill buffer with zeros
|
||||
int16_t *out_buf = player->outBuf;
|
||||
std::memset(out_buf, 0, static_cast<size_t>(in_generatedPhys) * sizeof(int16_t));
|
||||
int32_t *out_buf = player->outBuf;
|
||||
std::memset(out_buf, 0, static_cast<size_t>(in_generatedPhys) * sizeof(out_buf[0]));
|
||||
unsigned int chips = player->opl.NumCards;
|
||||
if(chips == 1)
|
||||
{
|
||||
#ifdef ADLMIDI_USE_DOSBOX_OPL
|
||||
player->opl.cards[0].GenerateArr(out_buf, &in_generatedStereo);
|
||||
in_generatedPhys = in_generatedStereo * 2;
|
||||
#else
|
||||
OPL3_GenerateStream(&player->opl.cards[0], out_buf, static_cast<Bit32u>(in_generatedStereo));
|
||||
#endif
|
||||
player->opl.cardsOP2[0]->generate32(out_buf, (size_t)in_generatedStereo);
|
||||
}
|
||||
else if(n_periodCountStereo > 0)
|
||||
{
|
||||
/* Generate data from every chip and mix result */
|
||||
for(unsigned card = 0; card < chips; ++card)
|
||||
{
|
||||
#ifdef ADLMIDI_USE_DOSBOX_OPL
|
||||
player->opl.cards[card].GenerateArrMix(out_buf, &in_generatedStereo);
|
||||
in_generatedPhys = in_generatedStereo * 2;
|
||||
#else
|
||||
OPL3_GenerateStreamMix(&player->opl.cards[card], out_buf, static_cast<Bit32u>(in_generatedStereo));
|
||||
#endif
|
||||
}
|
||||
for(size_t card = 0; card < chips; ++card)
|
||||
player->opl.cardsOP2[card]->generateAndMix32(out_buf, (size_t)in_generatedStereo);
|
||||
}
|
||||
|
||||
/* Process it */
|
||||
SendStereoAudio(sampleCount, in_generatedStereo, out_buf, gotten_len, out);
|
||||
if(SendStereoAudio(sampleCount, in_generatedStereo, out_buf, gotten_len, out_left, out_right, format) == -1)
|
||||
return 0;
|
||||
|
||||
left -= (int)in_generatedPhys;
|
||||
gotten_len += (in_generatedPhys) /* - setup.stored_samples*/;
|
||||
|
@ -698,11 +1032,20 @@ ADLMIDI_EXPORT int adl_play(ADL_MIDIPlayer *device, int sampleCount, short *out)
|
|||
|
||||
|
||||
ADLMIDI_EXPORT int adl_generate(struct ADL_MIDIPlayer *device, int sampleCount, short *out)
|
||||
{
|
||||
return adl_generateFormat(device, sampleCount, (ADL_UInt8 *)out, (ADL_UInt8 *)(out + 1), &adl_DefaultAudioFormat);
|
||||
}
|
||||
|
||||
ADLMIDI_EXPORT int adl_generateFormat(struct ADL_MIDIPlayer *device, int sampleCount,
|
||||
ADL_UInt8 *out_left, ADL_UInt8 *out_right,
|
||||
const ADLMIDI_AudioFormat *format)
|
||||
{
|
||||
#ifdef ADLMIDI_HW_OPL
|
||||
(void)device;
|
||||
(void)sampleCount;
|
||||
(void)out;
|
||||
(void)out_left;
|
||||
(void)out_right;
|
||||
(void)format;
|
||||
return 0;
|
||||
#else
|
||||
sampleCount -= sampleCount % 2; //Avoid even sample requests
|
||||
|
@ -739,33 +1082,20 @@ ADLMIDI_EXPORT int adl_generate(struct ADL_MIDIPlayer *device, int sampleCount,
|
|||
ssize_t in_generatedPhys = in_generatedStereo * 2;
|
||||
//! Unsigned total sample count
|
||||
//fill buffer with zeros
|
||||
int16_t *out_buf = player->outBuf;
|
||||
std::memset(out_buf, 0, static_cast<size_t>(in_generatedPhys) * sizeof(int16_t));
|
||||
int32_t *out_buf = player->outBuf;
|
||||
std::memset(out_buf, 0, static_cast<size_t>(in_generatedPhys) * sizeof(out_buf[0]));
|
||||
unsigned int chips = player->opl.NumCards;
|
||||
if(chips == 1)
|
||||
{
|
||||
#ifdef ADLMIDI_USE_DOSBOX_OPL
|
||||
player->opl.cards[0].GenerateArr(out_buf, &in_generatedStereo);
|
||||
in_generatedPhys = in_generatedStereo * 2;
|
||||
#else
|
||||
OPL3_GenerateStream(&player->opl.cards[0], out_buf, static_cast<Bit32u>(in_generatedStereo));
|
||||
#endif
|
||||
}
|
||||
player->opl.cardsOP2[0]->generate32(out_buf, (size_t)in_generatedStereo);
|
||||
else if(n_periodCountStereo > 0)
|
||||
{
|
||||
/* Generate data from every chip and mix result */
|
||||
for(unsigned card = 0; card < chips; ++card)
|
||||
{
|
||||
#ifdef ADLMIDI_USE_DOSBOX_OPL
|
||||
player->opl.cards[card].GenerateArrMix(out_buf, &in_generatedStereo);
|
||||
in_generatedPhys = in_generatedStereo * 2;
|
||||
#else
|
||||
OPL3_GenerateStreamMix(&player->opl.cards[card], out_buf, static_cast<Bit32u>(in_generatedStereo));
|
||||
#endif
|
||||
}
|
||||
player->opl.cardsOP2[card]->generateAndMix32(out_buf, (size_t)in_generatedStereo);
|
||||
}
|
||||
/* Process it */
|
||||
SendStereoAudio(sampleCount, in_generatedStereo, out_buf, gotten_len, out);
|
||||
if(SendStereoAudio(sampleCount, in_generatedStereo, out_buf, gotten_len, out_left, out_right, format) == -1)
|
||||
return 0;
|
||||
|
||||
left -= (int)in_generatedPhys;
|
||||
gotten_len += (in_generatedPhys) /* - setup.stored_samples*/;
|
||||
|
|
|
@ -30,13 +30,14 @@ extern "C" {
|
|||
|
||||
#define ADLMIDI_VERSION_MAJOR 1
|
||||
#define ADLMIDI_VERSION_MINOR 3
|
||||
#define ADLMIDI_VERSION_PATCHLEVEL 2
|
||||
#define ADLMIDI_VERSION_PATCHLEVEL 3
|
||||
|
||||
#define ADLMIDI_TOSTR(s) #s
|
||||
#define ADLMIDI_TOSTR_I(s) #s
|
||||
#define ADLMIDI_TOSTR(s) ADLMIDI_TOSTR_I(s)
|
||||
#define ADLMIDI_VERSION \
|
||||
ADLMIDI_TOSTR(OPNMIDI_VERSION_MAJOR) "." \
|
||||
ADLMIDI_TOSTR(OPNMIDI_VERSION_MINOR) "." \
|
||||
ADLMIDI_TOSTR(OPNMIDI_VERSION_PATCHLEVEL)
|
||||
ADLMIDI_TOSTR(ADLMIDI_VERSION_MAJOR) "." \
|
||||
ADLMIDI_TOSTR(ADLMIDI_VERSION_MINOR) "." \
|
||||
ADLMIDI_TOSTR(ADLMIDI_VERSION_PATCHLEVEL)
|
||||
|
||||
|
||||
#include <stddef.h>
|
||||
|
@ -57,11 +58,34 @@ typedef short ADL_SInt16;
|
|||
enum ADLMIDI_VolumeModels
|
||||
{
|
||||
ADLMIDI_VolumeModel_AUTO = 0,
|
||||
ADLMIDI_VolumeModel_Generic,
|
||||
ADLMIDI_VolumeModel_CMF,
|
||||
ADLMIDI_VolumeModel_DMX,
|
||||
ADLMIDI_VolumeModel_APOGEE,
|
||||
ADLMIDI_VolumeModel_9X
|
||||
ADLMIDI_VolumeModel_Generic = 1,
|
||||
ADLMIDI_VolumeModel_NativeOPL3 = 2,
|
||||
ADLMIDI_VolumeModel_CMF = ADLMIDI_VolumeModel_NativeOPL3,
|
||||
ADLMIDI_VolumeModel_DMX = 3,
|
||||
ADLMIDI_VolumeModel_APOGEE = 4,
|
||||
ADLMIDI_VolumeModel_9X = 5
|
||||
};
|
||||
|
||||
enum ADLMIDI_SampleType
|
||||
{
|
||||
ADLMIDI_SampleType_S16 = 0, /* signed PCM 16-bit */
|
||||
ADLMIDI_SampleType_S8, /* signed PCM 8-bit */
|
||||
ADLMIDI_SampleType_F32, /* float 32-bit */
|
||||
ADLMIDI_SampleType_F64, /* float 64-bit */
|
||||
ADLMIDI_SampleType_S24, /* signed PCM 24-bit */
|
||||
ADLMIDI_SampleType_S32, /* signed PCM 32-bit */
|
||||
ADLMIDI_SampleType_U8, /* unsigned PCM 8-bit */
|
||||
ADLMIDI_SampleType_U16, /* unsigned PCM 16-bit */
|
||||
ADLMIDI_SampleType_U24, /* unsigned PCM 24-bit */
|
||||
ADLMIDI_SampleType_U32, /* unsigned PCM 32-bit */
|
||||
ADLMIDI_SampleType_Count,
|
||||
};
|
||||
|
||||
struct ADLMIDI_AudioFormat
|
||||
{
|
||||
enum ADLMIDI_SampleType type; /* type of sample */
|
||||
unsigned containerSize; /* size in bytes of the storage type */
|
||||
unsigned sampleOffset; /* distance in bytes between consecutive samples */
|
||||
};
|
||||
|
||||
struct ADL_MIDIPlayer
|
||||
|
@ -87,6 +111,46 @@ extern int adl_getBanksCount();
|
|||
/* Returns pointer to array of names of every bank */
|
||||
extern const char *const *adl_getBankNames();
|
||||
|
||||
/* Reference to dynamic bank */
|
||||
typedef struct ADL_Bank
|
||||
{
|
||||
void *pointer[3];
|
||||
} ADL_Bank;
|
||||
|
||||
/* Identifier of dynamic bank */
|
||||
typedef struct ADL_BankId
|
||||
{
|
||||
ADL_UInt8 percussive, msb, lsb;
|
||||
} ADL_BankId;
|
||||
|
||||
/* Flags for dynamic bank access */
|
||||
enum ADL_BankAccessFlags
|
||||
{
|
||||
ADLMIDI_Bank_Create = 1, /* create bank, allocating memory as needed */
|
||||
ADLMIDI_Bank_CreateRt = 1|2, /* create bank, never allocating memory */
|
||||
};
|
||||
|
||||
typedef struct ADL_Instrument ADL_Instrument;
|
||||
|
||||
#if defined(ADLMIDI_UNSTABLE_API)
|
||||
/* Preallocates a minimum number of bank slots. Returns the actual capacity. */
|
||||
extern int adl_reserveBanks(struct ADL_MIDIPlayer *device, unsigned banks);
|
||||
/* Gets the bank designated by the identifier, optionally creating if it does not exist. */
|
||||
extern int adl_getBank(struct ADL_MIDIPlayer *device, const ADL_BankId *id, int flags, ADL_Bank *bank);
|
||||
/* Gets the identifier of a bank. */
|
||||
extern int adl_getBankId(struct ADL_MIDIPlayer *device, const ADL_Bank *bank, ADL_BankId *id);
|
||||
/* Removes a bank. */
|
||||
extern int adl_removeBank(struct ADL_MIDIPlayer *device, ADL_Bank *bank);
|
||||
/* Gets the first bank. */
|
||||
extern int adl_getFirstBank(struct ADL_MIDIPlayer *device, ADL_Bank *bank);
|
||||
/* Iterates to the next bank. */
|
||||
extern int adl_getNextBank(struct ADL_MIDIPlayer *device, ADL_Bank *bank);
|
||||
/* Gets the nth intrument in the bank [0..127]. */
|
||||
extern int adl_getInstrument(struct ADL_MIDIPlayer *device, const ADL_Bank *bank, unsigned index, ADL_Instrument *ins);
|
||||
/* Sets the nth intrument in the bank [0..127]. */
|
||||
extern int adl_setInstrument(struct ADL_MIDIPlayer *device, ADL_Bank *bank, unsigned index, const ADL_Instrument *ins);
|
||||
#endif /* defined(ADLMIDI_UNSTABLE_API) */
|
||||
|
||||
/*Sets number of 4-operator channels between all chips.
|
||||
By default, it is automatically re-calculating every bank change.
|
||||
If you want to specify custom number of four operator channels,
|
||||
|
@ -109,10 +173,16 @@ extern void adl_setHTremolo(struct ADL_MIDIPlayer *device, int htremo);
|
|||
/*Override Enable(1) or Disable(0) scaling of modulator volumes. -1 - use bank default scaling of modulator volumes*/
|
||||
extern void adl_setScaleModulators(struct ADL_MIDIPlayer *device, int smod);
|
||||
|
||||
/*Enable(1) or Disable(0) full-range brightness (MIDI CC74 used in XG music to filter result sounding) scaling.
|
||||
By default, brightness affects sound between 0 and 64.
|
||||
When this option is enabled, the range will use a full range from 0 up to 127.
|
||||
*/
|
||||
extern void adl_setFullRangeBrightness(struct ADL_MIDIPlayer *device, int fr_brightness);
|
||||
|
||||
/*Enable or disable built-in loop (built-in loop supports 'loopStart' and 'loopEnd' tags to loop specific part)*/
|
||||
extern void adl_setLoopEnabled(struct ADL_MIDIPlayer *device, int loopEn);
|
||||
|
||||
/*Enable or disable Logariphmic volume changer */
|
||||
/* !!!DEPRECATED!!! Enable or disable Logariphmic volume changer */
|
||||
extern void adl_setLogarithmicVolumes(struct ADL_MIDIPlayer *device, int logvol);
|
||||
|
||||
/*Set different volume range model */
|
||||
|
@ -125,15 +195,33 @@ extern int adl_openBankFile(struct ADL_MIDIPlayer *device, const char *filePath)
|
|||
extern int adl_openBankData(struct ADL_MIDIPlayer *device, const void *mem, unsigned long size);
|
||||
|
||||
|
||||
/*Returns name of currently used OPL3 emulator*/
|
||||
/* DEPRECATED */
|
||||
extern const char *adl_emulatorName();
|
||||
|
||||
/*Returns chip emulator name string*/
|
||||
extern const char *adl_chipEmulatorName(struct ADL_MIDIPlayer *device);
|
||||
|
||||
enum ADL_Emulator
|
||||
{
|
||||
ADLMIDI_EMU_NUKED = 0,
|
||||
ADLMIDI_EMU_NUKED_174,
|
||||
ADLMIDI_EMU_DOSBOX,
|
||||
ADLMIDI_EMU_end
|
||||
};
|
||||
|
||||
/* Switch the emulation core */
|
||||
extern int adl_switchEmulator(struct ADL_MIDIPlayer *device, int emulator);
|
||||
|
||||
|
||||
typedef struct {
|
||||
ADL_UInt16 major;
|
||||
ADL_UInt16 minor;
|
||||
ADL_UInt16 patch;
|
||||
} ADL_Version;
|
||||
|
||||
/*Run emulator with PCM rate to reduce CPU usage on slow devices. May decrease sounding accuracy.*/
|
||||
extern int adl_setRunAtPcmRate(struct ADL_MIDIPlayer *device, int enabled);
|
||||
|
||||
/*Returns string which contains a version number*/
|
||||
extern const char *adl_linkedLibraryVersion();
|
||||
|
||||
|
@ -213,11 +301,17 @@ extern struct Adl_MarkerEntry adl_metaMarker(struct ADL_MIDIPlayer *device, size
|
|||
|
||||
|
||||
/*Take a sample buffer and iterate MIDI timers */
|
||||
extern int adl_play(struct ADL_MIDIPlayer *device, int sampleCount, short out[]);
|
||||
extern int adl_play(struct ADL_MIDIPlayer *device, int sampleCount, short *out);
|
||||
|
||||
/*Take a sample buffer and iterate MIDI timers */
|
||||
extern int adl_playFormat(struct ADL_MIDIPlayer *device, int sampleCount, ADL_UInt8 *left, ADL_UInt8 *right, const struct ADLMIDI_AudioFormat *format);
|
||||
|
||||
/*Generate audio output from chip emulators without iteration of MIDI timers.*/
|
||||
extern int adl_generate(struct ADL_MIDIPlayer *device, int sampleCount, short *out);
|
||||
|
||||
/*Generate audio output from chip emulators without iteration of MIDI timers.*/
|
||||
extern int adl_generateFormat(struct ADL_MIDIPlayer *device, int sampleCount, ADL_UInt8 *left, ADL_UInt8 *right, const struct ADLMIDI_AudioFormat *format);
|
||||
|
||||
/**
|
||||
* @brief Periodic tick handler.
|
||||
* @param device
|
||||
|
@ -286,6 +380,70 @@ extern void adl_setNoteHook(struct ADL_MIDIPlayer *device, ADL_NoteHook noteHook
|
|||
/* Set debug message hook */
|
||||
extern void adl_setDebugMessageHook(struct ADL_MIDIPlayer *device, ADL_DebugMessageHook debugMessageHook, void *userData);
|
||||
|
||||
|
||||
/**Instrument structures**/
|
||||
|
||||
enum
|
||||
{
|
||||
ADLMIDI_InstrumentVersion = 0,
|
||||
};
|
||||
|
||||
typedef enum ADL_InstrumentFlags
|
||||
{
|
||||
/* Is two-operator single-voice instrument (no flags) */
|
||||
ADLMIDI_Ins_2op = 0x00,
|
||||
/* Is true four-operator instrument */
|
||||
ADLMIDI_Ins_4op = 0x01,
|
||||
/* Is pseudo four-operator (two 2-operator voices) instrument */
|
||||
ADLMIDI_Ins_Pseudo4op = 0x02,
|
||||
/* Is a blank instrument entry */
|
||||
ADLMIDI_Ins_IsBlank = 0x04,
|
||||
/* Mask of the flags range */
|
||||
ADLMIDI_Ins_ALL_MASK = 0x07,
|
||||
} ADL_InstrumentFlags;
|
||||
|
||||
typedef struct ADL_Operator
|
||||
{
|
||||
/* AM/Vib/Env/Ksr/FMult characteristics */
|
||||
ADL_UInt8 avekf_20;
|
||||
/* Key Scale Level / Total level register data */
|
||||
ADL_UInt8 ksl_l_40;
|
||||
/* Attack / Decay */
|
||||
ADL_UInt8 atdec_60;
|
||||
/* Systain and Release register data */
|
||||
ADL_UInt8 susrel_80;
|
||||
/* Wave form */
|
||||
ADL_UInt8 waveform_E0;
|
||||
} ADL_Operator;
|
||||
|
||||
typedef struct ADL_Instrument
|
||||
{
|
||||
/* Version of the instrument object */
|
||||
int version;
|
||||
/* MIDI note key (half-tone) offset for an instrument (or a first voice in pseudo-4-op mode) */
|
||||
ADL_SInt16 note_offset1;
|
||||
/* MIDI note key (half-tone) offset for a second voice in pseudo-4-op mode */
|
||||
ADL_SInt16 note_offset2;
|
||||
/* MIDI note velocity offset (taken from Apogee TMB format) */
|
||||
ADL_SInt8 midi_velocity_offset;
|
||||
/* Second voice detune level (taken from DMX OP2) */
|
||||
ADL_SInt8 second_voice_detune;
|
||||
/* Percussion MIDI base tone number at which this drum will be played */
|
||||
ADL_UInt8 percussion_key_number;
|
||||
/* Enum ADL_InstrumentFlags */
|
||||
ADL_UInt8 inst_flags;
|
||||
/* Feedback&Connection register for first and second operators */
|
||||
ADL_UInt8 fb_conn1_C0;
|
||||
/* Feedback&Connection register for third and fourth operators */
|
||||
ADL_UInt8 fb_conn2_C0;
|
||||
/* Operators register data */
|
||||
ADL_Operator operators[4];
|
||||
/* Millisecond delay of sounding while key is on */
|
||||
ADL_UInt16 delay_on_ms;
|
||||
/* Millisecond delay of sounding after key off */
|
||||
ADL_UInt16 delay_off_ms;
|
||||
} ADL_Instrument;
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
||||
|
|
|
@ -24,24 +24,15 @@
|
|||
#ifndef ADLMIDI_HPP
|
||||
#define ADLMIDI_HPP
|
||||
|
||||
#include "adlmidi.h"
|
||||
|
||||
#include <stdint.h>
|
||||
#include <vector>
|
||||
|
||||
class OPL3;
|
||||
class MIDIplay;
|
||||
struct ADL_MIDIPlayer;
|
||||
|
||||
class AdlInstrumentTester
|
||||
{
|
||||
uint32_t cur_gm;
|
||||
uint32_t ins_idx;
|
||||
std::vector<uint32_t> adl_ins_list;
|
||||
OPL3 *opl;
|
||||
MIDIplay * play;
|
||||
struct Impl;
|
||||
Impl *P;
|
||||
|
||||
public:
|
||||
AdlInstrumentTester(ADL_MIDIPlayer *device);
|
||||
explicit AdlInstrumentTester(ADL_MIDIPlayer *device);
|
||||
virtual ~AdlInstrumentTester();
|
||||
|
||||
// Find list of adlib instruments that supposedly implement this GM
|
||||
|
@ -51,6 +42,10 @@ public:
|
|||
void NextGM(int offset);
|
||||
void NextAdl(int offset);
|
||||
bool HandleInputChar(char ch);
|
||||
|
||||
private:
|
||||
AdlInstrumentTester(const AdlInstrumentTester &);
|
||||
AdlInstrumentTester &operator=(const AdlInstrumentTester &);
|
||||
};
|
||||
|
||||
#endif //ADLMIDI_HPP
|
||||
|
|
127
src/sound/adlmidi/adlmidi_bankmap.h
Normal file
127
src/sound/adlmidi/adlmidi_bankmap.h
Normal file
|
@ -0,0 +1,127 @@
|
|||
/*
|
||||
* libADLMIDI is a free MIDI to WAV conversion library with OPL3 emulation
|
||||
*
|
||||
* Original ADLMIDI code: Copyright (c) 2010-2014 Joel Yliluoma <bisqwit@iki.fi>
|
||||
* ADLMIDI Library API: Copyright (c) 2015-2018 Vitaly Novichkov <admin@wohlnet.ru>
|
||||
*
|
||||
* Library is based on the ADLMIDI, a MIDI player for Linux and Windows with OPL3 emulation:
|
||||
* http://iki.fi/bisqwit/source/adlmidi.html
|
||||
*
|
||||
* This program is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation, either version 3 of the License, or
|
||||
* any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
#ifndef ADLMIDI_BANKMAP_H
|
||||
#define ADLMIDI_BANKMAP_H
|
||||
|
||||
#include <list>
|
||||
#include <utility>
|
||||
#include <stdint.h>
|
||||
#include <stddef.h>
|
||||
|
||||
#include "adlmidi_ptr.hpp"
|
||||
|
||||
/**
|
||||
* A simple hash map which accepts bank numbers as keys, can be reserved to a
|
||||
* fixed size, offers O(1) search and insertion, has a hash function to
|
||||
* optimize for the worst case, and has some good cache locality properties.
|
||||
*/
|
||||
template <class T>
|
||||
class BasicBankMap
|
||||
{
|
||||
public:
|
||||
typedef uint16_t key_type; /* the bank identifier */
|
||||
typedef T mapped_type;
|
||||
typedef std::pair<key_type, T> value_type;
|
||||
|
||||
BasicBankMap();
|
||||
void reserve(size_t capacity);
|
||||
|
||||
size_t size() const
|
||||
{ return m_size; }
|
||||
size_t capacity() const
|
||||
{ return m_capacity; }
|
||||
bool empty() const
|
||||
{ return m_size == 0; }
|
||||
|
||||
class iterator;
|
||||
iterator begin() const;
|
||||
iterator end() const;
|
||||
|
||||
struct do_not_expand_t {};
|
||||
|
||||
iterator find(key_type key);
|
||||
void erase(iterator it);
|
||||
std::pair<iterator, bool> insert(const value_type &value);
|
||||
std::pair<iterator, bool> insert(const value_type &value, do_not_expand_t);
|
||||
void clear();
|
||||
|
||||
T &operator[](key_type key);
|
||||
|
||||
private:
|
||||
struct Slot;
|
||||
enum { minimum_allocation = 4 };
|
||||
enum
|
||||
{
|
||||
hash_bits = 8, /* worst case # of collisions: 128^2/2^hash_bits */
|
||||
hash_buckets = 1 << hash_bits,
|
||||
};
|
||||
|
||||
public:
|
||||
class iterator
|
||||
{
|
||||
public:
|
||||
iterator();
|
||||
value_type &operator*() const { return slot->value; }
|
||||
value_type *operator->() const { return &slot->value; }
|
||||
iterator &operator++();
|
||||
bool operator==(const iterator &o) const;
|
||||
bool operator!=(const iterator &o) const;
|
||||
void to_ptrs(void *ptrs[3]);
|
||||
static iterator from_ptrs(void *const ptrs[3]);
|
||||
private:
|
||||
Slot **buckets;
|
||||
Slot *slot;
|
||||
size_t index;
|
||||
iterator(Slot **buckets, Slot *slot, size_t index);
|
||||
#ifdef _MSC_VER
|
||||
template<class _T>
|
||||
friend class BasicBankMap;
|
||||
#else
|
||||
friend class BasicBankMap<T>;
|
||||
#endif
|
||||
};
|
||||
|
||||
private:
|
||||
struct Slot {
|
||||
Slot *next, *prev;
|
||||
value_type value;
|
||||
Slot() : next(NULL), prev(NULL) {}
|
||||
};
|
||||
AdlMIDI_SPtrArray<Slot *> m_buckets;
|
||||
std::list< AdlMIDI_SPtrArray<Slot> > m_allocations;
|
||||
Slot *m_freeslots;
|
||||
size_t m_size;
|
||||
size_t m_capacity;
|
||||
static size_t hash(key_type key);
|
||||
Slot *allocate_slot();
|
||||
Slot *ensure_allocate_slot();
|
||||
void free_slot(Slot *slot);
|
||||
Slot *bucket_find(size_t index, key_type key);
|
||||
void bucket_add(size_t index, Slot *slot);
|
||||
void bucket_remove(size_t index, Slot *slot);
|
||||
};
|
||||
|
||||
#include "adlmidi_bankmap.tcc"
|
||||
|
||||
#endif // ADLMIDI_BANKMAP_H
|
283
src/sound/adlmidi/adlmidi_bankmap.tcc
Normal file
283
src/sound/adlmidi/adlmidi_bankmap.tcc
Normal file
|
@ -0,0 +1,283 @@
|
|||
/*
|
||||
* libADLMIDI is a free MIDI to WAV conversion library with OPL3 emulation
|
||||
*
|
||||
* Original ADLMIDI code: Copyright (c) 2010-2014 Joel Yliluoma <bisqwit@iki.fi>
|
||||
* ADLMIDI Library API: Copyright (c) 2015-2018 Vitaly Novichkov <admin@wohlnet.ru>
|
||||
*
|
||||
* Library is based on the ADLMIDI, a MIDI player for Linux and Windows with OPL3 emulation:
|
||||
* http://iki.fi/bisqwit/source/adlmidi.html
|
||||
*
|
||||
* This program is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation, either version 3 of the License, or
|
||||
* any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
#include "adlmidi_bankmap.h"
|
||||
#include <cassert>
|
||||
|
||||
template <class T>
|
||||
inline BasicBankMap<T>::BasicBankMap()
|
||||
: m_freeslots(NULL),
|
||||
m_size(0),
|
||||
m_capacity(0)
|
||||
{
|
||||
m_buckets.reset(new Slot *[hash_buckets]());
|
||||
}
|
||||
|
||||
template <class T>
|
||||
inline size_t BasicBankMap<T>::hash(key_type key)
|
||||
{
|
||||
// disregard the 0 high bit in LSB
|
||||
key = (key & 127) | ((key >> 8) << 7);
|
||||
// take low part as hash value
|
||||
return key & (hash_buckets - 1);
|
||||
}
|
||||
|
||||
template <class T>
|
||||
void BasicBankMap<T>::reserve(size_t capacity)
|
||||
{
|
||||
if(m_capacity >= capacity)
|
||||
return;
|
||||
|
||||
size_t need = capacity - m_capacity;
|
||||
const size_t minalloc = static_cast<size_t>(minimum_allocation);
|
||||
need = (need < minalloc) ? minalloc : need;
|
||||
|
||||
AdlMIDI_SPtrArray<Slot> slotz;
|
||||
slotz.reset(new Slot[need]);
|
||||
m_allocations.push_back(slotz);
|
||||
m_capacity += need;
|
||||
|
||||
for(size_t i = need; i-- > 0;)
|
||||
free_slot(&slotz[i]);
|
||||
}
|
||||
|
||||
template <class T>
|
||||
typename BasicBankMap<T>::iterator
|
||||
BasicBankMap<T>::begin() const
|
||||
{
|
||||
iterator it(m_buckets.get(), NULL, 0);
|
||||
while(it.index < hash_buckets && !(it.slot = m_buckets[it.index]))
|
||||
++it.index;
|
||||
return it;
|
||||
}
|
||||
|
||||
template <class T>
|
||||
typename BasicBankMap<T>::iterator
|
||||
BasicBankMap<T>::end() const
|
||||
{
|
||||
iterator it(m_buckets.get(), NULL, hash_buckets);
|
||||
return it;
|
||||
}
|
||||
|
||||
template <class T>
|
||||
typename BasicBankMap<T>::iterator BasicBankMap<T>::find(key_type key)
|
||||
{
|
||||
size_t index = hash(key);
|
||||
Slot *slot = bucket_find(index, key);
|
||||
if(!slot)
|
||||
return end();
|
||||
return iterator(m_buckets.get(), slot, index);
|
||||
}
|
||||
|
||||
template <class T>
|
||||
void BasicBankMap<T>::erase(iterator it)
|
||||
{
|
||||
bucket_remove(it.index, it.slot);
|
||||
free_slot(it.slot);
|
||||
--m_size;
|
||||
}
|
||||
|
||||
template <class T>
|
||||
inline BasicBankMap<T>::iterator::iterator()
|
||||
: buckets(NULL), slot(NULL), index(0)
|
||||
{
|
||||
}
|
||||
|
||||
template <class T>
|
||||
inline BasicBankMap<T>::iterator::iterator(Slot **buckets, Slot *slot, size_t index)
|
||||
: buckets(buckets), slot(slot), index(index)
|
||||
{
|
||||
}
|
||||
|
||||
template <class T>
|
||||
typename BasicBankMap<T>::iterator &
|
||||
BasicBankMap<T>::iterator::operator++()
|
||||
{
|
||||
if(slot->next)
|
||||
slot = slot->next;
|
||||
else {
|
||||
Slot *slot = NULL;
|
||||
++index;
|
||||
while(index < hash_buckets && !(slot = buckets[index]))
|
||||
++index;
|
||||
this->slot = slot;
|
||||
}
|
||||
return *this;
|
||||
}
|
||||
|
||||
template <class T>
|
||||
bool BasicBankMap<T>::iterator::operator==(const iterator &o) const
|
||||
{
|
||||
return buckets == o.buckets && slot == o.slot && index == o.index;
|
||||
}
|
||||
|
||||
template <class T>
|
||||
inline bool BasicBankMap<T>::iterator::operator!=(const iterator &o) const
|
||||
{
|
||||
return !operator==(o);
|
||||
}
|
||||
|
||||
template <class T>
|
||||
void BasicBankMap<T>::iterator::to_ptrs(void *ptrs[3])
|
||||
{
|
||||
ptrs[0] = buckets;
|
||||
ptrs[1] = slot;
|
||||
ptrs[2] = (void *)index;
|
||||
}
|
||||
|
||||
template <class T>
|
||||
typename BasicBankMap<T>::iterator
|
||||
BasicBankMap<T>::iterator::from_ptrs(void *const ptrs[3])
|
||||
{
|
||||
iterator it;
|
||||
it.buckets = (Slot **)ptrs[0];
|
||||
it.slot = (Slot *)ptrs[1];
|
||||
it.index = (size_t)ptrs[2];
|
||||
return it;
|
||||
}
|
||||
|
||||
template <class T>
|
||||
std::pair<typename BasicBankMap<T>::iterator, bool>
|
||||
BasicBankMap<T>::insert(const value_type &value)
|
||||
{
|
||||
size_t index = hash(value.first);
|
||||
Slot *slot = bucket_find(index, value.first);
|
||||
if(slot)
|
||||
return std::make_pair(iterator(m_buckets.get(), slot, index), false);
|
||||
slot = allocate_slot();
|
||||
if(!slot) {
|
||||
reserve(m_capacity + minimum_allocation);
|
||||
slot = ensure_allocate_slot();
|
||||
}
|
||||
slot->value = value;
|
||||
bucket_add(index, slot);
|
||||
++m_size;
|
||||
return std::make_pair(iterator(m_buckets.get(), slot, index), true);
|
||||
}
|
||||
|
||||
template <class T>
|
||||
std::pair<typename BasicBankMap<T>::iterator, bool>
|
||||
BasicBankMap<T>::insert(const value_type &value, do_not_expand_t)
|
||||
{
|
||||
size_t index = hash(value.first);
|
||||
Slot *slot = bucket_find(index, value.first);
|
||||
if(slot)
|
||||
return std::make_pair(iterator(m_buckets.get(), slot, index), false);
|
||||
slot = allocate_slot();
|
||||
if(!slot)
|
||||
return std::make_pair(end(), false);
|
||||
slot->value = value;
|
||||
bucket_add(index, slot);
|
||||
++m_size;
|
||||
return std::make_pair(iterator(m_buckets.get(), slot, index), true);
|
||||
}
|
||||
|
||||
template <class T>
|
||||
void BasicBankMap<T>::clear()
|
||||
{
|
||||
for(size_t i = 0; i < hash_buckets; ++i) {
|
||||
Slot *slot = m_buckets[i];
|
||||
while (Slot *cur = slot) {
|
||||
slot = slot->next;
|
||||
free_slot(cur);
|
||||
}
|
||||
m_buckets[i] = NULL;
|
||||
}
|
||||
m_size = 0;
|
||||
}
|
||||
|
||||
template <class T>
|
||||
inline T &BasicBankMap<T>::operator[](key_type key)
|
||||
{
|
||||
return insert(value_type(key, T())).first->second;
|
||||
}
|
||||
|
||||
template <class T>
|
||||
typename BasicBankMap<T>::Slot *
|
||||
BasicBankMap<T>::allocate_slot()
|
||||
{
|
||||
Slot *slot = m_freeslots;
|
||||
if(!slot)
|
||||
return NULL;
|
||||
Slot *next = slot->next;
|
||||
if(next)
|
||||
next->prev = NULL;
|
||||
m_freeslots = next;
|
||||
return slot;
|
||||
}
|
||||
|
||||
template <class T>
|
||||
inline typename BasicBankMap<T>::Slot *
|
||||
BasicBankMap<T>::ensure_allocate_slot()
|
||||
{
|
||||
Slot *slot = allocate_slot();
|
||||
assert(slot);
|
||||
return slot;
|
||||
}
|
||||
|
||||
template <class T>
|
||||
void BasicBankMap<T>::free_slot(Slot *slot)
|
||||
{
|
||||
Slot *next = m_freeslots;
|
||||
if(next)
|
||||
next->prev = slot;
|
||||
slot->prev = NULL;
|
||||
slot->next = next;
|
||||
m_freeslots = slot;
|
||||
m_freeslots->value.second = T();
|
||||
}
|
||||
|
||||
template <class T>
|
||||
typename BasicBankMap<T>::Slot *
|
||||
BasicBankMap<T>::bucket_find(size_t index, key_type key)
|
||||
{
|
||||
Slot *slot = m_buckets[index];
|
||||
while(slot && slot->value.first != key)
|
||||
slot = slot->next;
|
||||
return slot;
|
||||
}
|
||||
|
||||
template <class T>
|
||||
void BasicBankMap<T>::bucket_add(size_t index, Slot *slot)
|
||||
{
|
||||
assert(slot);
|
||||
Slot *next = m_buckets[index];
|
||||
if(next)
|
||||
next->prev = slot;
|
||||
slot->next = next;
|
||||
m_buckets[index] = slot;
|
||||
}
|
||||
|
||||
template <class T>
|
||||
void BasicBankMap<T>::bucket_remove(size_t index, Slot *slot)
|
||||
{
|
||||
assert(slot);
|
||||
Slot *prev = slot->prev;
|
||||
Slot *next = slot->next;
|
||||
if(!prev)
|
||||
m_buckets[index] = next;
|
||||
else
|
||||
prev->next = next;
|
||||
if(next)
|
||||
next->prev = prev;
|
||||
}
|
|
@ -22,6 +22,7 @@
|
|||
*/
|
||||
|
||||
#include "adlmidi_private.hpp"
|
||||
#include "wopl/wopl_file.h"
|
||||
|
||||
#ifndef ADLMIDI_DISABLE_MIDI_SEQUENCER
|
||||
# ifndef ADLMIDI_DISABLE_MUS_SUPPORT
|
||||
|
@ -32,6 +33,7 @@
|
|||
# endif//XMI
|
||||
#endif //ADLMIDI_DISABLE_MIDI_SEQUENCER
|
||||
|
||||
#ifndef ADLMIDI_DISABLE_MIDI_SEQUENCER
|
||||
uint64_t MIDIplay::ReadBEint(const void *buffer, size_t nbytes)
|
||||
{
|
||||
uint64_t result = 0;
|
||||
|
@ -54,6 +56,8 @@ uint64_t MIDIplay::ReadLEint(const void *buffer, size_t nbytes)
|
|||
return result;
|
||||
}
|
||||
|
||||
#endif
|
||||
|
||||
bool MIDIplay::LoadBank(const std::string &filename)
|
||||
{
|
||||
fileReader file;
|
||||
|
@ -68,282 +72,223 @@ bool MIDIplay::LoadBank(const void *data, size_t size)
|
|||
return LoadBank(file);
|
||||
}
|
||||
|
||||
|
||||
|
||||
/* WOPL-needed misc functions */
|
||||
static uint16_t toUint16LE(const uint8_t *arr)
|
||||
template <class WOPLI>
|
||||
static void cvt_generic_to_FMIns(adlinsdata2 &ins, const WOPLI &in)
|
||||
{
|
||||
uint16_t num = arr[0];
|
||||
num |= ((arr[1] << 8) & 0xFF00);
|
||||
return num;
|
||||
}
|
||||
|
||||
static uint16_t toUint16BE(const uint8_t *arr)
|
||||
{
|
||||
uint16_t num = arr[1];
|
||||
num |= ((arr[0] << 8) & 0xFF00);
|
||||
return num;
|
||||
}
|
||||
|
||||
static int16_t toSint16BE(const uint8_t *arr)
|
||||
{
|
||||
int16_t num = *reinterpret_cast<const int8_t *>(&arr[0]);
|
||||
num *= 1 << 8;
|
||||
num |= arr[1];
|
||||
return num;
|
||||
}
|
||||
|
||||
static const char *wopl3_magic = "WOPL3-BANK\0";
|
||||
static const uint16_t wopl_latest_version = 3;
|
||||
|
||||
#define WOPL_INST_SIZE_V2 62
|
||||
#define WOPL_INST_SIZE_V3 66
|
||||
|
||||
enum WOPL_InstrumentFlags
|
||||
{
|
||||
WOPL_Flags_NONE = 0,
|
||||
WOPL_Flag_Enable4OP = 0x01,
|
||||
WOPL_Flag_Pseudo4OP = 0x02,
|
||||
WOPL_Flag_NoSound = 0x04,
|
||||
};
|
||||
|
||||
struct WOPL_Inst
|
||||
{
|
||||
bool fourOps;
|
||||
char padding[7];
|
||||
struct adlinsdata adlins;
|
||||
struct adldata op[2];
|
||||
uint16_t ms_sound_kon;
|
||||
uint16_t ms_sound_koff;
|
||||
};
|
||||
|
||||
static bool readInstrument(MIDIplay::fileReader &file, WOPL_Inst &ins, uint16_t &version, bool isPercussion = false)
|
||||
{
|
||||
uint8_t idata[WOPL_INST_SIZE_V3];
|
||||
if(version >= 3)
|
||||
{
|
||||
if(file.read(idata, 1, WOPL_INST_SIZE_V3) != WOPL_INST_SIZE_V3)
|
||||
return false;
|
||||
}
|
||||
else
|
||||
{
|
||||
if(file.read(idata, 1, WOPL_INST_SIZE_V2) != WOPL_INST_SIZE_V2)
|
||||
return false;
|
||||
}
|
||||
|
||||
//strncpy(ins.name, char_p(idata), 32);
|
||||
ins.op[0].finetune = (int8_t)toSint16BE(idata + 32);
|
||||
ins.op[1].finetune = (int8_t)toSint16BE(idata + 34);
|
||||
//ins.velocity_offset = int8_t(idata[36]);
|
||||
|
||||
ins.adlins.voice2_fine_tune = 0.0;
|
||||
int8_t voice2_fine_tune = int8_t(idata[37]);
|
||||
ins.voice2_fine_tune = 0.0;
|
||||
int8_t voice2_fine_tune = in.second_voice_detune;
|
||||
if(voice2_fine_tune != 0)
|
||||
{
|
||||
if(voice2_fine_tune == 1)
|
||||
ins.adlins.voice2_fine_tune = 0.000025;
|
||||
ins.voice2_fine_tune = 0.000025;
|
||||
else if(voice2_fine_tune == -1)
|
||||
ins.adlins.voice2_fine_tune = -0.000025;
|
||||
ins.voice2_fine_tune = -0.000025;
|
||||
else
|
||||
ins.adlins.voice2_fine_tune = ((voice2_fine_tune * 15.625) / 1000.0);
|
||||
ins.voice2_fine_tune = voice2_fine_tune * (15.625 / 1000.0);
|
||||
}
|
||||
|
||||
ins.adlins.tone = isPercussion ? idata[38] : 0;
|
||||
ins.tone = in.percussion_key_number;
|
||||
ins.flags = (in.inst_flags & WOPL_Ins_4op) && (in.inst_flags & WOPL_Ins_Pseudo4op) ? adlinsdata::Flag_Pseudo4op : 0;
|
||||
ins.flags|= (in.inst_flags & WOPL_Ins_4op) && ((in.inst_flags & WOPL_Ins_Pseudo4op) == 0) ? adlinsdata::Flag_Real4op : 0;
|
||||
ins.flags|= (in.inst_flags & WOPL_Ins_IsBlank) ? adlinsdata::Flag_NoSound : 0;
|
||||
|
||||
uint8_t flags = idata[39];
|
||||
ins.adlins.flags = (flags & WOPL_Flag_Enable4OP) && (flags & WOPL_Flag_Pseudo4OP) ? adlinsdata::Flag_Pseudo4op : 0;
|
||||
ins.adlins.flags|= (flags & WOPL_Flag_NoSound) ? adlinsdata::Flag_NoSound : 0;
|
||||
ins.fourOps = (flags & WOPL_Flag_Enable4OP) || (flags & WOPL_Flag_Pseudo4OP);
|
||||
|
||||
ins.op[0].feedconn = (idata[40]);
|
||||
ins.op[1].feedconn = (idata[41]);
|
||||
|
||||
for(size_t op = 0, slt = 0; op < 4; op++, slt++)
|
||||
bool fourOps = (in.inst_flags & WOPL_Ins_4op) || (in.inst_flags & WOPL_Ins_Pseudo4op);
|
||||
for(size_t op = 0, slt = 0; op < static_cast<size_t>(fourOps ? 4 : 2); op++, slt++)
|
||||
{
|
||||
size_t off = 42 + size_t(op) * 5;
|
||||
// ins.setAVEKM(op, idata[off + 0]);//AVEKM
|
||||
// ins.setAtDec(op, idata[off + 2]);//AtDec
|
||||
// ins.setSusRel(op, idata[off + 3]);//SusRel
|
||||
// ins.setWaveForm(op, idata[off + 4]);//WaveForm
|
||||
// ins.setKSLL(op, idata[off + 1]);//KSLL
|
||||
ins.op[slt].carrier_E862 =
|
||||
((static_cast<uint32_t>(idata[off + 4]) << 24) & 0xFF000000) //WaveForm
|
||||
| ((static_cast<uint32_t>(idata[off + 3]) << 16) & 0x00FF0000) //SusRel
|
||||
| ((static_cast<uint32_t>(idata[off + 2]) << 8) & 0x0000FF00) //AtDec
|
||||
| ((static_cast<uint32_t>(idata[off + 0]) << 0) & 0x000000FF); //AVEKM
|
||||
ins.op[slt].carrier_40 = idata[off + 1];//KSLL
|
||||
ins.adl[slt].carrier_E862 =
|
||||
((static_cast<uint32_t>(in.operators[op].waveform_E0) << 24) & 0xFF000000) //WaveForm
|
||||
| ((static_cast<uint32_t>(in.operators[op].susrel_80) << 16) & 0x00FF0000) //SusRel
|
||||
| ((static_cast<uint32_t>(in.operators[op].atdec_60) << 8) & 0x0000FF00) //AtDec
|
||||
| ((static_cast<uint32_t>(in.operators[op].avekf_20) << 0) & 0x000000FF); //AVEKM
|
||||
ins.adl[slt].carrier_40 = in.operators[op].ksl_l_40;//KSLL
|
||||
|
||||
op++;
|
||||
off = 42 + size_t(op) * 5;
|
||||
ins.op[slt].modulator_E862 =
|
||||
((static_cast<uint32_t>(idata[off + 4]) << 24) & 0xFF000000) //WaveForm
|
||||
| ((static_cast<uint32_t>(idata[off + 3]) << 16) & 0x00FF0000) //SusRel
|
||||
| ((static_cast<uint32_t>(idata[off + 2]) << 8) & 0x0000FF00) //AtDec
|
||||
| ((static_cast<uint32_t>(idata[off + 0]) << 0) & 0x000000FF); //AVEKM
|
||||
ins.op[slt].modulator_40 = idata[off + 1];//KSLL
|
||||
ins.adl[slt].modulator_E862 =
|
||||
((static_cast<uint32_t>(in.operators[op].waveform_E0) << 24) & 0xFF000000) //WaveForm
|
||||
| ((static_cast<uint32_t>(in.operators[op].susrel_80) << 16) & 0x00FF0000) //SusRel
|
||||
| ((static_cast<uint32_t>(in.operators[op].atdec_60) << 8) & 0x0000FF00) //AtDec
|
||||
| ((static_cast<uint32_t>(in.operators[op].avekf_20) << 0) & 0x000000FF); //AVEKM
|
||||
ins.adl[slt].modulator_40 = in.operators[op].ksl_l_40;//KSLL
|
||||
}
|
||||
|
||||
if(version >= 3)
|
||||
ins.adl[0].finetune = static_cast<int8_t>(in.note_offset1);
|
||||
ins.adl[0].feedconn = in.fb_conn1_C0;
|
||||
if(!fourOps)
|
||||
ins.adl[1] = ins.adl[0];
|
||||
else
|
||||
{
|
||||
ins.ms_sound_kon = toUint16BE(idata + 62);
|
||||
ins.ms_sound_koff = toUint16BE(idata + 64);
|
||||
ins.adl[1].finetune = static_cast<int8_t>(in.note_offset2);
|
||||
ins.adl[1].feedconn = in.fb_conn2_C0;
|
||||
}
|
||||
|
||||
ins.ms_sound_kon = in.delay_on_ms;
|
||||
ins.ms_sound_koff = in.delay_off_ms;
|
||||
}
|
||||
|
||||
template <class WOPLI>
|
||||
static void cvt_FMIns_to_generic(WOPLI &ins, const adlinsdata2 &in)
|
||||
{
|
||||
ins.second_voice_detune = 0;
|
||||
double voice2_fine_tune = in.voice2_fine_tune;
|
||||
if(voice2_fine_tune != 0)
|
||||
{
|
||||
if(voice2_fine_tune > 0 && voice2_fine_tune <= 0.000025)
|
||||
ins.second_voice_detune = 1;
|
||||
else if(voice2_fine_tune < 0 && voice2_fine_tune >= -0.000025)
|
||||
ins.second_voice_detune = -1;
|
||||
else
|
||||
{
|
||||
long value = lround(voice2_fine_tune * (1000.0 / 15.625));
|
||||
value = (value < -128) ? -128 : value;
|
||||
value = (value > +127) ? +127 : value;
|
||||
ins.second_voice_detune = static_cast<int8_t>(value);
|
||||
}
|
||||
}
|
||||
|
||||
ins.percussion_key_number = in.tone;
|
||||
bool fourOps = (in.flags & adlinsdata::Flag_Pseudo4op) || in.adl[0] != in.adl[1];
|
||||
ins.inst_flags = fourOps ? WOPL_Ins_4op : 0;
|
||||
ins.inst_flags|= (in.flags & adlinsdata::Flag_Pseudo4op) ? WOPL_Ins_Pseudo4op : 0;
|
||||
ins.inst_flags|= (in.flags & adlinsdata::Flag_NoSound) ? WOPL_Ins_IsBlank : 0;
|
||||
|
||||
for(size_t op = 0, slt = 0; op < static_cast<size_t>(fourOps ? 4 : 2); op++, slt++)
|
||||
{
|
||||
ins.operators[op].waveform_E0 = static_cast<uint8_t>(in.adl[slt].carrier_E862 >> 24);
|
||||
ins.operators[op].susrel_80 = static_cast<uint8_t>(in.adl[slt].carrier_E862 >> 16);
|
||||
ins.operators[op].atdec_60 = static_cast<uint8_t>(in.adl[slt].carrier_E862 >> 8);
|
||||
ins.operators[op].avekf_20 = static_cast<uint8_t>(in.adl[slt].carrier_E862 >> 0);
|
||||
ins.operators[op].ksl_l_40 = in.adl[slt].carrier_40;
|
||||
|
||||
op++;
|
||||
ins.operators[op].waveform_E0 = static_cast<uint8_t>(in.adl[slt].carrier_E862 >> 24);
|
||||
ins.operators[op].susrel_80 = static_cast<uint8_t>(in.adl[slt].carrier_E862 >> 16);
|
||||
ins.operators[op].atdec_60 = static_cast<uint8_t>(in.adl[slt].carrier_E862 >> 8);
|
||||
ins.operators[op].avekf_20 = static_cast<uint8_t>(in.adl[slt].carrier_E862 >> 0);
|
||||
ins.operators[op].ksl_l_40 = in.adl[slt].carrier_40;
|
||||
}
|
||||
|
||||
ins.note_offset1 = in.adl[0].finetune;
|
||||
ins.fb_conn1_C0 = in.adl[0].feedconn;
|
||||
if(!fourOps)
|
||||
{
|
||||
ins.operators[2] = ins.operators[0];
|
||||
ins.operators[3] = ins.operators[1];
|
||||
}
|
||||
else
|
||||
{
|
||||
ins.ms_sound_kon = 1000;
|
||||
ins.ms_sound_koff = 500;
|
||||
ins.note_offset2 = in.adl[1].finetune;
|
||||
ins.fb_conn2_C0 = in.adl[1].feedconn;
|
||||
}
|
||||
|
||||
return true;
|
||||
ins.delay_on_ms = in.ms_sound_kon;
|
||||
ins.delay_off_ms = in.ms_sound_koff;
|
||||
}
|
||||
|
||||
void cvt_ADLI_to_FMIns(adlinsdata2 &ins, const ADL_Instrument &in)
|
||||
{
|
||||
return cvt_generic_to_FMIns(ins, in);
|
||||
}
|
||||
|
||||
void cvt_FMIns_to_ADLI(ADL_Instrument &ins, const adlinsdata2 &in)
|
||||
{
|
||||
cvt_FMIns_to_generic(ins, in);
|
||||
}
|
||||
|
||||
bool MIDIplay::LoadBank(MIDIplay::fileReader &fr)
|
||||
{
|
||||
int err = 0;
|
||||
WOPLFile *wopl = NULL;
|
||||
char *raw_file_data = NULL;
|
||||
size_t fsize;
|
||||
ADL_UNUSED(fsize);
|
||||
if(!fr.isValid())
|
||||
{
|
||||
errorStringOut = "Custom bank: Invalid data stream!";
|
||||
return false;
|
||||
}
|
||||
|
||||
char magic[32];
|
||||
std::memset(magic, 0, 32);
|
||||
|
||||
uint16_t version = 0;
|
||||
|
||||
uint16_t count_melodic_banks = 1;
|
||||
uint16_t count_percusive_banks = 1;
|
||||
|
||||
if(fr.read(magic, 1, 11) != 11)
|
||||
// Read complete bank file into the memory
|
||||
fr.seek(0, SEEK_END);
|
||||
fsize = fr.tell();
|
||||
fr.seek(0, SEEK_SET);
|
||||
// Allocate necessary memory block
|
||||
raw_file_data = (char*)malloc(fsize);
|
||||
if(!raw_file_data)
|
||||
{
|
||||
errorStringOut = "Custom bank: Can't read magic number!";
|
||||
errorStringOut = "Custom bank: Out of memory before of read!";
|
||||
return false;
|
||||
}
|
||||
fr.read(raw_file_data, 1, fsize);
|
||||
|
||||
if(std::strncmp(magic, wopl3_magic, 11) != 0)
|
||||
// Parse bank file from the memory
|
||||
wopl = WOPL_LoadBankFromMem((void*)raw_file_data, fsize, &err);
|
||||
//Free the buffer no more needed
|
||||
free(raw_file_data);
|
||||
|
||||
// Check for any erros
|
||||
if(!wopl)
|
||||
{
|
||||
errorStringOut = "Custom bank: Invalid magic number!";
|
||||
return false;
|
||||
switch(err)
|
||||
{
|
||||
case WOPL_ERR_BAD_MAGIC:
|
||||
errorStringOut = "Custom bank: Invalid magic!";
|
||||
return false;
|
||||
case WOPL_ERR_UNEXPECTED_ENDING:
|
||||
errorStringOut = "Custom bank: Unexpected ending!";
|
||||
return false;
|
||||
case WOPL_ERR_INVALID_BANKS_COUNT:
|
||||
errorStringOut = "Custom bank: Invalid banks count!";
|
||||
return false;
|
||||
case WOPL_ERR_NEWER_VERSION:
|
||||
errorStringOut = "Custom bank: Version is newer than supported by this library!";
|
||||
return false;
|
||||
case WOPL_ERR_OUT_OF_MEMORY:
|
||||
errorStringOut = "Custom bank: Out of memory!";
|
||||
return false;
|
||||
default:
|
||||
errorStringOut = "Custom bank: Unknown error!";
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
uint8_t version_raw[2];
|
||||
if(fr.read(version_raw, 1, 2) != 2)
|
||||
{
|
||||
errorStringOut = "Custom bank: Can't read version!";
|
||||
return false;
|
||||
}
|
||||
|
||||
version = toUint16LE(version_raw);
|
||||
if(version > wopl_latest_version)
|
||||
{
|
||||
errorStringOut = "Custom bank: Unsupported WOPL version!";
|
||||
return false;
|
||||
}
|
||||
|
||||
uint8_t head[6];
|
||||
std::memset(head, 0, 6);
|
||||
if(fr.read(head, 1, 6) != 6)
|
||||
{
|
||||
errorStringOut = "Custom bank: Can't read header!";
|
||||
return false;
|
||||
}
|
||||
|
||||
count_melodic_banks = toUint16BE(head);
|
||||
count_percusive_banks = toUint16BE(head + 2);
|
||||
|
||||
if((count_melodic_banks < 1) || (count_percusive_banks < 1))
|
||||
{
|
||||
errorStringOut = "Custom bank: Too few banks in this file!";
|
||||
return false;
|
||||
}
|
||||
|
||||
/*UNUSED YET*/
|
||||
bool default_deep_vibrato = ((head[4]>>0) & 0x01);
|
||||
bool default_deep_tremolo = ((head[4]>>1) & 0x01);
|
||||
|
||||
//5'th byte reserved for Deep-Tremolo and Deep-Vibrato flags
|
||||
m_setup.HighTremoloMode = default_deep_tremolo;
|
||||
m_setup.HighVibratoMode = default_deep_vibrato;
|
||||
//6'th byte reserved for ADLMIDI's default volume model
|
||||
m_setup.VolumeModel = (int)head[5];
|
||||
|
||||
opl.dynamic_melodic_banks.clear();
|
||||
opl.dynamic_percussion_banks.clear();
|
||||
opl.dynamic_bank_setup.adLibPercussions = false;
|
||||
opl.dynamic_bank_setup.scaleModulators = false;
|
||||
opl.dynamic_bank_setup.deepTremolo = (wopl->opl_flags & WOPL_FLAG_DEEP_TREMOLO) != 0;
|
||||
opl.dynamic_bank_setup.deepVibrato = (wopl->opl_flags & WOPL_FLAG_DEEP_VIBRATO) != 0;
|
||||
opl.dynamic_bank_setup.volumeModel = wopl->volume_model;
|
||||
m_setup.HighTremoloMode = -1;
|
||||
m_setup.HighVibratoMode = -1;
|
||||
m_setup.VolumeModel = ADLMIDI_VolumeModel_AUTO;
|
||||
|
||||
opl.setEmbeddedBank(m_setup.AdlBank);
|
||||
|
||||
if(version >= 2)//Read bank meta-entries
|
||||
uint16_t slots_counts[2] = {wopl->banks_count_melodic, wopl->banks_count_percussion};
|
||||
WOPLBank *slots_src_ins[2] = { wopl->banks_melodic, wopl->banks_percussive };
|
||||
|
||||
for(unsigned ss = 0; ss < 2; ss++)
|
||||
{
|
||||
for(uint16_t i = 0; i < count_melodic_banks; i++)
|
||||
for(unsigned i = 0; i < slots_counts[ss]; i++)
|
||||
{
|
||||
uint8_t bank_meta[34];
|
||||
if(fr.read(bank_meta, 1, 34) != 34)
|
||||
unsigned bankno =
|
||||
(slots_src_ins[ss][i].bank_midi_msb * 256) +
|
||||
slots_src_ins[ss][i].bank_midi_lsb +
|
||||
(ss ? OPL3::PercussionTag : 0);
|
||||
OPL3::Bank &bank = opl.dynamic_banks[bankno];
|
||||
for(int j = 0; j < 128; j++)
|
||||
{
|
||||
errorStringOut = "Custom bank: Fail to read melodic bank meta-data!";
|
||||
return false;
|
||||
adlinsdata2 &ins = bank.ins[j];
|
||||
std::memset(&ins, 0, sizeof(adlinsdata2));
|
||||
WOPLInstrument &inIns = slots_src_ins[ss][i].ins[j];
|
||||
cvt_generic_to_FMIns(ins, inIns);
|
||||
}
|
||||
uint16_t bank = uint16_t(bank_meta[33]) * 256 + uint16_t(bank_meta[32]);
|
||||
size_t offset = opl.dynamic_melodic_banks.size();
|
||||
opl.dynamic_melodic_banks[bank] = offset;
|
||||
//strncpy(bankMeta.name, char_p(bank_meta), 32);
|
||||
}
|
||||
|
||||
for(uint16_t i = 0; i < count_percusive_banks; i++)
|
||||
{
|
||||
uint8_t bank_meta[34];
|
||||
if(fr.read(bank_meta, 1, 34) != 34)
|
||||
{
|
||||
errorStringOut = "Custom bank: Fail to read percussion bank meta-data!";
|
||||
return false;
|
||||
}
|
||||
uint16_t bank = uint16_t(bank_meta[33]) * 256 + uint16_t(bank_meta[32]);
|
||||
size_t offset = opl.dynamic_percussion_banks.size();
|
||||
opl.dynamic_percussion_banks[bank] = offset;
|
||||
//strncpy(bankMeta.name, char_p(bank_meta), 32);
|
||||
}
|
||||
}
|
||||
|
||||
uint16_t total = 128 * count_melodic_banks;
|
||||
bool readPercussion = false;
|
||||
|
||||
tryAgain:
|
||||
for(uint16_t i = 0; i < total; i++)
|
||||
{
|
||||
WOPL_Inst ins;
|
||||
std::memset(&ins, 0, sizeof(WOPL_Inst));
|
||||
if(!readInstrument(fr, ins, version, readPercussion))
|
||||
{
|
||||
opl.setEmbeddedBank(m_setup.AdlBank);
|
||||
errorStringOut = "Custom bank: Fail to read instrument!";
|
||||
return false;
|
||||
}
|
||||
ins.adlins.ms_sound_kon = ins.ms_sound_kon;
|
||||
ins.adlins.ms_sound_koff = ins.ms_sound_koff;
|
||||
ins.adlins.adlno1 = static_cast<uint16_t>(opl.dynamic_instruments.size() | opl.DynamicInstrumentTag);
|
||||
opl.dynamic_instruments.push_back(ins.op[0]);
|
||||
ins.adlins.adlno2 = ins.adlins.adlno1;
|
||||
if(ins.fourOps)
|
||||
{
|
||||
ins.adlins.adlno2 = static_cast<uint16_t>(opl.dynamic_instruments.size() | opl.DynamicInstrumentTag);
|
||||
opl.dynamic_instruments.push_back(ins.op[1]);
|
||||
}
|
||||
opl.dynamic_metainstruments.push_back(ins.adlins);
|
||||
}
|
||||
|
||||
if(!readPercussion)
|
||||
{
|
||||
total = 128 * count_percusive_banks;
|
||||
readPercussion = true;
|
||||
goto tryAgain;
|
||||
}
|
||||
|
||||
opl.AdlBank = ~0u; // Use dynamic banks!
|
||||
//Percussion offset is count of instruments multipled to count of melodic banks
|
||||
opl.dynamic_percussion_offset = 128 * count_melodic_banks;
|
||||
|
||||
applySetup();
|
||||
|
||||
WOPL_Free(wopl);
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
|
@ -373,7 +318,7 @@ bool MIDIplay::LoadMIDI(MIDIplay::fileReader &fr)
|
|||
errorString.clear();
|
||||
|
||||
#ifdef DISABLE_EMBEDDED_BANKS
|
||||
if((opl.AdlBank != ~0u) || (opl.dynamic_metainstruments.size() < 256))
|
||||
if((opl.AdlBank != ~0u) || opl.dynamic_banks.empty())
|
||||
{
|
||||
errorStringOut = "Bank is not set! Please load any instruments bank by using of adl_openBankFile() or adl_openBankData() functions!";
|
||||
return false;
|
||||
|
@ -497,8 +442,7 @@ riffskip:
|
|||
#endif //ADLMIDI_DISABLE_XMI_SUPPORT
|
||||
else if(std::memcmp(HeaderBuf, "CTMF", 4) == 0)
|
||||
{
|
||||
opl.dynamic_instruments.clear();
|
||||
opl.dynamic_metainstruments.clear();
|
||||
opl.dynamic_banks.clear();
|
||||
// Creative Music Format (CMF).
|
||||
// When playing CTMF files, use the following commandline:
|
||||
// adlmidi song8.ctmf -p -v 1 1 0
|
||||
|
@ -520,13 +464,19 @@ riffskip:
|
|||
//std::printf("%u instruments\n", ins_count);
|
||||
for(unsigned i = 0; i < ins_count; ++i)
|
||||
{
|
||||
unsigned bank = i / 256;
|
||||
bank = (bank & 127) + ((bank >> 7) << 8);
|
||||
if(bank > 127 + (127 << 8))
|
||||
break;
|
||||
bank += (i % 256 < 128) ? 0 : OPL3::PercussionTag;
|
||||
|
||||
unsigned char InsData[16];
|
||||
fr.read(InsData, 1, 16);
|
||||
/*std::printf("Ins %3u: %02X %02X %02X %02X %02X %02X %02X %02X %02X %02X %02X %02X %02X %02X %02X %02X\n",
|
||||
i, InsData[0],InsData[1],InsData[2],InsData[3], InsData[4],InsData[5],InsData[6],InsData[7],
|
||||
InsData[8],InsData[9],InsData[10],InsData[11], InsData[12],InsData[13],InsData[14],InsData[15]);*/
|
||||
struct adldata adl;
|
||||
struct adlinsdata adlins;
|
||||
adlinsdata2 &adlins = opl.dynamic_banks[bank].ins[i % 128];
|
||||
adldata adl;
|
||||
adl.modulator_E862 =
|
||||
((static_cast<uint32_t>(InsData[8] & 0x07) << 24) & 0xFF000000) //WaveForm
|
||||
| ((static_cast<uint32_t>(InsData[6]) << 16) & 0x00FF0000) //Sustain/Release
|
||||
|
@ -541,15 +491,13 @@ riffskip:
|
|||
adl.carrier_40 = InsData[3];
|
||||
adl.feedconn = InsData[10] & 0x0F;
|
||||
adl.finetune = 0;
|
||||
adlins.adlno1 = static_cast<uint16_t>(opl.dynamic_instruments.size() | opl.DynamicInstrumentTag);
|
||||
adlins.adlno2 = adlins.adlno1;
|
||||
adlins.adl[0] = adl;
|
||||
adlins.adl[1] = adl;
|
||||
adlins.ms_sound_kon = 1000;
|
||||
adlins.ms_sound_koff = 500;
|
||||
adlins.tone = 0;
|
||||
adlins.flags = 0;
|
||||
adlins.voice2_fine_tune = 0.0;
|
||||
opl.dynamic_metainstruments.push_back(adlins);
|
||||
opl.dynamic_instruments.push_back(adl);
|
||||
}
|
||||
|
||||
fr.seeku(mus_start, SEEK_SET);
|
||||
|
@ -557,10 +505,9 @@ riffskip:
|
|||
DeltaTicks = (size_t)ticks;
|
||||
opl.AdlBank = ~0u; // Ignore AdlBank number, use dynamic banks instead
|
||||
//std::printf("CMF deltas %u ticks %u, basictempo = %u\n", deltas, ticks, basictempo);
|
||||
opl.LogarithmicVolumes = true;
|
||||
opl.AdlPercussionMode = true;
|
||||
opl.m_musicMode = OPL3::MODE_CMF;
|
||||
opl.m_volumeScale = OPL3::VOLUME_CMF;
|
||||
opl.m_volumeScale = OPL3::VOLUME_NATIVE;
|
||||
}
|
||||
else
|
||||
{
|
||||
|
@ -575,10 +522,9 @@ riffskip:
|
|||
fr.seek(0x7D, SEEK_SET);
|
||||
TrackCount = 1;
|
||||
DeltaTicks = 60;
|
||||
opl.LogarithmicVolumes = true;
|
||||
//opl.CartoonersVolumes = true;
|
||||
opl.m_musicMode = OPL3::MODE_RSXX;
|
||||
opl.m_volumeScale = OPL3::VOLUME_CMF;
|
||||
opl.m_volumeScale = OPL3::VOLUME_NATIVE;
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -636,11 +582,11 @@ riffskip:
|
|||
|
||||
TrackData.clear();
|
||||
TrackData.resize(TrackCount, std::vector<uint8_t>());
|
||||
//CurrentPosition.track.clear();
|
||||
//CurrentPosition.track.resize(TrackCount);
|
||||
InvDeltaTicks = fraction<uint64_t>(1, 1000000l * static_cast<uint64_t>(DeltaTicks));
|
||||
//Tempo = 1000000l * InvDeltaTicks;
|
||||
Tempo = fraction<uint64_t>(1, static_cast<uint64_t>(DeltaTicks));
|
||||
if(is_CMF || is_RSXX)
|
||||
Tempo = fraction<uint64_t>(1, static_cast<uint64_t>(DeltaTicks));
|
||||
else
|
||||
Tempo = fraction<uint64_t>(1, static_cast<uint64_t>(DeltaTicks) * 2);
|
||||
static const unsigned char EndTag[4] = {0xFF, 0x2F, 0x00, 0x00};
|
||||
size_t totalGotten = 0;
|
||||
|
||||
|
@ -761,14 +707,14 @@ riffskip:
|
|||
return false;
|
||||
}
|
||||
|
||||
//Build new MIDI events table (ALPHA!!!)
|
||||
//Build new MIDI events table
|
||||
if(!buildTrackData())
|
||||
{
|
||||
errorStringOut = fr._fileName + ": MIDI data parsing error has occouped!\n" + errorString;
|
||||
return false;
|
||||
}
|
||||
|
||||
opl.Reset(m_setup.PCM_RATE); // Reset AdLib
|
||||
opl.Reset(m_setup.emulator, m_setup.PCM_RATE, this); // Reset OPL3 chip
|
||||
//opl.Reset(); // ...twice (just in case someone misprogrammed OPL3 previously)
|
||||
ch.clear();
|
||||
ch.resize(opl.NumChannels);
|
||||
|
|
File diff suppressed because it is too large
Load diff
|
@ -25,6 +25,21 @@
|
|||
|
||||
#ifdef ADLMIDI_HW_OPL
|
||||
static const unsigned OPLBase = 0x388;
|
||||
#else
|
||||
# if defined(ADLMIDI_DISABLE_NUKED_EMULATOR) && defined(ADLMIDI_DISABLE_DOSBOX_EMULATOR)
|
||||
# error "No emulators enabled. You must enable at least one emulator to use this library!"
|
||||
# endif
|
||||
|
||||
// Nuked OPL3 emulator, Most accurate, but requires the powerful CPU
|
||||
# ifndef ADLMIDI_DISABLE_NUKED_EMULATOR
|
||||
# include "chips/nuked_opl3.h"
|
||||
# include "chips/nuked_opl3_v174.h"
|
||||
# endif
|
||||
|
||||
// DosBox 0.74 OPL3 emulator, Well-accurate and fast
|
||||
# ifndef ADLMIDI_DISABLE_DOSBOX_EMULATOR
|
||||
# include "chips/dosbox_opl3.h"
|
||||
# endif
|
||||
#endif
|
||||
|
||||
#ifdef DISABLE_EMBEDDED_BANKS
|
||||
|
@ -114,87 +129,56 @@ static const unsigned short Channels[23] =
|
|||
Ports: ???
|
||||
*/
|
||||
|
||||
|
||||
const adlinsdata &OPL3::GetAdlMetaIns(size_t n)
|
||||
{
|
||||
return (n & DynamicMetaInstrumentTag) ?
|
||||
dynamic_metainstruments[n & ~DynamicMetaInstrumentTag]
|
||||
: adlins[n];
|
||||
}
|
||||
|
||||
size_t OPL3::GetAdlMetaNumber(size_t midiins)
|
||||
{
|
||||
return (AdlBank == ~0u) ?
|
||||
(midiins | DynamicMetaInstrumentTag)
|
||||
: banks[AdlBank][midiins];
|
||||
}
|
||||
|
||||
const adldata &OPL3::GetAdlIns(size_t insno)
|
||||
{
|
||||
return (insno & DynamicInstrumentTag)
|
||||
? dynamic_instruments[insno & ~DynamicInstrumentTag]
|
||||
: adl[insno];
|
||||
}
|
||||
|
||||
void OPL3::setEmbeddedBank(unsigned int bank)
|
||||
{
|
||||
AdlBank = bank;
|
||||
//Embedded banks are supports 128:128 GM set only
|
||||
dynamic_percussion_offset = 128;
|
||||
dynamic_melodic_banks.clear();
|
||||
dynamic_percussion_banks.clear();
|
||||
dynamic_banks.clear();
|
||||
|
||||
if(bank >= static_cast<unsigned int>(maxAdlBanks()))
|
||||
return;
|
||||
|
||||
Bank *bank_pair[2] =
|
||||
{
|
||||
&dynamic_banks[0],
|
||||
&dynamic_banks[PercussionTag]
|
||||
};
|
||||
|
||||
for(unsigned i = 0; i < 256; ++i)
|
||||
{
|
||||
size_t meta = banks[bank][i];
|
||||
adlinsdata2 &ins = bank_pair[i / 128]->ins[i % 128];
|
||||
ins = adlinsdata2(adlins[meta]);
|
||||
}
|
||||
}
|
||||
|
||||
static adlinsdata2 makeEmptyInstrument()
|
||||
{
|
||||
adlinsdata2 ins;
|
||||
memset(&ins, 0, sizeof(adlinsdata2));
|
||||
ins.flags = adlinsdata::Flag_NoSound;
|
||||
return ins;
|
||||
}
|
||||
|
||||
const adlinsdata2 OPL3::emptyInstrument = makeEmptyInstrument();
|
||||
|
||||
OPL3::OPL3() :
|
||||
dynamic_percussion_offset(128),
|
||||
DynamicInstrumentTag(0x8000u),
|
||||
DynamicMetaInstrumentTag(0x4000000u),
|
||||
NumCards(1),
|
||||
AdlBank(0),
|
||||
NumFourOps(0),
|
||||
HighTremoloMode(false),
|
||||
HighVibratoMode(false),
|
||||
AdlPercussionMode(false),
|
||||
LogarithmicVolumes(false),
|
||||
//CartoonersVolumes(false),
|
||||
m_musicMode(MODE_MIDI),
|
||||
m_volumeScale(VOLUME_Generic)
|
||||
{}
|
||||
|
||||
void OPL3::Poke(size_t card, uint32_t index, uint32_t value)
|
||||
{
|
||||
#ifdef ADLMIDI_HW_OPL
|
||||
(void)card;
|
||||
unsigned o = index >> 8;
|
||||
unsigned port = OPLBase + o * 2;
|
||||
|
||||
#ifdef __DJGPP__
|
||||
outportb(port, index);
|
||||
for(unsigned c = 0; c < 6; ++c) inportb(port);
|
||||
outportb(port + 1, value);
|
||||
for(unsigned c = 0; c < 35; ++c) inportb(port);
|
||||
#endif//__DJGPP__
|
||||
|
||||
#ifdef __WATCOMC__
|
||||
outp(port, index);
|
||||
for(uint16_t c = 0; c < 6; ++c) inp(port);
|
||||
outp(port + 1, value);
|
||||
for(uint16_t c = 0; c < 35; ++c) inp(port);
|
||||
#endif//__WATCOMC__
|
||||
|
||||
#else//ADLMIDI_HW_OPL
|
||||
|
||||
#ifdef ADLMIDI_USE_DOSBOX_OPL
|
||||
cards[card].WriteReg(index, static_cast<uint8_t>(value));
|
||||
#else
|
||||
OPL3_WriteReg(&cards[card], static_cast<Bit16u>(index), static_cast<Bit8u>(value));
|
||||
#endif
|
||||
|
||||
#endif//ADLMIDI_HW_OPL
|
||||
#ifdef DISABLE_EMBEDDED_BANKS
|
||||
AdlBank = ~0u;
|
||||
#else
|
||||
setEmbeddedBank(0);
|
||||
#endif
|
||||
}
|
||||
|
||||
void OPL3::PokeN(size_t card, uint16_t index, uint8_t value)
|
||||
void OPL3::Poke(size_t card, uint16_t index, uint8_t value)
|
||||
{
|
||||
#ifdef ADLMIDI_HW_OPL
|
||||
(void)card;
|
||||
|
@ -216,11 +200,7 @@ void OPL3::PokeN(size_t card, uint16_t index, uint8_t value)
|
|||
#endif//__WATCOMC__
|
||||
|
||||
#else
|
||||
#ifdef ADLMIDI_USE_DOSBOX_OPL
|
||||
cards[card].WriteReg(static_cast<Bit32u>(index), value);
|
||||
#else
|
||||
OPL3_WriteReg(&cards[card], index, value);
|
||||
#endif
|
||||
cardsOP2[card]->writeReg(index, value);
|
||||
#endif
|
||||
}
|
||||
|
||||
|
@ -277,10 +257,9 @@ void OPL3::Touch_Real(unsigned c, unsigned volume, uint8_t brightness)
|
|||
volume = 63;
|
||||
|
||||
size_t card = c / 23, cc = c % 23;
|
||||
size_t i = ins[c];
|
||||
const adldata &adli = ins[c];
|
||||
uint16_t o1 = Operators[cc * 2 + 0];
|
||||
uint16_t o2 = Operators[cc * 2 + 1];
|
||||
const adldata &adli = GetAdlIns(i);
|
||||
uint8_t x = adli.modulator_40, y = adli.carrier_40;
|
||||
uint16_t mode = 1; // 2-op AM
|
||||
|
||||
|
@ -290,22 +269,22 @@ void OPL3::Touch_Real(unsigned c, unsigned volume, uint8_t brightness)
|
|||
}
|
||||
else if(four_op_category[c] == 1 || four_op_category[c] == 2)
|
||||
{
|
||||
size_t i0, i1;
|
||||
const adldata *i0, *i1;
|
||||
|
||||
if(four_op_category[c] == 1)
|
||||
{
|
||||
i0 = i;
|
||||
i1 = ins[c + 3];
|
||||
i0 = &adli;
|
||||
i1 = &ins[c + 3];
|
||||
mode = 2; // 4-op xx-xx ops 1&2
|
||||
}
|
||||
else
|
||||
{
|
||||
i0 = ins[c - 3];
|
||||
i1 = i;
|
||||
i0 = &ins[c - 3];
|
||||
i1 = &adli;
|
||||
mode = 6; // 4-op xx-xx ops 3&4
|
||||
}
|
||||
|
||||
mode += (GetAdlIns(i0).feedconn & 1) + (GetAdlIns(i1).feedconn & 1) * 2;
|
||||
mode += (i0->feedconn & 1) + (i1->feedconn & 1) * 2;
|
||||
}
|
||||
|
||||
static const bool do_ops[10][2] =
|
||||
|
@ -372,14 +351,13 @@ void OPL3::Touch(unsigned c, unsigned volume) // Volume maxes at 127*127*127
|
|||
}
|
||||
}*/
|
||||
|
||||
void OPL3::Patch(uint16_t c, size_t i)
|
||||
void OPL3::Patch(uint16_t c, const adldata &adli)
|
||||
{
|
||||
uint16_t card = c / 23, cc = c % 23;
|
||||
static const uint8_t data[4] = {0x20, 0x60, 0x80, 0xE0};
|
||||
ins[c] = i;
|
||||
ins[c] = adli;
|
||||
uint16_t o1 = Operators[cc * 2 + 0];
|
||||
uint16_t o2 = Operators[cc * 2 + 1];
|
||||
const adldata &adli = GetAdlIns(i);
|
||||
unsigned x = adli.modulator_E862, y = adli.carrier_E862;
|
||||
|
||||
for(unsigned a = 0; a < 4; ++a, x >>= 8, y >>= 8)
|
||||
|
@ -395,7 +373,7 @@ void OPL3::Pan(unsigned c, unsigned value)
|
|||
unsigned card = c / 23, cc = c % 23;
|
||||
|
||||
if(Channels[cc] != 0xFFF)
|
||||
Poke(card, 0xC0 + Channels[cc], GetAdlIns(ins[c]).feedconn | value);
|
||||
Poke(card, 0xC0 + Channels[cc], ins[c].feedconn | value);
|
||||
}
|
||||
|
||||
void OPL3::Silence() // Silence all OPL channels.
|
||||
|
@ -479,9 +457,8 @@ void OPL3::ChangeVolumeRangesModel(ADLMIDI_VolumeModels volumeModel)
|
|||
m_volumeScale = OPL3::VOLUME_Generic;
|
||||
break;
|
||||
|
||||
case ADLMIDI_VolumeModel_CMF:
|
||||
LogarithmicVolumes = true;
|
||||
m_volumeScale = OPL3::VOLUME_CMF;
|
||||
case ADLMIDI_VolumeModel_NativeOPL3:
|
||||
m_volumeScale = OPL3::VOLUME_NATIVE;
|
||||
break;
|
||||
|
||||
case ADLMIDI_VolumeModel_DMX:
|
||||
|
@ -498,26 +475,36 @@ void OPL3::ChangeVolumeRangesModel(ADLMIDI_VolumeModels volumeModel)
|
|||
}
|
||||
}
|
||||
|
||||
void OPL3::Reset(unsigned long PCM_RATE)
|
||||
#ifndef ADLMIDI_HW_OPL
|
||||
void OPL3::ClearChips()
|
||||
{
|
||||
#ifndef ADLMIDI_HW_OPL
|
||||
#ifdef ADLMIDI_USE_DOSBOX_OPL
|
||||
DBOPL::Handler emptyChip; //Constructors inside are will initialize necessary fields
|
||||
#else
|
||||
_opl3_chip emptyChip;
|
||||
std::memset(&emptyChip, 0, sizeof(_opl3_chip));
|
||||
#endif
|
||||
cards.clear();
|
||||
#endif
|
||||
for(size_t i = 0; i < cardsOP2.size(); i++)
|
||||
cardsOP2[i].reset(NULL);
|
||||
cardsOP2.clear();
|
||||
}
|
||||
#endif
|
||||
|
||||
void OPL3::Reset(int emulator, unsigned long PCM_RATE, void *audioTickHandler)
|
||||
{
|
||||
#ifndef ADLMIDI_HW_OPL
|
||||
ClearChips();
|
||||
#else
|
||||
(void)emulator;
|
||||
(void)PCM_RATE;
|
||||
#endif
|
||||
#if !defined(ADLMIDI_AUDIO_TICK_HANDLER)
|
||||
(void)audioTickHandler;
|
||||
#endif
|
||||
ins.clear();
|
||||
pit.clear();
|
||||
regBD.clear();
|
||||
#ifndef ADLMIDI_HW_OPL
|
||||
cards.resize(NumCards, emptyChip);
|
||||
#endif
|
||||
|
||||
#ifndef ADLMIDI_HW_OPL
|
||||
cardsOP2.resize(NumCards, AdlMIDI_SPtr<OPLChipBase>());
|
||||
#endif
|
||||
|
||||
NumChannels = NumCards * 23;
|
||||
ins.resize(NumChannels, 189);
|
||||
ins.resize(NumChannels, adl[adlDefaultNumber]);
|
||||
pit.resize(NumChannels, 0);
|
||||
regBD.resize(NumCards, 0);
|
||||
four_op_category.resize(NumChannels, 0);
|
||||
|
@ -536,24 +523,45 @@ void OPL3::Reset(unsigned long PCM_RATE)
|
|||
};
|
||||
unsigned fours = NumFourOps;
|
||||
|
||||
for(unsigned card = 0; card < NumCards; ++card)
|
||||
for(size_t i = 0; i < NumCards; ++i)
|
||||
{
|
||||
#ifndef ADLMIDI_HW_OPL
|
||||
# ifdef ADLMIDI_USE_DOSBOX_OPL
|
||||
cards[card].Init(PCM_RATE);
|
||||
# else
|
||||
OPL3_Reset(&cards[card], static_cast<Bit32u>(PCM_RATE));
|
||||
# endif
|
||||
#endif
|
||||
#ifndef ADLMIDI_HW_OPL
|
||||
OPLChipBase *chip;
|
||||
switch(emulator)
|
||||
{
|
||||
default:
|
||||
#ifndef ADLMIDI_DISABLE_NUKED_EMULATOR
|
||||
case ADLMIDI_EMU_NUKED: /* Latest Nuked OPL3 */
|
||||
chip = new NukedOPL3;
|
||||
break;
|
||||
case ADLMIDI_EMU_NUKED_174: /* Old Nuked OPL3 1.4.7 modified and optimized */
|
||||
chip = new NukedOPL3v174;
|
||||
break;
|
||||
#endif
|
||||
#ifndef ADLMIDI_DISABLE_DOSBOX_EMULATOR
|
||||
case ADLMIDI_EMU_DOSBOX:
|
||||
chip = new DosBoxOPL3;
|
||||
break;
|
||||
#endif
|
||||
}
|
||||
cardsOP2[i].reset(chip);
|
||||
chip->setChipId((uint32_t)i);
|
||||
chip->setRate((uint32_t)PCM_RATE);
|
||||
if(runAtPcmRate)
|
||||
chip->setRunningAtPcmRate(true);
|
||||
# if defined(ADLMIDI_AUDIO_TICK_HANDLER)
|
||||
chip->setAudioTickHandlerInstance(audioTickHandler);
|
||||
# endif
|
||||
#endif // ADLMIDI_HW_OPL
|
||||
|
||||
for(unsigned a = 0; a < 18; ++a) Poke(card, 0xB0 + Channels[a], 0x00);
|
||||
for(unsigned a = 0; a < 18; ++a) Poke(i, 0xB0 + Channels[a], 0x00);
|
||||
for(unsigned a = 0; a < sizeof(data) / sizeof(*data); a += 2)
|
||||
PokeN(card, data[a], static_cast<uint8_t>(data[a + 1]));
|
||||
Poke(card, 0x0BD, regBD[card] = (HighTremoloMode * 0x80
|
||||
+ HighVibratoMode * 0x40
|
||||
+ AdlPercussionMode * 0x20));
|
||||
Poke(i, data[a], static_cast<uint8_t>(data[a + 1]));
|
||||
Poke(i, 0x0BD, regBD[i] = (HighTremoloMode * 0x80
|
||||
+ HighVibratoMode * 0x40
|
||||
+ AdlPercussionMode * 0x20));
|
||||
unsigned fours_this_card = std::min(fours, 6u);
|
||||
Poke(card, 0x104, (1 << fours_this_card) - 1);
|
||||
Poke(i, 0x104, (1 << fours_this_card) - 1);
|
||||
//fprintf(stderr, "Card %u: %u four-ops.\n", card, fours_this_card);
|
||||
fours -= fours_this_card;
|
||||
}
|
||||
|
|
Some files were not shown because too many files have changed in this diff Show more
Loading…
Reference in a new issue