mirror of
https://github.com/ZDoom/gzdoom.git
synced 2024-11-13 16:07:45 +00:00
commit
a7025b5563
34 changed files with 293 additions and 590 deletions
|
@ -12,7 +12,7 @@ git:
|
||||||
matrix:
|
matrix:
|
||||||
include:
|
include:
|
||||||
- os: osx
|
- os: osx
|
||||||
osx_image: xcode8.2
|
osx_image: xcode8.3
|
||||||
env:
|
env:
|
||||||
- CMAKE_OPTIONS="-DCMAKE_BUILD_TYPE=Release -DCMAKE_OSX_DEPLOYMENT_TARGET=10.7"
|
- CMAKE_OPTIONS="-DCMAKE_BUILD_TYPE=Release -DCMAKE_OSX_DEPLOYMENT_TARGET=10.7"
|
||||||
|
|
||||||
|
|
BIN
soundfont/gzdoom.sf2
Normal file
BIN
soundfont/gzdoom.sf2
Normal file
Binary file not shown.
|
@ -517,7 +517,6 @@ set( PLAT_UNIX_SOURCES
|
||||||
posix/unix/i_specialpaths.cpp
|
posix/unix/i_specialpaths.cpp
|
||||||
posix/unix/iwadpicker_gtk.cpp )
|
posix/unix/iwadpicker_gtk.cpp )
|
||||||
set( PLAT_OSX_SOURCES
|
set( PLAT_OSX_SOURCES
|
||||||
sound/mididevices/music_audiotoolbox_mididevice.cpp
|
|
||||||
posix/osx/iwadpicker_cocoa.mm
|
posix/osx/iwadpicker_cocoa.mm
|
||||||
posix/osx/i_specialpaths.mm
|
posix/osx/i_specialpaths.mm
|
||||||
posix/osx/zdoom.icns )
|
posix/osx/zdoom.icns )
|
||||||
|
@ -1254,12 +1253,17 @@ if( MSVC )
|
||||||
create_default_target_launcher( zdoom WORKING_DIRECTORY ${ZDOOM_OUTPUT_DIR} )
|
create_default_target_launcher( zdoom WORKING_DIRECTORY ${ZDOOM_OUTPUT_DIR} )
|
||||||
endif()
|
endif()
|
||||||
|
|
||||||
if( NOT WIN32 )
|
if( NOT WIN32 AND NOT APPLE )
|
||||||
FILE( WRITE ${CMAKE_CURRENT_BINARY_DIR}/link-make "if [ ! -e ${ZDOOM_OUTPUT_DIR}/${ZDOOM_EXE_NAME} ]; then ln -sf ${CMAKE_CURRENT_BINARY_DIR}/${ZDOOM_EXE_NAME} ${ZDOOM_OUTPUT_DIR}/${ZDOOM_EXE_NAME}; fi" )
|
FILE( WRITE ${CMAKE_CURRENT_BINARY_DIR}/link-make "if [ ! -e ${ZDOOM_OUTPUT_DIR}/${ZDOOM_EXE_NAME} ]; then ln -sf ${CMAKE_CURRENT_BINARY_DIR}/${ZDOOM_EXE_NAME} ${ZDOOM_OUTPUT_DIR}/${ZDOOM_EXE_NAME}; fi" )
|
||||||
add_custom_command( TARGET zdoom POST_BUILD
|
add_custom_command( TARGET zdoom POST_BUILD
|
||||||
COMMAND chmod +x ${CMAKE_CURRENT_BINARY_DIR}/link-make
|
COMMAND chmod +x ${CMAKE_CURRENT_BINARY_DIR}/link-make
|
||||||
COMMAND /bin/sh -c ${CMAKE_CURRENT_BINARY_DIR}/link-make )
|
COMMAND /bin/sh -c ${CMAKE_CURRENT_BINARY_DIR}/link-make )
|
||||||
endif()
|
endif()
|
||||||
|
|
||||||
|
add_custom_command(TARGET zdoom POST_BUILD
|
||||||
|
COMMAND ${CMAKE_COMMAND} -E copy_if_different
|
||||||
|
${CMAKE_SOURCE_DIR}/soundfont/gzdoom.sf2 $<TARGET_FILE_DIR:zdoom>)
|
||||||
|
|
||||||
if( CMAKE_COMPILER_IS_GNUCXX )
|
if( CMAKE_COMPILER_IS_GNUCXX )
|
||||||
# GCC misoptimizes this file
|
# GCC misoptimizes this file
|
||||||
set_source_files_properties( oplsynth/fmopl.cpp PROPERTIES COMPILE_FLAGS "-fno-tree-dominator-opts -fno-tree-fre" )
|
set_source_files_properties( oplsynth/fmopl.cpp PROPERTIES COMPILE_FLAGS "-fno-tree-dominator-opts -fno-tree-fre" )
|
||||||
|
@ -1278,7 +1282,7 @@ endif()
|
||||||
|
|
||||||
if( APPLE )
|
if( APPLE )
|
||||||
set_target_properties(zdoom PROPERTIES
|
set_target_properties(zdoom PROPERTIES
|
||||||
LINK_FLAGS "-framework AudioToolbox -framework AudioUnit -framework Carbon -framework Cocoa -framework IOKit -framework OpenGL"
|
LINK_FLAGS "-framework Carbon -framework Cocoa -framework IOKit -framework OpenGL"
|
||||||
MACOSX_BUNDLE_INFO_PLIST "${CMAKE_CURRENT_SOURCE_DIR}/posix/osx/zdoom-info.plist" )
|
MACOSX_BUNDLE_INFO_PLIST "${CMAKE_CURRENT_SOURCE_DIR}/posix/osx/zdoom-info.plist" )
|
||||||
|
|
||||||
endif()
|
endif()
|
||||||
|
|
|
@ -149,7 +149,7 @@ void ParseGLDefs();
|
||||||
// PRIVATE FUNCTION PROTOTYPES ---------------------------------------------
|
// PRIVATE FUNCTION PROTOTYPES ---------------------------------------------
|
||||||
|
|
||||||
void D_DoomLoop ();
|
void D_DoomLoop ();
|
||||||
static const char *BaseFileSearch (const char *file, const char *ext, bool lookfirstinprogdir=false);
|
const char *BaseFileSearch (const char *file, const char *ext, bool lookfirstinprogdir=false);
|
||||||
|
|
||||||
// EXTERNAL DATA DECLARATIONS ----------------------------------------------
|
// EXTERNAL DATA DECLARATIONS ----------------------------------------------
|
||||||
|
|
||||||
|
@ -1693,7 +1693,7 @@ static void D_AddDirectory (TArray<FString> &wadfiles, const char *dir)
|
||||||
//
|
//
|
||||||
//==========================================================================
|
//==========================================================================
|
||||||
|
|
||||||
static const char *BaseFileSearch (const char *file, const char *ext, bool lookfirstinprogdir)
|
const char *BaseFileSearch (const char *file, const char *ext, bool lookfirstinprogdir)
|
||||||
{
|
{
|
||||||
static char wad[PATH_MAX];
|
static char wad[PATH_MAX];
|
||||||
|
|
||||||
|
|
|
@ -119,6 +119,7 @@ void GLPortal::ClearScreen()
|
||||||
gl_RenderState.mViewMatrix.loadIdentity();
|
gl_RenderState.mViewMatrix.loadIdentity();
|
||||||
gl_RenderState.mProjectionMatrix.ortho(0, SCREENWIDTH, SCREENHEIGHT, 0, -1.0f, 1.0f);
|
gl_RenderState.mProjectionMatrix.ortho(0, SCREENWIDTH, SCREENHEIGHT, 0, -1.0f, 1.0f);
|
||||||
gl_RenderState.ApplyMatrices();
|
gl_RenderState.ApplyMatrices();
|
||||||
|
glVertexAttrib4f(VATTR_COLOR, 0, 0, 0, 1); // color should be black.
|
||||||
|
|
||||||
glDisable(GL_MULTISAMPLE);
|
glDisable(GL_MULTISAMPLE);
|
||||||
glDisable(GL_DEPTH_TEST);
|
glDisable(GL_DEPTH_TEST);
|
||||||
|
|
|
@ -2763,7 +2763,11 @@ bool P_CheckMove(AActor *thing, const DVector2 &pos, int flags)
|
||||||
FCheckPosition tm;
|
FCheckPosition tm;
|
||||||
double newz = thing->Z();
|
double newz = thing->Z();
|
||||||
|
|
||||||
if (!P_CheckPosition(thing, pos, tm))
|
auto f1 = thing->flags & MF_PICKUP;
|
||||||
|
thing->flags &= ~MF_PICKUP;
|
||||||
|
auto res = P_CheckPosition(thing, pos, tm);
|
||||||
|
thing->flags |= f1;
|
||||||
|
if (!res)
|
||||||
{
|
{
|
||||||
// Ignore PCM_DROPOFF. Not necessary here: a little later it is.
|
// Ignore PCM_DROPOFF. Not necessary here: a little later it is.
|
||||||
if (!flags || (!(flags & PCM_NOACTORS) && !(flags & PCM_NOLINES)))
|
if (!flags || (!(flags & PCM_NOACTORS) && !(flags & PCM_NOLINES)))
|
||||||
|
|
|
@ -159,8 +159,6 @@ void PolyRenderer::ClearBuffers()
|
||||||
PolyStencilBuffer::Instance()->Clear(RenderTarget->GetWidth(), RenderTarget->GetHeight(), 0);
|
PolyStencilBuffer::Instance()->Clear(RenderTarget->GetWidth(), RenderTarget->GetHeight(), 0);
|
||||||
PolySubsectorGBuffer::Instance()->Resize(RenderTarget->GetPitch(), RenderTarget->GetHeight());
|
PolySubsectorGBuffer::Instance()->Resize(RenderTarget->GetPitch(), RenderTarget->GetHeight());
|
||||||
NextStencilValue = 0;
|
NextStencilValue = 0;
|
||||||
SeenLinePortals.clear();
|
|
||||||
SeenMirrors.clear();
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void PolyRenderer::SetSceneViewport()
|
void PolyRenderer::SetSceneViewport()
|
||||||
|
@ -216,13 +214,3 @@ void PolyRenderer::SetupPerspectiveMatrix()
|
||||||
|
|
||||||
WorldToClip = TriMatrix::perspective(fovy, ratio, 5.0f, 65535.0f) * worldToView;
|
WorldToClip = TriMatrix::perspective(fovy, ratio, 5.0f, 65535.0f) * worldToView;
|
||||||
}
|
}
|
||||||
|
|
||||||
bool PolyRenderer::InsertSeenLinePortal(FLinePortal *portal)
|
|
||||||
{
|
|
||||||
return SeenLinePortals.insert(portal).second;
|
|
||||||
}
|
|
||||||
|
|
||||||
bool PolyRenderer::InsertSeenMirror(line_t *mirrorLine)
|
|
||||||
{
|
|
||||||
return SeenMirrors.insert(mirrorLine).second;
|
|
||||||
}
|
|
||||||
|
|
|
@ -52,9 +52,6 @@ public:
|
||||||
|
|
||||||
uint32_t GetNextStencilValue() { uint32_t value = NextStencilValue; NextStencilValue += 2; return value; }
|
uint32_t GetNextStencilValue() { uint32_t value = NextStencilValue; NextStencilValue += 2; return value; }
|
||||||
|
|
||||||
bool InsertSeenLinePortal(FLinePortal *portal);
|
|
||||||
bool InsertSeenMirror(line_t *mirrorLine);
|
|
||||||
|
|
||||||
bool DontMapLines = false;
|
bool DontMapLines = false;
|
||||||
|
|
||||||
RenderMemory FrameMemory;
|
RenderMemory FrameMemory;
|
||||||
|
@ -75,7 +72,4 @@ private:
|
||||||
PolySkyDome Skydome;
|
PolySkyDome Skydome;
|
||||||
RenderPolyPlayerSprites PlayerSprites;
|
RenderPolyPlayerSprites PlayerSprites;
|
||||||
uint32_t NextStencilValue = 0;
|
uint32_t NextStencilValue = 0;
|
||||||
|
|
||||||
std::set<FLinePortal *> SeenLinePortals;
|
|
||||||
std::set<line_t *> SeenMirrors;
|
|
||||||
};
|
};
|
||||||
|
|
|
@ -70,6 +70,20 @@ void PolyCull::CullNode(void *node)
|
||||||
|
|
||||||
void PolyCull::CullSubsector(subsector_t *sub)
|
void PolyCull::CullSubsector(subsector_t *sub)
|
||||||
{
|
{
|
||||||
|
// Check if subsector is clipped entirely by the portal clip plane
|
||||||
|
bool visible = false;
|
||||||
|
for (uint32_t i = 0; i < sub->numlines; i++)
|
||||||
|
{
|
||||||
|
seg_t *line = &sub->firstline[i];
|
||||||
|
if (PortalClipPlane.A * line->v1->fX() + PortalClipPlane.B * line->v1->fY() + PortalClipPlane.D > 0.0)
|
||||||
|
{
|
||||||
|
visible = true;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if (!visible)
|
||||||
|
return;
|
||||||
|
|
||||||
// Update sky heights for the scene
|
// Update sky heights for the scene
|
||||||
if (!FirstSkyHeight)
|
if (!FirstSkyHeight)
|
||||||
{
|
{
|
||||||
|
@ -98,6 +112,13 @@ void PolyCull::CullSubsector(subsector_t *sub)
|
||||||
if (pt1.Y * (pt1.X - pt2.X) + pt1.X * (pt2.Y - pt1.Y) >= 0)
|
if (pt1.Y * (pt1.X - pt2.X) + pt1.X * (pt2.Y - pt1.Y) >= 0)
|
||||||
continue;
|
continue;
|
||||||
|
|
||||||
|
// Skip line if entirely behind portal clipping plane
|
||||||
|
if ((PortalClipPlane.A * line->v1->fX() + PortalClipPlane.B * line->v1->fY() + PortalClipPlane.D <= 0.0) ||
|
||||||
|
(PortalClipPlane.A * line->v2->fX() + PortalClipPlane.B * line->v2->fY() + PortalClipPlane.D <= 0.0))
|
||||||
|
{
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
angle_t angle1, angle2;
|
angle_t angle1, angle2;
|
||||||
if (GetAnglesForLine(line->v1->fX(), line->v1->fY(), line->v2->fX(), line->v2->fY(), angle1, angle2))
|
if (GetAnglesForLine(line->v1->fX(), line->v1->fY(), line->v2->fX(), line->v2->fY(), angle1, angle2))
|
||||||
{
|
{
|
||||||
|
@ -119,11 +140,11 @@ void PolyCull::InvertSegments()
|
||||||
angle_t cur = 0;
|
angle_t cur = 0;
|
||||||
for (const auto &segment : TempInvertSolidSegments)
|
for (const auto &segment : TempInvertSolidSegments)
|
||||||
{
|
{
|
||||||
if (segment.Start != 0 || segment.End != ANGLE_MAX)
|
if (cur < segment.Start)
|
||||||
MarkSegmentCulled(cur, segment.Start - 1);
|
MarkSegmentCulled(cur, segment.Start - 1);
|
||||||
cur = segment.End + 1;
|
cur = segment.End + 1;
|
||||||
}
|
}
|
||||||
if (cur != 0)
|
if (cur < ANGLE_MAX)
|
||||||
MarkSegmentCulled(cur, ANGLE_MAX);
|
MarkSegmentCulled(cur, ANGLE_MAX);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -241,32 +262,6 @@ bool PolyCull::CheckBBox(float *bspcoord)
|
||||||
|
|
||||||
bool PolyCull::GetAnglesForLine(double x1, double y1, double x2, double y2, angle_t &angle1, angle_t &angle2) const
|
bool PolyCull::GetAnglesForLine(double x1, double y1, double x2, double y2, angle_t &angle1, angle_t &angle2) const
|
||||||
{
|
{
|
||||||
#if 0
|
|
||||||
// Clip line to the portal clip plane
|
|
||||||
float distance1 = Vec4f::dot(PortalClipPlane, Vec4f((float)x1, (float)y1, 0.0f, 1.0f));
|
|
||||||
float distance2 = Vec4f::dot(PortalClipPlane, Vec4f((float)x2, (float)y2, 0.0f, 1.0f));
|
|
||||||
if (distance1 < 0.0f && distance2 < 0.0f)
|
|
||||||
{
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
else if (distance1 < 0.0f || distance2 < 0.0f)
|
|
||||||
{
|
|
||||||
double t1 = 0.0f, t2 = 1.0f;
|
|
||||||
if (distance1 < 0.0f)
|
|
||||||
t1 = clamp(distance1 / (distance1 - distance2), 0.0f, 1.0f);
|
|
||||||
else
|
|
||||||
t2 = clamp(distance2 / (distance1 - distance2), 0.0f, 1.0f);
|
|
||||||
double nx1 = x1 * (1.0 - t1) + x2 * t1;
|
|
||||||
double ny1 = y1 * (1.0 - t1) + y2 * t1;
|
|
||||||
double nx2 = x1 * (1.0 - t2) + x2 * t2;
|
|
||||||
double ny2 = y1 * (1.0 - t2) + y2 * t2;
|
|
||||||
x1 = nx1;
|
|
||||||
x2 = nx2;
|
|
||||||
y1 = ny1;
|
|
||||||
y2 = ny2;
|
|
||||||
}
|
|
||||||
#endif
|
|
||||||
|
|
||||||
angle2 = PointToPseudoAngle(x1, y1);
|
angle2 = PointToPseudoAngle(x1, y1);
|
||||||
angle1 = PointToPseudoAngle(x2, y2);
|
angle1 = PointToPseudoAngle(x2, y2);
|
||||||
return !IsSegmentCulled(angle1, angle2);
|
return !IsSegmentCulled(angle1, angle2);
|
||||||
|
|
|
@ -40,6 +40,8 @@ public:
|
||||||
double MaxCeilingHeight = 0.0;
|
double MaxCeilingHeight = 0.0;
|
||||||
double MinFloorHeight = 0.0;
|
double MinFloorHeight = 0.0;
|
||||||
|
|
||||||
|
static angle_t PointToPseudoAngle(double x, double y);
|
||||||
|
|
||||||
private:
|
private:
|
||||||
struct SolidSegment
|
struct SolidSegment
|
||||||
{
|
{
|
||||||
|
@ -62,6 +64,5 @@ private:
|
||||||
|
|
||||||
PolyClipPlane PortalClipPlane;
|
PolyClipPlane PortalClipPlane;
|
||||||
|
|
||||||
static angle_t PointToPseudoAngle(double x, double y);
|
|
||||||
static angle_t AngleToPseudo(angle_t ang);
|
static angle_t AngleToPseudo(angle_t ang);
|
||||||
};
|
};
|
||||||
|
|
|
@ -43,44 +43,10 @@ void PolyDrawSectorPortal::Render(int portalDepth)
|
||||||
if (Portal->mType == PORTS_HORIZON || Portal->mType == PORTS_PLANE)
|
if (Portal->mType == PORTS_HORIZON || Portal->mType == PORTS_PLANE)
|
||||||
return;
|
return;
|
||||||
|
|
||||||
const auto &viewpoint = PolyRenderer::Instance()->Viewpoint;
|
|
||||||
|
|
||||||
PolyClipPlane portalPlane(0.0f, 0.0f, 0.0f, 1.0f);
|
|
||||||
if (Portal->mType != PORTS_SKYVIEWPOINT)
|
|
||||||
{
|
|
||||||
float minHeight;
|
|
||||||
float maxHeight;
|
|
||||||
bool first = true;
|
|
||||||
for (const auto &range : Shape)
|
|
||||||
{
|
|
||||||
for (int i = 0; i < range.Count; i++)
|
|
||||||
{
|
|
||||||
if (first)
|
|
||||||
{
|
|
||||||
minHeight = range.Vertices[i].z;
|
|
||||||
maxHeight = range.Vertices[i].z;
|
|
||||||
first = false;
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
minHeight = MIN(minHeight, range.Vertices[i].z);
|
|
||||||
maxHeight = MAX(maxHeight, range.Vertices[i].z);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
if (!first && minHeight > viewpoint.Pos.Z)
|
|
||||||
{
|
|
||||||
portalPlane = PolyClipPlane(0.0f, 0.0f, 1.0f, -minHeight);
|
|
||||||
}
|
|
||||||
else if (!first && maxHeight < viewpoint.Pos.Z)
|
|
||||||
{
|
|
||||||
portalPlane = PolyClipPlane(0.0f, 0.0f, -1.0f, maxHeight);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
SaveGlobals();
|
SaveGlobals();
|
||||||
|
|
||||||
|
const auto &viewpoint = PolyRenderer::Instance()->Viewpoint;
|
||||||
|
|
||||||
// To do: get this information from PolyRenderer instead of duplicating the code..
|
// To do: get this information from PolyRenderer instead of duplicating the code..
|
||||||
const auto &viewwindow = PolyRenderer::Instance()->Viewwindow;
|
const auto &viewwindow = PolyRenderer::Instance()->Viewwindow;
|
||||||
double radPitch = viewpoint.Angles.Pitch.Normalized180().Radians();
|
double radPitch = viewpoint.Angles.Pitch.Normalized180().Radians();
|
||||||
|
@ -100,6 +66,7 @@ void PolyDrawSectorPortal::Render(int portalDepth)
|
||||||
TriMatrix::translate((float)-viewpoint.Pos.X, (float)-viewpoint.Pos.Y, (float)-viewpoint.Pos.Z);
|
TriMatrix::translate((float)-viewpoint.Pos.X, (float)-viewpoint.Pos.Y, (float)-viewpoint.Pos.Z);
|
||||||
TriMatrix worldToClip = TriMatrix::perspective(fovy, ratio, 5.0f, 65535.0f) * worldToView;
|
TriMatrix worldToClip = TriMatrix::perspective(fovy, ratio, 5.0f, 65535.0f) * worldToView;
|
||||||
|
|
||||||
|
PolyClipPlane portalPlane(0.0f, 0.0f, 0.0f, 1.0f);
|
||||||
RenderPortal.SetViewpoint(worldToClip, portalPlane, StencilValue);
|
RenderPortal.SetViewpoint(worldToClip, portalPlane, StencilValue);
|
||||||
RenderPortal.SetPortalSegments(Segments);
|
RenderPortal.SetPortalSegments(Segments);
|
||||||
RenderPortal.Render(portalDepth);
|
RenderPortal.Render(portalDepth);
|
||||||
|
@ -211,14 +178,29 @@ void PolyDrawLinePortal::Render(int portalDepth)
|
||||||
worldToView = TriMatrix::scale(-1.0f, 1.0f, 1.0f) * worldToView;
|
worldToView = TriMatrix::scale(-1.0f, 1.0f, 1.0f) * worldToView;
|
||||||
TriMatrix worldToClip = TriMatrix::perspective(fovy, ratio, 5.0f, 65535.0f) * worldToView;
|
TriMatrix worldToClip = TriMatrix::perspective(fovy, ratio, 5.0f, 65535.0f) * worldToView;
|
||||||
|
|
||||||
// Calculate plane clipping
|
// Find portal destination line and make sure it faces the right way
|
||||||
line_t *clipLine = Portal ? Portal->mDestination : Mirror;
|
line_t *clipLine = Portal ? Portal->mDestination : Mirror;
|
||||||
DVector2 planePos = clipLine->v1->fPos();
|
DVector2 pt1 = clipLine->v1->fPos() - viewpoint.Pos;
|
||||||
DVector2 planeNormal = (clipLine->v2->fPos() - clipLine->v1->fPos()).Rotated90CW();
|
DVector2 pt2 = clipLine->v2->fPos() - viewpoint.Pos;
|
||||||
|
bool backfacing = (pt1.Y * (pt1.X - pt2.X) + pt1.X * (pt2.Y - pt1.Y) >= 0);
|
||||||
|
vertex_t *v1 = backfacing ? clipLine->v1 : clipLine->v2;
|
||||||
|
vertex_t *v2 = backfacing ? clipLine->v2 : clipLine->v1;
|
||||||
|
|
||||||
|
// Calculate plane clipping
|
||||||
|
DVector2 planePos = v1->fPos();
|
||||||
|
DVector2 planeNormal = (v2->fPos() - v1->fPos()).Rotated90CW();
|
||||||
planeNormal.MakeUnit();
|
planeNormal.MakeUnit();
|
||||||
double planeD = -(planeNormal | (planePos + planeNormal * 0.001));
|
double planeD = -(planeNormal | (planePos + planeNormal * 0.001));
|
||||||
PolyClipPlane portalPlane((float)planeNormal.X, (float)planeNormal.Y, (float)0.0f, (float)planeD);
|
PolyClipPlane portalPlane((float)planeNormal.X, (float)planeNormal.Y, (float)0.0f, (float)planeD);
|
||||||
|
|
||||||
|
// Cull everything outside the portal line
|
||||||
|
// To do: this doesn't work for some strange reason..
|
||||||
|
/*angle_t angle1 = PolyCull::PointToPseudoAngle(v1->fX(), v1->fY());
|
||||||
|
angle_t angle2 = PolyCull::PointToPseudoAngle(v2->fX(), v2->fY());
|
||||||
|
Segments.clear();
|
||||||
|
Segments.push_back({ angle1, angle2 });*/
|
||||||
|
|
||||||
|
RenderPortal.LastPortalLine = clipLine;
|
||||||
RenderPortal.SetViewpoint(worldToClip, portalPlane, StencilValue);
|
RenderPortal.SetViewpoint(worldToClip, portalPlane, StencilValue);
|
||||||
RenderPortal.SetPortalSegments(Segments);
|
RenderPortal.SetPortalSegments(Segments);
|
||||||
RenderPortal.Render(portalDepth);
|
RenderPortal.Render(portalDepth);
|
||||||
|
@ -296,6 +278,9 @@ void PolyDrawLinePortal::SaveGlobals()
|
||||||
P_TranslatePortalXY(src, viewpoint.Path[0].X, viewpoint.Path[0].Y);
|
P_TranslatePortalXY(src, viewpoint.Path[0].X, viewpoint.Path[0].Y);
|
||||||
P_TranslatePortalXY(src, viewpoint.Path[1].X, viewpoint.Path[1].Y);
|
P_TranslatePortalXY(src, viewpoint.Path[1].X, viewpoint.Path[1].Y);
|
||||||
|
|
||||||
|
if (viewpoint.camera)
|
||||||
|
viewpoint.camera->renderflags &= ~RF_INVISIBLE;
|
||||||
|
|
||||||
if (!viewpoint.showviewer && viewpoint.camera && P_PointOnLineSidePrecise(viewpoint.Path[0], dst) != P_PointOnLineSidePrecise(viewpoint.Path[1], dst))
|
if (!viewpoint.showviewer && viewpoint.camera && P_PointOnLineSidePrecise(viewpoint.Path[0], dst) != P_PointOnLineSidePrecise(viewpoint.Path[1], dst))
|
||||||
{
|
{
|
||||||
double distp = (viewpoint.Path[0] - viewpoint.Path[1]).Length();
|
double distp = (viewpoint.Path[0] - viewpoint.Path[1]).Length();
|
||||||
|
@ -312,8 +297,8 @@ void PolyDrawLinePortal::SaveGlobals()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
//camera = nullptr;
|
viewpoint.camera = nullptr;
|
||||||
//viewsector = R_PointInSubsector(ViewPos)->sector;
|
viewpoint.sector = R_PointInSubsector(viewpoint.Pos)->sector;
|
||||||
R_SetViewAngle(viewpoint, viewwindow);
|
R_SetViewAngle(viewpoint, viewwindow);
|
||||||
|
|
||||||
if (Mirror)
|
if (Mirror)
|
||||||
|
|
|
@ -219,7 +219,7 @@ void RenderPolyScene::RenderPolySubsector(subsector_t *sub, uint32_t subsectorDe
|
||||||
}
|
}
|
||||||
|
|
||||||
// Render wall, and update culling info if its an occlusion blocker
|
// Render wall, and update culling info if its an occlusion blocker
|
||||||
if (RenderPolyWall::RenderLine(WorldToClip, PortalPlane, Cull, line, frontsector, subsectorDepth, StencilValue, TranslucentObjects, LinePortals))
|
if (RenderPolyWall::RenderLine(WorldToClip, PortalPlane, Cull, line, frontsector, subsectorDepth, StencilValue, TranslucentObjects, LinePortals, LastPortalLine))
|
||||||
{
|
{
|
||||||
Cull.MarkSegmentCulled(angle1, angle2);
|
Cull.MarkSegmentCulled(angle1, angle2);
|
||||||
}
|
}
|
||||||
|
@ -319,7 +319,7 @@ void RenderPolyScene::RenderLine(subsector_t *sub, seg_t *line, sector_t *fronts
|
||||||
}
|
}
|
||||||
|
|
||||||
// Render wall, and update culling info if its an occlusion blocker
|
// Render wall, and update culling info if its an occlusion blocker
|
||||||
if (RenderPolyWall::RenderLine(WorldToClip, PortalPlane, Cull, line, frontsector, subsectorDepth, StencilValue, TranslucentObjects, LinePortals))
|
if (RenderPolyWall::RenderLine(WorldToClip, PortalPlane, Cull, line, frontsector, subsectorDepth, StencilValue, TranslucentObjects, LinePortals, LastPortalLine))
|
||||||
{
|
{
|
||||||
Cull.MarkSegmentCulled(angle1, angle2);
|
Cull.MarkSegmentCulled(angle1, angle2);
|
||||||
}
|
}
|
||||||
|
|
|
@ -80,6 +80,8 @@ public:
|
||||||
|
|
||||||
static const uint32_t SkySubsectorDepth = 0x7fffffff;
|
static const uint32_t SkySubsectorDepth = 0x7fffffff;
|
||||||
|
|
||||||
|
line_t *LastPortalLine = nullptr;
|
||||||
|
|
||||||
private:
|
private:
|
||||||
void ClearBuffers();
|
void ClearBuffers();
|
||||||
void RenderPortals(int portalDepth);
|
void RenderPortals(int portalDepth);
|
||||||
|
|
|
@ -37,36 +37,51 @@
|
||||||
|
|
||||||
EXTERN_CVAR(Bool, r_drawmirrors)
|
EXTERN_CVAR(Bool, r_drawmirrors)
|
||||||
|
|
||||||
bool RenderPolyWall::RenderLine(const TriMatrix &worldToClip, const PolyClipPlane &clipPlane, PolyCull &cull, seg_t *line, sector_t *frontsector, uint32_t subsectorDepth, uint32_t stencilValue, std::vector<PolyTranslucentObject*> &translucentWallsOutput, std::vector<std::unique_ptr<PolyDrawLinePortal>> &linePortals)
|
bool RenderPolyWall::RenderLine(const TriMatrix &worldToClip, const PolyClipPlane &clipPlane, PolyCull &cull, seg_t *line, sector_t *frontsector, uint32_t subsectorDepth, uint32_t stencilValue, std::vector<PolyTranslucentObject*> &translucentWallsOutput, std::vector<std::unique_ptr<PolyDrawLinePortal>> &linePortals, line_t *lastPortalLine)
|
||||||
{
|
{
|
||||||
|
double frontceilz1 = frontsector->ceilingplane.ZatPoint(line->v1);
|
||||||
|
double frontfloorz1 = frontsector->floorplane.ZatPoint(line->v1);
|
||||||
|
double frontceilz2 = frontsector->ceilingplane.ZatPoint(line->v2);
|
||||||
|
double frontfloorz2 = frontsector->floorplane.ZatPoint(line->v2);
|
||||||
|
double topTexZ = frontsector->GetPlaneTexZ(sector_t::ceiling);
|
||||||
|
double bottomTexZ = frontsector->GetPlaneTexZ(sector_t::floor);
|
||||||
|
|
||||||
PolyDrawLinePortal *polyportal = nullptr;
|
PolyDrawLinePortal *polyportal = nullptr;
|
||||||
if (line->backsector == nullptr && line->linedef && line->sidedef == line->linedef->sidedef[0] && (line->linedef->special == Line_Mirror && r_drawmirrors))
|
if (line->backsector == nullptr && line->linedef && line->sidedef == line->linedef->sidedef[0] && (line->linedef->special == Line_Mirror && r_drawmirrors))
|
||||||
{
|
{
|
||||||
if (PolyRenderer::Instance()->InsertSeenMirror(line->linedef))
|
if (lastPortalLine == line->linedef ||
|
||||||
|
(line->linedef->v1->fX() * clipPlane.A + line->linedef->v1->fY() * clipPlane.B + clipPlane.D <= 0.0f) ||
|
||||||
|
(line->linedef->v2->fX() * clipPlane.A + line->linedef->v2->fY() * clipPlane.B + clipPlane.D <= 0.0f))
|
||||||
{
|
{
|
||||||
linePortals.push_back(std::unique_ptr<PolyDrawLinePortal>(new PolyDrawLinePortal(line->linedef)));
|
return false;
|
||||||
polyportal = linePortals.back().get();
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
linePortals.push_back(std::unique_ptr<PolyDrawLinePortal>(new PolyDrawLinePortal(line->linedef)));
|
||||||
|
polyportal = linePortals.back().get();
|
||||||
}
|
}
|
||||||
else if (line->linedef && line->linedef->isVisualPortal())
|
else if (line->linedef && line->linedef->isVisualPortal())
|
||||||
{
|
{
|
||||||
FLinePortal *portal = line->linedef->getPortal();
|
if (lastPortalLine == line->linedef ||
|
||||||
if (PolyRenderer::Instance()->InsertSeenLinePortal(portal))
|
(line->linedef->v1->fX() * clipPlane.A + line->linedef->v1->fY() * clipPlane.B + clipPlane.D <= 0.0f) ||
|
||||||
|
(line->linedef->v2->fX() * clipPlane.A + line->linedef->v2->fY() * clipPlane.B + clipPlane.D <= 0.0f))
|
||||||
{
|
{
|
||||||
for (auto &p : linePortals)
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
FLinePortal *portal = line->linedef->getPortal();
|
||||||
|
for (auto &p : linePortals)
|
||||||
|
{
|
||||||
|
if (p->Portal == portal) // To do: what other criterias do we need to check for?
|
||||||
{
|
{
|
||||||
if (p->Portal == portal) // To do: what other criterias do we need to check for?
|
polyportal = p.get();
|
||||||
{
|
break;
|
||||||
polyportal = p.get();
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
if (!polyportal)
|
|
||||||
{
|
|
||||||
linePortals.push_back(std::unique_ptr<PolyDrawLinePortal>(new PolyDrawLinePortal(portal)));
|
|
||||||
polyportal = linePortals.back().get();
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
if (!polyportal)
|
||||||
|
{
|
||||||
|
linePortals.push_back(std::unique_ptr<PolyDrawLinePortal>(new PolyDrawLinePortal(portal)));
|
||||||
|
polyportal = linePortals.back().get();
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
RenderPolyWall wall;
|
RenderPolyWall wall;
|
||||||
|
@ -78,13 +93,6 @@ bool RenderPolyWall::RenderLine(const TriMatrix &worldToClip, const PolyClipPlan
|
||||||
wall.SubsectorDepth = subsectorDepth;
|
wall.SubsectorDepth = subsectorDepth;
|
||||||
wall.StencilValue = stencilValue;
|
wall.StencilValue = stencilValue;
|
||||||
|
|
||||||
double frontceilz1 = frontsector->ceilingplane.ZatPoint(line->v1);
|
|
||||||
double frontfloorz1 = frontsector->floorplane.ZatPoint(line->v1);
|
|
||||||
double frontceilz2 = frontsector->ceilingplane.ZatPoint(line->v2);
|
|
||||||
double frontfloorz2 = frontsector->floorplane.ZatPoint(line->v2);
|
|
||||||
double topTexZ = frontsector->GetPlaneTexZ(sector_t::ceiling);
|
|
||||||
double bottomTexZ = frontsector->GetPlaneTexZ(sector_t::floor);
|
|
||||||
|
|
||||||
if (line->backsector == nullptr)
|
if (line->backsector == nullptr)
|
||||||
{
|
{
|
||||||
if (line->sidedef)
|
if (line->sidedef)
|
||||||
|
@ -244,6 +252,14 @@ void RenderPolyWall::Render(const TriMatrix &worldToClip, const PolyClipPlane &c
|
||||||
vertices[3].u = (float)texcoordsU.u1;
|
vertices[3].u = (float)texcoordsU.u1;
|
||||||
vertices[3].v = (float)texcoordsVLeft.v2;
|
vertices[3].v = (float)texcoordsVLeft.v2;
|
||||||
}
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
for (int i = 0; i < 4; i++)
|
||||||
|
{
|
||||||
|
vertices[i].u = 0.0f;
|
||||||
|
vertices[i].v = 0.0f;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
// Masked walls clamp to the 0-1 range (no texture repeat)
|
// Masked walls clamp to the 0-1 range (no texture repeat)
|
||||||
if (Masked)
|
if (Masked)
|
||||||
|
@ -259,7 +275,7 @@ void RenderPolyWall::Render(const TriMatrix &worldToClip, const PolyClipPlane &c
|
||||||
args.SetFaceCullCCW(true);
|
args.SetFaceCullCCW(true);
|
||||||
args.SetStencilTestValue(StencilValue);
|
args.SetStencilTestValue(StencilValue);
|
||||||
args.SetWriteStencil(true, StencilValue + 1);
|
args.SetWriteStencil(true, StencilValue + 1);
|
||||||
if (tex)
|
if (tex && !Polyportal)
|
||||||
args.SetTexture(tex);
|
args.SetTexture(tex);
|
||||||
args.SetClipPlane(clipPlane);
|
args.SetClipPlane(clipPlane);
|
||||||
|
|
||||||
|
@ -270,10 +286,6 @@ void RenderPolyWall::Render(const TriMatrix &worldToClip, const PolyClipPlane &c
|
||||||
args.SetWriteSubsectorDepth(false);
|
args.SetWriteSubsectorDepth(false);
|
||||||
args.DrawArray(vertices, 4, PolyDrawMode::TriangleFan);
|
args.DrawArray(vertices, 4, PolyDrawMode::TriangleFan);
|
||||||
Polyportal->Shape.push_back({ vertices, 4, true, SubsectorDepth });
|
Polyportal->Shape.push_back({ vertices, 4, true, SubsectorDepth });
|
||||||
|
|
||||||
angle_t angle1, angle2;
|
|
||||||
if (cull.GetAnglesForLine(v1.X, v1.Y, v2.X, v2.Y, angle1, angle2))
|
|
||||||
Polyportal->Segments.push_back({ angle1, angle2 });
|
|
||||||
}
|
}
|
||||||
else if (!Masked)
|
else if (!Masked)
|
||||||
{
|
{
|
||||||
|
@ -363,20 +375,24 @@ int RenderPolyWall::GetLightLevel()
|
||||||
|
|
||||||
PolyWallTextureCoordsU::PolyWallTextureCoordsU(FTexture *tex, const seg_t *lineseg, const line_t *line, const side_t *side, side_t::ETexpart texpart)
|
PolyWallTextureCoordsU::PolyWallTextureCoordsU(FTexture *tex, const seg_t *lineseg, const line_t *line, const side_t *side, side_t::ETexpart texpart)
|
||||||
{
|
{
|
||||||
double lineLength = side->TexelLength;
|
double t1, t2;
|
||||||
double lineStart = 0.0;
|
double deltaX = line->v2->fX() - line->v1->fX();
|
||||||
|
double deltaY = line->v2->fY() - line->v1->fY();
|
||||||
bool entireSegment = ((lineseg->v1 == line->v1) && (lineseg->v2 == line->v2)) || ((lineseg->v2 == line->v1) && (lineseg->v1 == line->v2));
|
if (fabs(deltaX) > fabs(deltaY))
|
||||||
if (!entireSegment)
|
|
||||||
{
|
{
|
||||||
lineLength = (lineseg->v2->fPos() - lineseg->v1->fPos()).Length();
|
t1 = (lineseg->v1->fX() - line->v1->fX()) / deltaX;
|
||||||
lineStart = (lineseg->v1->fPos() - line->v1->fPos()).Length();
|
t2 = (lineseg->v2->fX() - line->v1->fX()) / deltaX;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
t1 = (lineseg->v1->fY() - line->v1->fY()) / deltaY;
|
||||||
|
t2 = (lineseg->v2->fY() - line->v1->fY()) / deltaY;
|
||||||
}
|
}
|
||||||
|
|
||||||
int texWidth = tex->GetWidth();
|
int texWidth = tex->GetWidth();
|
||||||
double uscale = side->GetTextureXScale(texpart) * tex->Scale.X;
|
double uscale = side->GetTextureXScale(texpart) * tex->Scale.X;
|
||||||
u1 = lineStart + side->GetTextureXOffset(texpart);
|
u1 = t1 * side->TexelLength + side->GetTextureXOffset(texpart);
|
||||||
u2 = u1 + lineLength;
|
u2 = t2 * side->TexelLength + side->GetTextureXOffset(texpart);
|
||||||
u1 *= uscale;
|
u1 *= uscale;
|
||||||
u2 *= uscale;
|
u2 *= uscale;
|
||||||
u1 /= texWidth;
|
u1 /= texWidth;
|
||||||
|
|
|
@ -31,7 +31,7 @@ class PolyCull;
|
||||||
class RenderPolyWall
|
class RenderPolyWall
|
||||||
{
|
{
|
||||||
public:
|
public:
|
||||||
static bool RenderLine(const TriMatrix &worldToClip, const PolyClipPlane &clipPlane, PolyCull &cull, seg_t *line, sector_t *frontsector, uint32_t subsectorDepth, uint32_t stencilValue, std::vector<PolyTranslucentObject*> &translucentWallsOutput, std::vector<std::unique_ptr<PolyDrawLinePortal>> &linePortals);
|
static bool RenderLine(const TriMatrix &worldToClip, const PolyClipPlane &clipPlane, PolyCull &cull, seg_t *line, sector_t *frontsector, uint32_t subsectorDepth, uint32_t stencilValue, std::vector<PolyTranslucentObject*> &translucentWallsOutput, std::vector<std::unique_ptr<PolyDrawLinePortal>> &linePortals, line_t *lastPortalLine);
|
||||||
static void Render3DFloorLine(const TriMatrix &worldToClip, const PolyClipPlane &clipPlane, PolyCull &cull, seg_t *line, sector_t *frontsector, uint32_t subsectorDepth, uint32_t stencilValue, F3DFloor *fakeFloor, std::vector<PolyTranslucentObject*> &translucentWallsOutput);
|
static void Render3DFloorLine(const TriMatrix &worldToClip, const PolyClipPlane &clipPlane, PolyCull &cull, seg_t *line, sector_t *frontsector, uint32_t subsectorDepth, uint32_t stencilValue, F3DFloor *fakeFloor, std::vector<PolyTranslucentObject*> &translucentWallsOutput);
|
||||||
|
|
||||||
void SetCoords(const DVector2 &v1, const DVector2 &v2, double ceil1, double floor1, double ceil2, double floor2);
|
void SetCoords(const DVector2 &v1, const DVector2 &v2, double ceil1, double floor1, double ceil2, double floor2);
|
||||||
|
|
|
@ -1027,8 +1027,17 @@ void P_CreateLinkedPortals()
|
||||||
{
|
{
|
||||||
if (linePortals[i].mType == PORTT_LINKED)
|
if (linePortals[i].mType == PORTT_LINKED)
|
||||||
{
|
{
|
||||||
if (CollectSectors(id, linePortals[i].mOrigin->frontsector)) id++;
|
if (linePortals[i].mDestination == nullptr)
|
||||||
if (CollectSectors(id, linePortals[i].mDestination->frontsector)) id++;
|
{
|
||||||
|
Printf("Linked portal on line %d is unconnected and will be disabled\n", linePortals[i].mOrigin->Index());
|
||||||
|
linePortals[i].mOrigin->portalindex = UINT_MAX;
|
||||||
|
linePortals[i].mType = PORTT_VISUAL;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
if (CollectSectors(id, linePortals[i].mOrigin->frontsector)) id++;
|
||||||
|
if (CollectSectors(id, linePortals[i].mDestination->frontsector)) id++;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -1237,6 +1246,7 @@ bool P_CollectConnectedGroups(int startgroup, const DVector3 &position, double u
|
||||||
{
|
{
|
||||||
int othergroup = wsec->GetOppositePortalGroup(sector_t::ceiling);
|
int othergroup = wsec->GetOppositePortalGroup(sector_t::ceiling);
|
||||||
DVector2 pos = Displacements.getOffset(startgroup, othergroup) + position;
|
DVector2 pos = Displacements.getOffset(startgroup, othergroup) + position;
|
||||||
|
if (processMask.getBit(othergroup)) break;
|
||||||
processMask.setBit(othergroup);
|
processMask.setBit(othergroup);
|
||||||
out.Add(othergroup | FPortalGroupArray::UPPER);
|
out.Add(othergroup | FPortalGroupArray::UPPER);
|
||||||
wsec = P_PointInSector(pos); // get upper sector at the exact spot we want to check and repeat
|
wsec = P_PointInSector(pos); // get upper sector at the exact spot we want to check and repeat
|
||||||
|
@ -1247,6 +1257,7 @@ bool P_CollectConnectedGroups(int startgroup, const DVector3 &position, double u
|
||||||
{
|
{
|
||||||
int othergroup = wsec->GetOppositePortalGroup(sector_t::floor);
|
int othergroup = wsec->GetOppositePortalGroup(sector_t::floor);
|
||||||
DVector2 pos = Displacements.getOffset(startgroup, othergroup) + position;
|
DVector2 pos = Displacements.getOffset(startgroup, othergroup) + position;
|
||||||
|
if (processMask.getBit(othergroup)) break;
|
||||||
processMask.setBit(othergroup);
|
processMask.setBit(othergroup);
|
||||||
out.Add(othergroup | FPortalGroupArray::LOWER);
|
out.Add(othergroup | FPortalGroupArray::LOWER);
|
||||||
wsec = P_PointInSector(pos); // get lower sector at the exact spot we want to check and repeat
|
wsec = P_PointInSector(pos); // get lower sector at the exact spot we want to check and repeat
|
||||||
|
|
|
@ -555,3 +555,38 @@ int SDLGLFB::GetClientHeight()
|
||||||
SDL_GL_GetDrawableSize(Screen, nullptr, &height);
|
SDL_GL_GetDrawableSize(Screen, nullptr, &height);
|
||||||
return height;
|
return height;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void SDLGLFB::ScaleCoordsFromWindow(int16_t &x, int16_t &y)
|
||||||
|
{
|
||||||
|
int w, h;
|
||||||
|
SDL_GetWindowSize (Screen, &w, &h);
|
||||||
|
|
||||||
|
// Detect if we're doing scaling in the Window and adjust the mouse
|
||||||
|
// coordinates accordingly. This could be more efficent, but I
|
||||||
|
// don't think performance is an issue in the menus.
|
||||||
|
if(IsFullscreen())
|
||||||
|
{
|
||||||
|
int realw = w, realh = h;
|
||||||
|
ScaleWithAspect (realw, realh, SCREENWIDTH, SCREENHEIGHT);
|
||||||
|
if (realw != SCREENWIDTH || realh != SCREENHEIGHT)
|
||||||
|
{
|
||||||
|
double xratio = (double)SCREENWIDTH/realw;
|
||||||
|
double yratio = (double)SCREENHEIGHT/realh;
|
||||||
|
if (realw < w)
|
||||||
|
{
|
||||||
|
x = (x - (w - realw)/2)*xratio;
|
||||||
|
y *= yratio;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
y = (y - (h - realh)/2)*yratio;
|
||||||
|
x *= xratio;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
x = (int16_t)(x*Width/w);
|
||||||
|
y = (int16_t)(y*Height/h);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
|
@ -72,6 +72,8 @@ public:
|
||||||
int GetClientWidth();
|
int GetClientWidth();
|
||||||
int GetClientHeight();
|
int GetClientHeight();
|
||||||
|
|
||||||
|
virtual void ScaleCoordsFromWindow(int16_t &x, int16_t &y);
|
||||||
|
|
||||||
SDL_Window *GetSDLWindow() override { return Screen; }
|
SDL_Window *GetSDLWindow() override { return Screen; }
|
||||||
|
|
||||||
protected:
|
protected:
|
||||||
|
|
|
@ -112,31 +112,6 @@ static cycle_t SDLFlipCycles;
|
||||||
|
|
||||||
// CODE --------------------------------------------------------------------
|
// CODE --------------------------------------------------------------------
|
||||||
|
|
||||||
void ScaleWithAspect (int &w, int &h, int Width, int Height)
|
|
||||||
{
|
|
||||||
int resRatio = CheckRatio (Width, Height);
|
|
||||||
int screenRatio;
|
|
||||||
CheckRatio (w, h, &screenRatio);
|
|
||||||
if (resRatio == screenRatio)
|
|
||||||
return;
|
|
||||||
|
|
||||||
double yratio;
|
|
||||||
switch(resRatio)
|
|
||||||
{
|
|
||||||
case 0: yratio = 4./3.; break;
|
|
||||||
case 1: yratio = 16./9.; break;
|
|
||||||
case 2: yratio = 16./10.; break;
|
|
||||||
case 3: yratio = 17./10.; break;
|
|
||||||
case 4: yratio = 5./4.; break;
|
|
||||||
default: return;
|
|
||||||
}
|
|
||||||
double y = w/yratio;
|
|
||||||
if (y > h)
|
|
||||||
w = h*yratio;
|
|
||||||
else
|
|
||||||
h = y;
|
|
||||||
}
|
|
||||||
|
|
||||||
// FrameBuffer implementation -----------------------------------------------
|
// FrameBuffer implementation -----------------------------------------------
|
||||||
|
|
||||||
SDLFB::SDLFB (int width, int height, bool bgra, bool fullscreen, SDL_Window *oldwin)
|
SDLFB::SDLFB (int width, int height, bool bgra, bool fullscreen, SDL_Window *oldwin)
|
||||||
|
|
|
@ -236,11 +236,6 @@ public:
|
||||||
{
|
{
|
||||||
return "Null sound module has no stats.";
|
return "Null sound module has no stats.";
|
||||||
}
|
}
|
||||||
|
|
||||||
virtual MIDIDevice* CreateMIDIDevice() const override
|
|
||||||
{
|
|
||||||
return nullptr;
|
|
||||||
}
|
|
||||||
};
|
};
|
||||||
|
|
||||||
void I_InitSound ()
|
void I_InitSound ()
|
||||||
|
|
|
@ -168,8 +168,6 @@ public:
|
||||||
|
|
||||||
virtual void DrawWaveDebug(int mode);
|
virtual void DrawWaveDebug(int mode);
|
||||||
|
|
||||||
virtual MIDIDevice* CreateMIDIDevice() const = 0;
|
|
||||||
|
|
||||||
static SoundDecoder *CreateDecoder(FileReader *reader);
|
static SoundDecoder *CreateDecoder(FileReader *reader);
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
|
@ -1,344 +0,0 @@
|
||||||
//
|
|
||||||
//---------------------------------------------------------------------------
|
|
||||||
//
|
|
||||||
// MIDI device for Apple's macOS using AudioToolbox framework
|
|
||||||
// Copyright(C) 2017 Alexey Lysiuk
|
|
||||||
// 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/
|
|
||||||
//
|
|
||||||
//--------------------------------------------------------------------------
|
|
||||||
//
|
|
||||||
|
|
||||||
// Implementation is loosely based on macOS native MIDI support from SDL_mixer
|
|
||||||
|
|
||||||
#ifdef __APPLE__
|
|
||||||
|
|
||||||
#include <AudioToolbox/AudioToolbox.h>
|
|
||||||
#include "i_musicinterns.h"
|
|
||||||
#include "templates.h"
|
|
||||||
|
|
||||||
// AudioToolbox implementation of a MIDI output device ----------------------
|
|
||||||
|
|
||||||
class AudioToolboxMIDIDevice : public MIDIDevice
|
|
||||||
{
|
|
||||||
public:
|
|
||||||
virtual int Open(MidiCallback, void *userData) override;
|
|
||||||
virtual void Close() override;
|
|
||||||
virtual bool IsOpen() const override;
|
|
||||||
virtual int GetTechnology() const override;
|
|
||||||
virtual int SetTempo(int tempo) override;
|
|
||||||
virtual int SetTimeDiv(int timediv) override;
|
|
||||||
virtual int StreamOut(MidiHeader *data) override;
|
|
||||||
virtual int StreamOutSync(MidiHeader *data) override;
|
|
||||||
virtual int Resume() override;
|
|
||||||
virtual void Stop() override;
|
|
||||||
virtual int PrepareHeader(MidiHeader* data) override;
|
|
||||||
virtual bool FakeVolume() override { return true; }
|
|
||||||
virtual bool Pause(bool paused) override;
|
|
||||||
virtual bool Preprocess(MIDIStreamer *song, bool looping) override;
|
|
||||||
|
|
||||||
private:
|
|
||||||
MusicPlayer m_player = nullptr;
|
|
||||||
MusicSequence m_sequence = nullptr;
|
|
||||||
AudioUnit m_audioUnit = nullptr;
|
|
||||||
CFRunLoopTimerRef m_timer = nullptr;
|
|
||||||
MusicTimeStamp m_length = 0;
|
|
||||||
|
|
||||||
MidiCallback m_callback = nullptr;
|
|
||||||
void* m_userData = nullptr;
|
|
||||||
|
|
||||||
static void TimerCallback(CFRunLoopTimerRef timer, void* info);
|
|
||||||
};
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
#define AT_MIDI_CHECK_ERROR(CALL,...) \
|
|
||||||
{ \
|
|
||||||
const OSStatus result = CALL; \
|
|
||||||
if (noErr != result) \
|
|
||||||
{ \
|
|
||||||
DPrintf(DMSG_ERROR, \
|
|
||||||
"Failed with error 0x%08X at " __FILE__ ":%d:\n> %s", \
|
|
||||||
int(result), __LINE__, #CALL); \
|
|
||||||
return __VA_ARGS__; \
|
|
||||||
} \
|
|
||||||
}
|
|
||||||
|
|
||||||
int AudioToolboxMIDIDevice::Open(MidiCallback callback, void *userData)
|
|
||||||
{
|
|
||||||
AT_MIDI_CHECK_ERROR(NewMusicPlayer(&m_player), false);
|
|
||||||
AT_MIDI_CHECK_ERROR(NewMusicSequence(&m_sequence), false);
|
|
||||||
AT_MIDI_CHECK_ERROR(MusicPlayerSetSequence(m_player, m_sequence), false);
|
|
||||||
|
|
||||||
CFRunLoopTimerContext context = { 0, this, nullptr, nullptr, nullptr };
|
|
||||||
m_timer = CFRunLoopTimerCreate(kCFAllocatorDefault, CFAbsoluteTimeGetCurrent(), 0.1, 0, 0, TimerCallback, &context);
|
|
||||||
|
|
||||||
if (nullptr == m_timer)
|
|
||||||
{
|
|
||||||
DPrintf(DMSG_ERROR, "Failed with create timer for MIDI playback");
|
|
||||||
return 1;
|
|
||||||
}
|
|
||||||
|
|
||||||
CFRunLoopAddTimer(CFRunLoopGetCurrent(), m_timer, kCFRunLoopDefaultMode);
|
|
||||||
|
|
||||||
m_callback = callback;
|
|
||||||
m_userData = userData;
|
|
||||||
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
void AudioToolboxMIDIDevice::Close()
|
|
||||||
{
|
|
||||||
m_length = 0;
|
|
||||||
m_audioUnit = nullptr;
|
|
||||||
|
|
||||||
m_callback = nullptr;
|
|
||||||
m_userData = nullptr;
|
|
||||||
|
|
||||||
if (nullptr != m_timer)
|
|
||||||
{
|
|
||||||
CFRunLoopRemoveTimer(CFRunLoopGetCurrent(), m_timer, kCFRunLoopDefaultMode);
|
|
||||||
|
|
||||||
CFRelease(m_timer);
|
|
||||||
m_timer = nullptr;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (nullptr != m_sequence)
|
|
||||||
{
|
|
||||||
DisposeMusicSequence(m_sequence);
|
|
||||||
m_sequence = nullptr;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (nullptr != m_player)
|
|
||||||
{
|
|
||||||
DisposeMusicPlayer(m_player);
|
|
||||||
m_player = nullptr;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
bool AudioToolboxMIDIDevice::IsOpen() const
|
|
||||||
{
|
|
||||||
return nullptr != m_player
|
|
||||||
&& nullptr != m_sequence
|
|
||||||
&& nullptr != m_timer;
|
|
||||||
}
|
|
||||||
|
|
||||||
int AudioToolboxMIDIDevice::GetTechnology() const
|
|
||||||
{
|
|
||||||
return MIDIDEV_SWSYNTH;
|
|
||||||
}
|
|
||||||
|
|
||||||
int AudioToolboxMIDIDevice::SetTempo(int tempo)
|
|
||||||
{
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
int AudioToolboxMIDIDevice::SetTimeDiv(int timediv)
|
|
||||||
{
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
int AudioToolboxMIDIDevice::StreamOut(MidiHeader* data)
|
|
||||||
{
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
int AudioToolboxMIDIDevice::StreamOutSync(MidiHeader* data)
|
|
||||||
{
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
int AudioToolboxMIDIDevice::Resume()
|
|
||||||
{
|
|
||||||
AT_MIDI_CHECK_ERROR(MusicPlayerSetTime(m_player, 0), false);
|
|
||||||
AT_MIDI_CHECK_ERROR(MusicPlayerPreroll(m_player), false);
|
|
||||||
|
|
||||||
if (nullptr == m_audioUnit)
|
|
||||||
{
|
|
||||||
AUGraph graph;
|
|
||||||
AT_MIDI_CHECK_ERROR(MusicSequenceGetAUGraph(m_sequence, &graph), false);
|
|
||||||
|
|
||||||
UInt32 nodecount;
|
|
||||||
AT_MIDI_CHECK_ERROR(AUGraphGetNodeCount(graph, &nodecount), false);
|
|
||||||
|
|
||||||
for (UInt32 i = 0; i < nodecount; ++i)
|
|
||||||
{
|
|
||||||
AUNode node;
|
|
||||||
AT_MIDI_CHECK_ERROR(AUGraphGetIndNode(graph, i, &node), false);
|
|
||||||
|
|
||||||
AudioUnit audioUnit = nullptr;
|
|
||||||
#if MAC_OS_X_VERSION_MAX_ALLOWED < 1050
|
|
||||||
ComponentDescription desc = {};
|
|
||||||
UInt32 classdatasize = 0;
|
|
||||||
void *classdata = nullptr;
|
|
||||||
AT_MIDI_CHECK_ERROR(AUGraphGetNodeInfo(graph, node, &desc, &classdatasize, &classdata, &audioUnit), false);
|
|
||||||
#else // 10.5 and above
|
|
||||||
AudioComponentDescription desc = {};
|
|
||||||
AT_MIDI_CHECK_ERROR(AUGraphNodeInfo(graph, node, &desc, &audioUnit), false);
|
|
||||||
#endif // prior to 10.5
|
|
||||||
|
|
||||||
if ( kAudioUnitType_Output != desc.componentType
|
|
||||||
|| kAudioUnitSubType_DefaultOutput != desc.componentSubType)
|
|
||||||
{
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
|
|
||||||
const float volume = clamp<float>(snd_musicvolume * relative_volume, 0.f, 1.f);
|
|
||||||
AT_MIDI_CHECK_ERROR(AudioUnitSetParameter(audioUnit, kHALOutputParam_Volume, kAudioUnitScope_Global, 0, volume, 0), false);
|
|
||||||
|
|
||||||
m_audioUnit = audioUnit;
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
AT_MIDI_CHECK_ERROR(MusicPlayerStart(m_player), false);
|
|
||||||
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
void AudioToolboxMIDIDevice::Stop()
|
|
||||||
{
|
|
||||||
AT_MIDI_CHECK_ERROR(MusicPlayerStop(m_player));
|
|
||||||
}
|
|
||||||
|
|
||||||
int AudioToolboxMIDIDevice::PrepareHeader(MidiHeader* data)
|
|
||||||
{
|
|
||||||
MidiHeader* events = data;
|
|
||||||
uint32_t position = 0;
|
|
||||||
|
|
||||||
while (nullptr != events)
|
|
||||||
{
|
|
||||||
uint32_t* const event = reinterpret_cast<uint32_t*>(events->lpData + position);
|
|
||||||
const uint32_t message = event[2];
|
|
||||||
|
|
||||||
if (0 == MEVENT_EVENTTYPE(message))
|
|
||||||
{
|
|
||||||
static const uint32_t VOLUME_CHANGE_EVENT = 7;
|
|
||||||
|
|
||||||
const uint32_t status = message & 0xFF;
|
|
||||||
const uint32_t param1 = (message >> 8) & 0x7F;
|
|
||||||
const uint32_t param2 = (message >> 16) & 0x7F;
|
|
||||||
|
|
||||||
if (nullptr != m_audioUnit && MIDI_CTRLCHANGE == status && VOLUME_CHANGE_EVENT == param1)
|
|
||||||
{
|
|
||||||
AT_MIDI_CHECK_ERROR(AudioUnitSetParameter(m_audioUnit, kHALOutputParam_Volume, kAudioUnitScope_Global, 0, param2 / 100.f, 0), false);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// Advance to next event
|
|
||||||
position += 12 + ( (message < 0x80000000)
|
|
||||||
? 0
|
|
||||||
: ((MEVENT_EVENTPARM(message) + 3) & ~3) );
|
|
||||||
|
|
||||||
// Did we use up this buffer?
|
|
||||||
if (position >= events->dwBytesRecorded)
|
|
||||||
{
|
|
||||||
events = events->lpNext;
|
|
||||||
position = 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (nullptr == events)
|
|
||||||
{
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
bool AudioToolboxMIDIDevice::Pause(bool paused)
|
|
||||||
{
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
static MusicTimeStamp GetSequenceLength(MusicSequence sequence)
|
|
||||||
{
|
|
||||||
UInt32 trackCount;
|
|
||||||
AT_MIDI_CHECK_ERROR(MusicSequenceGetTrackCount(sequence, &trackCount), 0);
|
|
||||||
|
|
||||||
MusicTimeStamp result = 0;
|
|
||||||
|
|
||||||
for (UInt32 i = 0; i < trackCount; ++i)
|
|
||||||
{
|
|
||||||
MusicTrack track;
|
|
||||||
AT_MIDI_CHECK_ERROR(MusicSequenceGetIndTrack(sequence, i, &track), 0);
|
|
||||||
|
|
||||||
MusicTimeStamp trackLength = 0;
|
|
||||||
UInt32 trackLengthSize = sizeof trackLength;
|
|
||||||
|
|
||||||
AT_MIDI_CHECK_ERROR(MusicTrackGetProperty(track, kSequenceTrackProperty_TrackLength, &trackLength, &trackLengthSize), 0);
|
|
||||||
|
|
||||||
if (result < trackLength)
|
|
||||||
{
|
|
||||||
result = trackLength;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
return result;
|
|
||||||
}
|
|
||||||
|
|
||||||
bool AudioToolboxMIDIDevice::Preprocess(MIDIStreamer* song, bool looping)
|
|
||||||
{
|
|
||||||
assert(nullptr != song);
|
|
||||||
|
|
||||||
TArray<uint8_t> midi;
|
|
||||||
song->CreateSMF(midi, looping ? 0 : 1);
|
|
||||||
|
|
||||||
CFDataRef data = CFDataCreateWithBytesNoCopy(kCFAllocatorDefault, &midi[0], midi.Size(), kCFAllocatorNull);
|
|
||||||
if (nullptr == data)
|
|
||||||
{
|
|
||||||
DPrintf(DMSG_ERROR, "Failed with create CFDataRef for MIDI song");
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
#if MAC_OS_X_VERSION_MAX_ALLOWED < 1050
|
|
||||||
AT_MIDI_CHECK_ERROR(MusicSequenceLoadSMFDataWithFlags(m_sequence, data, 0), false);
|
|
||||||
#else // 10.5 and above
|
|
||||||
AT_MIDI_CHECK_ERROR(MusicSequenceFileLoadData(m_sequence, data, kMusicSequenceFile_MIDIType, 0), CFRelease(data), false);
|
|
||||||
#endif // prior to 10.5
|
|
||||||
|
|
||||||
CFRelease(data);
|
|
||||||
|
|
||||||
m_length = GetSequenceLength(m_sequence);
|
|
||||||
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
|
|
||||||
void AudioToolboxMIDIDevice::TimerCallback(CFRunLoopTimerRef timer, void* info)
|
|
||||||
{
|
|
||||||
AudioToolboxMIDIDevice* const self = static_cast<AudioToolboxMIDIDevice*>(info);
|
|
||||||
|
|
||||||
if (nullptr != self->m_callback)
|
|
||||||
{
|
|
||||||
self->m_callback(self->m_userData);
|
|
||||||
}
|
|
||||||
|
|
||||||
MusicTimeStamp currentTime = 0;
|
|
||||||
AT_MIDI_CHECK_ERROR(MusicPlayerGetTime(self->m_player, ¤tTime));
|
|
||||||
|
|
||||||
if (currentTime > self->m_length)
|
|
||||||
{
|
|
||||||
MusicPlayerSetTime(self->m_player, 0);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
#undef AT_MIDI_CHECK_ERROR
|
|
||||||
|
|
||||||
MIDIDevice *CreateAudioToolboxMIDIDevice()
|
|
||||||
{
|
|
||||||
return new AudioToolboxMIDIDevice();
|
|
||||||
}
|
|
||||||
|
|
||||||
#endif // __APPLE__
|
|
|
@ -43,6 +43,7 @@
|
||||||
#include "m_swap.h"
|
#include "m_swap.h"
|
||||||
#include "w_wad.h"
|
#include "w_wad.h"
|
||||||
#include "v_text.h"
|
#include "v_text.h"
|
||||||
|
#include "version.h"
|
||||||
#include "cmdlib.h"
|
#include "cmdlib.h"
|
||||||
|
|
||||||
// MACROS ------------------------------------------------------------------
|
// MACROS ------------------------------------------------------------------
|
||||||
|
@ -91,6 +92,8 @@ extern "C" unsigned __stdcall GetSystemDirectoryA(char *lpBuffer, unsigned uSize
|
||||||
|
|
||||||
// EXTERNAL FUNCTION PROTOTYPES --------------------------------------------
|
// EXTERNAL FUNCTION PROTOTYPES --------------------------------------------
|
||||||
|
|
||||||
|
const char *BaseFileSearch(const char *file, const char *ext, bool lookfirstinprogdir = false);
|
||||||
|
|
||||||
// PUBLIC FUNCTION PROTOTYPES ----------------------------------------------
|
// PUBLIC FUNCTION PROTOTYPES ----------------------------------------------
|
||||||
|
|
||||||
// PRIVATE FUNCTION PROTOTYPES ---------------------------------------------
|
// PRIVATE FUNCTION PROTOTYPES ---------------------------------------------
|
||||||
|
@ -315,44 +318,54 @@ FluidSynthMIDIDevice::FluidSynthMIDIDevice(const char *args)
|
||||||
int res = 0;
|
int res = 0;
|
||||||
if (args != NULL && *args != 0)
|
if (args != NULL && *args != 0)
|
||||||
{
|
{
|
||||||
res = LoadPatchSets(args);
|
if (LoadPatchSets(args)) return;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (res == 0 && 0 == LoadPatchSets(fluid_patchset))
|
if (LoadPatchSets(fluid_patchset))
|
||||||
{
|
{
|
||||||
#ifdef __unix__
|
return;
|
||||||
// This is the standard location on Ubuntu.
|
|
||||||
if (0 == LoadPatchSets("/usr/share/sounds/sf2/FluidR3_GS.sf2:/usr/share/sounds/sf2/FluidR3_GM.sf2"))
|
|
||||||
{
|
|
||||||
#endif
|
|
||||||
#ifdef _WIN32
|
|
||||||
// On Windows, look for the 4 megabyte patch set installed by Creative's drivers as a default.
|
|
||||||
char sysdir[MAX_PATH+sizeof("\\CT4MGM.SF2")];
|
|
||||||
uint32_t filepart;
|
|
||||||
if (0 != (filepart = GetSystemDirectoryA(sysdir, MAX_PATH)))
|
|
||||||
{
|
|
||||||
strcat(sysdir, "\\CT4MGM.SF2");
|
|
||||||
if (0 == LoadPatchSets(sysdir))
|
|
||||||
{
|
|
||||||
// Try again with CT2MGM.SF2
|
|
||||||
sysdir[filepart + 3] = '2';
|
|
||||||
if (0 == LoadPatchSets(sysdir))
|
|
||||||
{
|
|
||||||
#endif
|
|
||||||
Printf("Failed to load any MIDI patches.\n");
|
|
||||||
delete_fluid_synth(FluidSynth);
|
|
||||||
FluidSynth = NULL;
|
|
||||||
#ifdef _WIN32
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
#endif
|
|
||||||
#ifdef __unix__
|
|
||||||
}
|
|
||||||
#endif
|
|
||||||
}
|
}
|
||||||
|
#ifdef __unix__
|
||||||
|
// This is the standard location on Ubuntu.
|
||||||
|
if (LoadPatchSets("/usr/share/sounds/sf2/FluidR3_GS.sf2:/usr/share/sounds/sf2/FluidR3_GM.sf2"))
|
||||||
|
{
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
#ifdef _WIN32
|
||||||
|
// On Windows, look for the 4 megabyte patch set installed by Creative's drivers as a default.
|
||||||
|
char sysdir[MAX_PATH + sizeof("\\CT4MGM.SF2")];
|
||||||
|
uint32_t filepart;
|
||||||
|
if (0 != (filepart = GetSystemDirectoryA(sysdir, MAX_PATH)))
|
||||||
|
{
|
||||||
|
strcat(sysdir, "\\CT4MGM.SF2");
|
||||||
|
if (LoadPatchSets(sysdir))
|
||||||
|
{
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
// Try again with CT2MGM.SF2
|
||||||
|
sysdir[filepart + 3] = '2';
|
||||||
|
if (LoadPatchSets(sysdir))
|
||||||
|
{
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
#endif
|
||||||
|
// Last try the base sound font which should be provided by the GZDoom binary package.
|
||||||
|
auto wad = BaseFileSearch(BASESF, NULL, true);
|
||||||
|
if (wad != NULL && LoadPatchSets(wad))
|
||||||
|
{
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
Printf("Failed to load any MIDI patches.\n");
|
||||||
|
delete_fluid_synth(FluidSynth);
|
||||||
|
FluidSynth = NULL;
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
//==========================================================================
|
//==========================================================================
|
||||||
//
|
//
|
||||||
// FluidSynthMIDIDevice Destructor
|
// FluidSynthMIDIDevice Destructor
|
||||||
|
@ -513,14 +526,21 @@ int FluidSynthMIDIDevice::LoadPatchSets(const char *patches)
|
||||||
{
|
{
|
||||||
path = NicePath(tok);
|
path = NicePath(tok);
|
||||||
}
|
}
|
||||||
if (FLUID_FAILED != fluid_synth_sfload(FluidSynth, path, count == 0))
|
if (FileExists(path))
|
||||||
{
|
{
|
||||||
DPrintf(DMSG_NOTIFY, "Loaded patch set %s.\n", tok);
|
if (FLUID_FAILED != fluid_synth_sfload(FluidSynth, path, count == 0))
|
||||||
count++;
|
{
|
||||||
|
DPrintf(DMSG_NOTIFY, "Loaded patch set %s.\n", tok);
|
||||||
|
count++;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
DPrintf(DMSG_ERROR, "Failed to load patch set %s.\n", tok);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
DPrintf(DMSG_ERROR, "Failed to load patch set %s.\n", tok);
|
DPrintf(DMSG_ERROR, "Could not find patch set %s.\n", tok);
|
||||||
}
|
}
|
||||||
tok = strtok(NULL, delim);
|
tok = strtok(NULL, delim);
|
||||||
}
|
}
|
||||||
|
|
|
@ -51,9 +51,9 @@ static uint32_t nummididevices;
|
||||||
static bool nummididevicesset;
|
static bool nummididevicesset;
|
||||||
|
|
||||||
#ifdef HAVE_FLUIDSYNTH
|
#ifdef HAVE_FLUIDSYNTH
|
||||||
#define NUM_DEF_DEVICES 6
|
|
||||||
#else
|
|
||||||
#define NUM_DEF_DEVICES 5
|
#define NUM_DEF_DEVICES 5
|
||||||
|
#else
|
||||||
|
#define NUM_DEF_DEVICES 4
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
static void AddDefaultMidiDevices(FOptionValues *opt)
|
static void AddDefaultMidiDevices(FOptionValues *opt)
|
||||||
|
@ -75,8 +75,6 @@ static void AddDefaultMidiDevices(FOptionValues *opt)
|
||||||
pair[p+2].Value = -2.0;
|
pair[p+2].Value = -2.0;
|
||||||
pair[p+3].Text = "WildMidi";
|
pair[p+3].Text = "WildMidi";
|
||||||
pair[p+3].Value = -6.0;
|
pair[p+3].Value = -6.0;
|
||||||
pair[p+4].Text = "Sound System";
|
|
||||||
pair[p+4].Value = -1.0;
|
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -117,10 +115,16 @@ void MIDIDeviceChanged(int newdev, bool force)
|
||||||
if (!force) oldmididev = newdev;
|
if (!force) oldmididev = newdev;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#ifdef HAVE_FLUIDSYNTH
|
||||||
|
#define DEF_MIDIDEV -5
|
||||||
|
#else
|
||||||
|
#define DEF_MIDIDEV -3
|
||||||
|
#endif
|
||||||
|
|
||||||
#ifdef _WIN32
|
#ifdef _WIN32
|
||||||
unsigned mididevice;
|
unsigned mididevice;
|
||||||
|
|
||||||
CUSTOM_CVAR (Int, snd_mididevice, -1, CVAR_ARCHIVE|CVAR_GLOBALCONFIG)
|
CUSTOM_CVAR (Int, snd_mididevice, DEF_MIDIDEV, CVAR_ARCHIVE|CVAR_GLOBALCONFIG)
|
||||||
{
|
{
|
||||||
if (!nummididevicesset)
|
if (!nummididevicesset)
|
||||||
return;
|
return;
|
||||||
|
@ -131,10 +135,11 @@ CUSTOM_CVAR (Int, snd_mididevice, -1, CVAR_ARCHIVE|CVAR_GLOBALCONFIG)
|
||||||
if (self != 0)
|
if (self != 0)
|
||||||
{
|
{
|
||||||
Printf("ID out of range. Using default device.\n");
|
Printf("ID out of range. Using default device.\n");
|
||||||
self = 0;
|
self = DEF_MIDIDEV;
|
||||||
}
|
}
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
else if (self == -1) self = DEF_MIDIDEV;
|
||||||
mididevice = MAX<UINT>(0, self);
|
mididevice = MAX<UINT>(0, self);
|
||||||
MIDIDeviceChanged(self);
|
MIDIDeviceChanged(self);
|
||||||
}
|
}
|
||||||
|
@ -215,7 +220,6 @@ CCMD (snd_listmididevices)
|
||||||
PrintMidiDevice (-4, "Gravis Ultrasound Emulation", MIDIDEV_SWSYNTH, 0);
|
PrintMidiDevice (-4, "Gravis Ultrasound Emulation", MIDIDEV_SWSYNTH, 0);
|
||||||
PrintMidiDevice (-3, "Emulated OPL FM Synth", MIDIDEV_FMSYNTH, 0);
|
PrintMidiDevice (-3, "Emulated OPL FM Synth", MIDIDEV_FMSYNTH, 0);
|
||||||
PrintMidiDevice (-2, "TiMidity++", MIDIDEV_SWSYNTH, 0);
|
PrintMidiDevice (-2, "TiMidity++", MIDIDEV_SWSYNTH, 0);
|
||||||
PrintMidiDevice (-1, "Sound System", 0, 0);
|
|
||||||
if (nummididevices != 0)
|
if (nummididevices != 0)
|
||||||
{
|
{
|
||||||
for (id = 0; id < nummididevices; ++id)
|
for (id = 0; id < nummididevices; ++id)
|
||||||
|
@ -237,12 +241,12 @@ CCMD (snd_listmididevices)
|
||||||
|
|
||||||
// Everything but Windows uses this code.
|
// Everything but Windows uses this code.
|
||||||
|
|
||||||
CUSTOM_CVAR(Int, snd_mididevice, -1, CVAR_ARCHIVE|CVAR_GLOBALCONFIG)
|
CUSTOM_CVAR(Int, snd_mididevice, DEF_MIDIDEV, CVAR_ARCHIVE|CVAR_GLOBALCONFIG)
|
||||||
{
|
{
|
||||||
if (self < -6)
|
if (self < -6)
|
||||||
self = -6;
|
self = -6;
|
||||||
else if (self > -1)
|
else if (self > -2)
|
||||||
self = -1;
|
self = -2;
|
||||||
else
|
else
|
||||||
MIDIDeviceChanged(self);
|
MIDIDeviceChanged(self);
|
||||||
}
|
}
|
||||||
|
@ -261,6 +265,5 @@ CCMD (snd_listmididevices)
|
||||||
Printf("%s-4. Gravis Ultrasound Emulation\n", -4 == snd_mididevice ? TEXTCOLOR_BOLD : "");
|
Printf("%s-4. Gravis Ultrasound Emulation\n", -4 == snd_mididevice ? TEXTCOLOR_BOLD : "");
|
||||||
Printf("%s-3. Emulated OPL FM Synth\n", -3 == snd_mididevice ? TEXTCOLOR_BOLD : "");
|
Printf("%s-3. Emulated OPL FM Synth\n", -3 == snd_mididevice ? TEXTCOLOR_BOLD : "");
|
||||||
Printf("%s-2. TiMidity++\n", -2 == snd_mididevice ? TEXTCOLOR_BOLD : "");
|
Printf("%s-2. TiMidity++\n", -2 == snd_mididevice ? TEXTCOLOR_BOLD : "");
|
||||||
Printf("%s-1. Sound System\n", -1 == snd_mididevice ? TEXTCOLOR_BOLD : "");
|
|
||||||
}
|
}
|
||||||
#endif
|
#endif
|
||||||
|
|
|
@ -651,7 +651,7 @@ uint32_t *HMISong::SendCommand (uint32_t *events, TrackInfo *track, uint32_t del
|
||||||
if (event == MIDI_SYSEX || event == MIDI_SYSEXEND)
|
if (event == MIDI_SYSEX || event == MIDI_SYSEXEND)
|
||||||
{
|
{
|
||||||
len = ReadVarLen(track);
|
len = ReadVarLen(track);
|
||||||
if (len >= (MAX_EVENTS-1)*3*4 || DeviceType == MDEV_SNDSYS)
|
if (len >= (MAX_EVENTS-1)*3*4)
|
||||||
{ // This message will never fit. Throw it away.
|
{ // This message will never fit. Throw it away.
|
||||||
track->TrackP += len;
|
track->TrackP += len;
|
||||||
}
|
}
|
||||||
|
|
|
@ -181,11 +181,6 @@ EMidiDevice MIDIStreamer::SelectMIDIDevice(EMidiDevice device)
|
||||||
- if explicitly selected by $mididevice
|
- if explicitly selected by $mididevice
|
||||||
- when snd_mididevice is -2 and no midi device is set for the song
|
- when snd_mididevice is -2 and no midi device is set for the song
|
||||||
|
|
||||||
- Sound System:
|
|
||||||
- if explicitly selected by $mididevice
|
|
||||||
- when snd_mididevice is -1 and no midi device is set for the song
|
|
||||||
- as fallback when both OPL and Timidity failed unless snd_mididevice is >= 0
|
|
||||||
|
|
||||||
- MMAPI (Win32 only):
|
- MMAPI (Win32 only):
|
||||||
- if explicitly selected by $mididevice (non-Win32 redirects this to Sound System)
|
- if explicitly selected by $mididevice (non-Win32 redirects this to Sound System)
|
||||||
- when snd_mididevice is >= 0 and no midi device is set for the song
|
- when snd_mididevice is >= 0 and no midi device is set for the song
|
||||||
|
@ -233,16 +228,19 @@ MIDIDevice *MIDIStreamer::CreateMIDIDevice(EMidiDevice devtype)
|
||||||
assert(0);
|
assert(0);
|
||||||
// Intentional fall-through for non-Windows systems.
|
// Intentional fall-through for non-Windows systems.
|
||||||
|
|
||||||
|
case MDEV_GUS:
|
||||||
|
return new TimidityMIDIDevice(Args);
|
||||||
|
|
||||||
#ifdef HAVE_FLUIDSYNTH
|
#ifdef HAVE_FLUIDSYNTH
|
||||||
case MDEV_FLUIDSYNTH:
|
case MDEV_FLUIDSYNTH:
|
||||||
return new FluidSynthMIDIDevice(Args);
|
return new FluidSynthMIDIDevice(Args);
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
case MDEV_SNDSYS:
|
case MDEV_SNDSYS:
|
||||||
return GSnd->CreateMIDIDevice();
|
#ifdef HAVE_FLUIDSYNTH
|
||||||
|
return new FluidSynthMIDIDevice(nullptr);
|
||||||
case MDEV_GUS:
|
#endif
|
||||||
return new TimidityMIDIDevice(Args);
|
// if no FluidSynth, fall through to OPL.
|
||||||
|
|
||||||
case MDEV_OPL:
|
case MDEV_OPL:
|
||||||
try
|
try
|
||||||
|
@ -252,8 +250,13 @@ MIDIDevice *MIDIStreamer::CreateMIDIDevice(EMidiDevice devtype)
|
||||||
catch (CRecoverableError &err)
|
catch (CRecoverableError &err)
|
||||||
{
|
{
|
||||||
// The creation of an OPL MIDI device can abort with an error if no GENMIDI lump can be found.
|
// The creation of an OPL MIDI device can abort with an error if no GENMIDI lump can be found.
|
||||||
Printf("Unable to create OPL MIDI device: %s\nFalling back to Sound System playback", err.GetMessage());
|
Printf("Unable to create OPL MIDI device: %s\nFalling back to default playback", err.GetMessage());
|
||||||
return GSnd->CreateMIDIDevice();
|
#ifdef HAVE_FLUIDSYNTH
|
||||||
|
return new FluidSynthMIDIDevice(nullptr);
|
||||||
|
#else
|
||||||
|
// Someone dared to compile GZDoom without FluidSynth support and then started an IWAD without GENMIDI support. Ugh...
|
||||||
|
return nullptr;
|
||||||
|
#endif
|
||||||
}
|
}
|
||||||
|
|
||||||
case MDEV_TIMIDITY:
|
case MDEV_TIMIDITY:
|
||||||
|
|
|
@ -592,7 +592,7 @@ uint32_t *MIDISong2::SendCommand (uint32_t *events, TrackInfo *track, uint32_t d
|
||||||
if (event == MIDI_SYSEX || event == MIDI_SYSEXEND)
|
if (event == MIDI_SYSEX || event == MIDI_SYSEXEND)
|
||||||
{
|
{
|
||||||
len = track->ReadVarLen();
|
len = track->ReadVarLen();
|
||||||
if (len >= (MAX_EVENTS-1)*3*4 || DeviceType == MDEV_SNDSYS)
|
if (len >= (MAX_EVENTS-1)*3*4)
|
||||||
{ // This message will never fit. Throw it away.
|
{ // This message will never fit. Throw it away.
|
||||||
track->TrackP += len;
|
track->TrackP += len;
|
||||||
}
|
}
|
||||||
|
|
|
@ -522,7 +522,7 @@ uint32_t *XMISong::SendCommand (uint32_t *events, EventSource due, uint32_t dela
|
||||||
if (event == MIDI_SYSEX || event == MIDI_SYSEXEND)
|
if (event == MIDI_SYSEX || event == MIDI_SYSEXEND)
|
||||||
{
|
{
|
||||||
len = track->ReadVarLen();
|
len = track->ReadVarLen();
|
||||||
if (len >= (MAX_EVENTS-1)*3*4 || DeviceType == MDEV_SNDSYS)
|
if (len >= (MAX_EVENTS-1)*3*4)
|
||||||
{ // This message will never fit. Throw it away.
|
{ // This message will never fit. Throw it away.
|
||||||
track->EventP += len;
|
track->EventP += len;
|
||||||
}
|
}
|
||||||
|
|
|
@ -2320,18 +2320,6 @@ void OpenALSoundRenderer::PrintDriversList()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
MIDIDevice* OpenALSoundRenderer::CreateMIDIDevice() const
|
|
||||||
{
|
|
||||||
#ifdef _WIN32
|
|
||||||
extern unsigned mididevice;
|
|
||||||
return CreateWinMIDIDevice(mididevice);
|
|
||||||
#elif defined __APPLE__
|
|
||||||
return CreateAudioToolboxMIDIDevice();
|
|
||||||
#else
|
|
||||||
return new OPLMIDIDevice(nullptr);
|
|
||||||
#endif
|
|
||||||
}
|
|
||||||
|
|
||||||
void OpenALSoundRenderer::PurgeStoppedSources()
|
void OpenALSoundRenderer::PurgeStoppedSources()
|
||||||
{
|
{
|
||||||
// Release channels that are stopped
|
// Release channels that are stopped
|
||||||
|
|
|
@ -175,8 +175,6 @@ public:
|
||||||
virtual void PrintDriversList();
|
virtual void PrintDriversList();
|
||||||
virtual FString GatherStats();
|
virtual FString GatherStats();
|
||||||
|
|
||||||
virtual MIDIDevice* CreateMIDIDevice() const override;
|
|
||||||
|
|
||||||
private:
|
private:
|
||||||
struct {
|
struct {
|
||||||
bool EXT_EFX;
|
bool EXT_EFX;
|
||||||
|
|
|
@ -1747,6 +1747,32 @@ bool AspectTallerThanWide(float aspect)
|
||||||
return aspect < 1.333f;
|
return aspect < 1.333f;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void ScaleWithAspect (int &w, int &h, int Width, int Height)
|
||||||
|
{
|
||||||
|
int resRatio = CheckRatio (Width, Height);
|
||||||
|
int screenRatio;
|
||||||
|
CheckRatio (w, h, &screenRatio);
|
||||||
|
if (resRatio == screenRatio)
|
||||||
|
return;
|
||||||
|
|
||||||
|
double yratio;
|
||||||
|
switch(resRatio)
|
||||||
|
{
|
||||||
|
case 0: yratio = 4./3.; break;
|
||||||
|
case 1: yratio = 16./9.; break;
|
||||||
|
case 2: yratio = 16./10.; break;
|
||||||
|
case 3: yratio = 17./10.; break;
|
||||||
|
case 4: yratio = 5./4.; break;
|
||||||
|
case 6: yratio = 21./9.; break;
|
||||||
|
default: return;
|
||||||
|
}
|
||||||
|
double y = w/yratio;
|
||||||
|
if (y > h)
|
||||||
|
w = h*yratio;
|
||||||
|
else
|
||||||
|
h = y;
|
||||||
|
}
|
||||||
|
|
||||||
void IVideo::DumpAdapters ()
|
void IVideo::DumpAdapters ()
|
||||||
{
|
{
|
||||||
Printf("Multi-monitor support unavailable.\n");
|
Printf("Multi-monitor support unavailable.\n");
|
||||||
|
|
|
@ -565,6 +565,8 @@ int AspectBaseHeight(float aspect);
|
||||||
double AspectPspriteOffset(float aspect);
|
double AspectPspriteOffset(float aspect);
|
||||||
int AspectMultiplier(float aspect);
|
int AspectMultiplier(float aspect);
|
||||||
bool AspectTallerThanWide(float aspect);
|
bool AspectTallerThanWide(float aspect);
|
||||||
|
void ScaleWithAspect(int &w, int &h, int Width, int Height);
|
||||||
|
|
||||||
int GetUIScale(int altval);
|
int GetUIScale(int altval);
|
||||||
|
|
||||||
EXTERN_CVAR(Int, uiscale);
|
EXTERN_CVAR(Int, uiscale);
|
||||||
|
|
|
@ -96,6 +96,7 @@ const char *GetVersionString();
|
||||||
// This is so that derivates can use the same savegame versions without worrying about engine compatibility
|
// This is so that derivates can use the same savegame versions without worrying about engine compatibility
|
||||||
#define GAMESIG "QZDOOM"
|
#define GAMESIG "QZDOOM"
|
||||||
#define BASEWAD "qzdoom.pk3"
|
#define BASEWAD "qzdoom.pk3"
|
||||||
|
#define BASESF "gzdoom.sf2"
|
||||||
|
|
||||||
// More stuff that needs to be different for derivatives.
|
// More stuff that needs to be different for derivatives.
|
||||||
#define GAMENAME "QZDoom"
|
#define GAMENAME "QZDoom"
|
||||||
|
|
|
@ -51,7 +51,7 @@ int main(int argc, char **argv)
|
||||||
// on a tag, it returns that tag. Otherwise it returns <most recent tag>-<number of
|
// on a tag, it returns that tag. Otherwise it returns <most recent tag>-<number of
|
||||||
// commits since the tag>-<short hash>.
|
// commits since the tag>-<short hash>.
|
||||||
// Use git log to get the time of the latest commit in ISO 8601 format and its full hash.
|
// Use git log to get the time of the latest commit in ISO 8601 format and its full hash.
|
||||||
stream = popen("git describe --tags && git log -1 --format=%ai*%H", "r");
|
stream = popen("git describe --tags --dirty=-m && git log -1 --format=%ai*%H", "r");
|
||||||
|
|
||||||
if (NULL != stream)
|
if (NULL != stream)
|
||||||
{
|
{
|
||||||
|
|
Loading…
Reference in a new issue