Merge remote-tracking branch 'gzdoom/master' into materials

This commit is contained in:
Magnus Norddahl 2018-02-20 00:22:06 +01:00
commit 4e7ca68bd6
20 changed files with 206 additions and 144 deletions

View file

@ -391,6 +391,12 @@ if( ZD_CMAKE_COMPILER_IS_GNUCXX_COMPATIBLE )
set( CMAKE_CXX_FLAGS "-Wno-unknown-pragmas -Wno-comment -Wno-format ${CMAKE_CXX_FLAGS}" ) set( CMAKE_CXX_FLAGS "-Wno-unknown-pragmas -Wno-comment -Wno-format ${CMAKE_CXX_FLAGS}" )
endif() endif()
# Detect FreeBSD and add flags
if(${CMAKE_SYSTEM_NAME} MATCHES "FreeBSD")
set( CMAKE_C_FLAGS "${CMAKE_C_FLAGS} -fPIC" )
set( CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -fPIC" )
endif()
if( NOT NO_STRIP ) if( NOT NO_STRIP )
set (CMAKE_EXE_LINKER_FLAGS_RELEASE "${CMAKE_EXE_LINKER_FLAGS_RELEASE} -s" ) set (CMAKE_EXE_LINKER_FLAGS_RELEASE "${CMAKE_EXE_LINKER_FLAGS_RELEASE} -s" )
set (CMAKE_EXE_LINKER_FLAGS_MINSIZEREL "${CMAKE_EXE_LINKER_FLAGS_MINSIZEREL} -s" ) set (CMAKE_EXE_LINKER_FLAGS_MINSIZEREL "${CMAKE_EXE_LINKER_FLAGS_MINSIZEREL} -s" )

View file

@ -231,7 +231,7 @@ bool AWeapon::CheckAmmo(int fireMode, bool autoSwitch, bool requireAmmo, int amm
VMCall(func, params, 5, &ret, 1); VMCall(func, params, 5, &ret, 1);
return !!retval; return !!retval;
} }
return CheckAmmo(fireMode, autoSwitch, requireAmmo, ammocount); return DoCheckAmmo(fireMode, autoSwitch, requireAmmo, ammocount);
} }
bool AWeapon::DoCheckAmmo (int fireMode, bool autoSwitch, bool requireAmmo, int ammocount) bool AWeapon::DoCheckAmmo (int fireMode, bool autoSwitch, bool requireAmmo, int ammocount)

View file

@ -459,8 +459,8 @@ bool gl_SetupLight(int group, Plane & p, ADynamicLight * light, FVector3 & nearP
bool gl_SetupLightTexture() bool gl_SetupLightTexture()
{ {
if (GLRenderer->gllight == nullptr) return false; if (!GLRenderer->glLight.isValid()) return false;
FMaterial * pat = FMaterial::ValidateTexture(GLRenderer->gllight, false); FMaterial * pat = FMaterial::ValidateTexture(GLRenderer->glLight, false, false);
gl_RenderState.SetMaterial(pat, CLAMP_XY_NOMIP, 0, -1, false); gl_RenderState.SetMaterial(pat, CLAMP_XY_NOMIP, 0, -1, false);
return true; return true;
} }

View file

@ -104,7 +104,6 @@ FGLRenderer::FGLRenderer(OpenGLFrameBuffer *fb)
mSkyVBO = nullptr; mSkyVBO = nullptr;
gl_spriteindex = 0; gl_spriteindex = 0;
mShaderManager = nullptr; mShaderManager = nullptr;
gllight = glpart2 = glpart = mirrortexture = nullptr;
mLights = nullptr; mLights = nullptr;
m2DDrawer = nullptr; m2DDrawer = nullptr;
mTonemapPalette = nullptr; mTonemapPalette = nullptr;
@ -163,6 +162,8 @@ void FGLRenderer::Initialize(int width, int height)
mCustomPostProcessShaders = new FCustomPostProcessShaders(); mCustomPostProcessShaders = new FCustomPostProcessShaders();
m2DDrawer = new F2DDrawer; m2DDrawer = new F2DDrawer;
GetSpecialTextures();
// needed for the core profile, because someone decided it was a good idea to remove the default VAO. // needed for the core profile, because someone decided it was a good idea to remove the default VAO.
if (!gl.legacyMode) if (!gl.legacyMode)
{ {
@ -172,11 +173,6 @@ void FGLRenderer::Initialize(int width, int height)
} }
else mVAOID = 0; else mVAOID = 0;
if (gl.legacyMode) gllight = FTexture::CreateTexture(Wads.GetNumForFullName("glstuff/gllight.png"), FTexture::TEX_MiscPatch);
glpart2 = FTexture::CreateTexture(Wads.GetNumForFullName("glstuff/glpart2.png"), FTexture::TEX_MiscPatch);
glpart = FTexture::CreateTexture(Wads.GetNumForFullName("glstuff/glpart.png"), FTexture::TEX_MiscPatch);
mirrortexture = FTexture::CreateTexture(Wads.GetNumForFullName("glstuff/mirror.png"), FTexture::TEX_MiscPatch);
mVBO = new FFlatVertexBuffer(width, height); mVBO = new FFlatVertexBuffer(width, height);
mSkyVBO = new FSkyVertexBuffer; mSkyVBO = new FSkyVertexBuffer;
if (!gl.legacyMode) mLights = new FLightBuffer(); if (!gl.legacyMode) mLights = new FLightBuffer();
@ -206,10 +202,6 @@ FGLRenderer::~FGLRenderer()
if (mVBO != NULL) delete mVBO; if (mVBO != NULL) delete mVBO;
if (mSkyVBO != NULL) delete mSkyVBO; if (mSkyVBO != NULL) delete mSkyVBO;
if (mLights != NULL) delete mLights; if (mLights != NULL) delete mLights;
if (glpart2) delete glpart2;
if (glpart) delete glpart;
if (gllight) delete gllight;
if (mirrortexture) delete mirrortexture;
if (mFBID != 0) glDeleteFramebuffers(1, &mFBID); if (mFBID != 0) glDeleteFramebuffers(1, &mFBID);
if (mVAOID != 0) if (mVAOID != 0)
{ {
@ -241,6 +233,16 @@ FGLRenderer::~FGLRenderer()
delete mFXAALumaShader; delete mFXAALumaShader;
} }
void FGLRenderer::GetSpecialTextures()
{
if (gl.legacyMode) glLight = TexMan.CheckForTexture("glstuff/gllight.png", FTexture::TEX_MiscPatch);
glPart2 = TexMan.CheckForTexture("glstuff/glpart2.png", FTexture::TEX_MiscPatch);
glPart = TexMan.CheckForTexture("glstuff/glpart.png", FTexture::TEX_MiscPatch);
mirrorTexture = TexMan.CheckForTexture("glstuff/mirror.png", FTexture::TEX_MiscPatch);
}
//========================================================================== //==========================================================================
// //
// Calculates the viewport values needed for 2D and 3D operations // Calculates the viewport values needed for 2D and 3D operations

View file

@ -133,10 +133,10 @@ public:
FShadowMap mShadowMap; FShadowMap mShadowMap;
FTexture *gllight; FTextureID glLight;
FTexture *glpart2; FTextureID glPart2;
FTexture *glpart; FTextureID glPart;
FTexture *mirrortexture; FTextureID mirrorTexture;
float mSky1Pos, mSky2Pos; float mSky1Pos, mSky2Pos;
@ -190,6 +190,7 @@ public:
void CopyToBackbuffer(const GL_IRECT *bounds, bool applyGamma); void CopyToBackbuffer(const GL_IRECT *bounds, bool applyGamma);
void DrawPresentTexture(const GL_IRECT &box, bool applyGamma); void DrawPresentTexture(const GL_IRECT &box, bool applyGamma);
void Flush(); void Flush();
void GetSpecialTextures();
bool StartOffscreen(); bool StartOffscreen();

View file

@ -1185,19 +1185,20 @@ void GLSprite::ProcessParticle (particle_t *particle, sector_t *sector)//, int s
// [BB] Load the texture for round or smooth particles // [BB] Load the texture for round or smooth particles
if (gl_particles_style) if (gl_particles_style)
{ {
FTexture *lump = NULL; FTextureID lump;
if (gl_particles_style == 1) if (gl_particles_style == 1)
{ {
lump = GLRenderer->glpart2; lump = GLRenderer->glPart2;
} }
else if (gl_particles_style == 2) else if (gl_particles_style == 2)
{ {
lump = GLRenderer->glpart; lump = GLRenderer->glPart;
} }
else lump.SetNull();
if (lump != NULL) if (lump.isValid())
{ {
gltexture = FMaterial::ValidateTexture(lump, true); gltexture = FMaterial::ValidateTexture(lump, true, false);
translation = 0; translation = 0;
ul = gltexture->GetUL(); ul = gltexture->GetUL();

View file

@ -260,7 +260,7 @@ void GLWall::RenderFogBoundary()
//========================================================================== //==========================================================================
void GLWall::RenderMirrorSurface() void GLWall::RenderMirrorSurface()
{ {
if (GLRenderer->mirrortexture == NULL) return; if (!GLRenderer->mirrorTexture.isValid()) return;
// For the sphere map effect we need a normal of the mirror surface, // For the sphere map effect we need a normal of the mirror surface,
FVector3 v = glseg.Normal(); FVector3 v = glseg.Normal();
@ -288,7 +288,7 @@ void GLWall::RenderMirrorSurface()
gl_RenderState.AlphaFunc(GL_GREATER,0); gl_RenderState.AlphaFunc(GL_GREATER,0);
glDepthFunc(GL_LEQUAL); glDepthFunc(GL_LEQUAL);
FMaterial * pat=FMaterial::ValidateTexture(GLRenderer->mirrortexture, false); FMaterial * pat=FMaterial::ValidateTexture(GLRenderer->mirrorTexture, false, false);
gl_RenderState.SetMaterial(pat, CLAMP_NONE, 0, -1, false); gl_RenderState.SetMaterial(pat, CLAMP_NONE, 0, -1, false);
flags &= ~GLWF_GLOW; flags &= ~GLWF_GLOW;

View file

@ -3,7 +3,6 @@
-- Generation of gl_load.c and gl_load.h files: -- Generation of gl_load.c and gl_load.h files:
-- > lua LoadGen.lua -style=pointer_c -spec=gl -version=3.3 -profile=compatibility -extfile=gl_extlist.txt load -- > lua LoadGen.lua -style=pointer_c -spec=gl -version=3.3 -profile=compatibility -extfile=gl_extlist.txt load
APPLE_client_storage
ARB_buffer_storage ARB_buffer_storage
ARB_shader_storage_buffer_object ARB_shader_storage_buffer_object
ARB_texture_compression ARB_texture_compression
@ -14,4 +13,3 @@ EXT_texture_filter_anisotropic
EXT_texture_sRGB EXT_texture_sRGB
KHR_debug KHR_debug
ARB_invalidate_subdata ARB_invalidate_subdata
EXT_abgr

View file

@ -551,6 +551,7 @@ void OpenGLFrameBuffer::GameRestart()
UpdatePalette (); UpdatePalette ();
ScreenshotBuffer = NULL; ScreenshotBuffer = NULL;
gl_GenerateGlobalBrightmapFromColormap(); gl_GenerateGlobalBrightmapFromColormap();
GLRenderer->GetSpecialTextures();
} }

View file

@ -97,7 +97,6 @@ static PROC WinGetProcAddress(const char *name)
#endif #endif
#endif #endif
int ogl_ext_APPLE_client_storage = ogl_LOAD_FAILED;
int ogl_ext_ARB_buffer_storage = ogl_LOAD_FAILED; int ogl_ext_ARB_buffer_storage = ogl_LOAD_FAILED;
int ogl_ext_ARB_shader_storage_buffer_object = ogl_LOAD_FAILED; int ogl_ext_ARB_shader_storage_buffer_object = ogl_LOAD_FAILED;
int ogl_ext_ARB_texture_compression = ogl_LOAD_FAILED; int ogl_ext_ARB_texture_compression = ogl_LOAD_FAILED;
@ -108,7 +107,6 @@ int ogl_ext_EXT_texture_filter_anisotropic = ogl_LOAD_FAILED;
int ogl_ext_EXT_texture_sRGB = ogl_LOAD_FAILED; int ogl_ext_EXT_texture_sRGB = ogl_LOAD_FAILED;
int ogl_ext_KHR_debug = ogl_LOAD_FAILED; int ogl_ext_KHR_debug = ogl_LOAD_FAILED;
int ogl_ext_ARB_invalidate_subdata = ogl_LOAD_FAILED; int ogl_ext_ARB_invalidate_subdata = ogl_LOAD_FAILED;
int ogl_ext_EXT_abgr = ogl_LOAD_FAILED;
void (CODEGEN_FUNCPTR *_ptrc_glBufferStorage)(GLenum target, GLsizeiptr size, const void * data, GLbitfield flags) = NULL; void (CODEGEN_FUNCPTR *_ptrc_glBufferStorage)(GLenum target, GLsizeiptr size, const void * data, GLbitfield flags) = NULL;
@ -2388,8 +2386,7 @@ typedef struct ogl_StrToExtMap_s
PFN_LOADFUNCPOINTERS LoadExtension; PFN_LOADFUNCPOINTERS LoadExtension;
} ogl_StrToExtMap; } ogl_StrToExtMap;
static ogl_StrToExtMap ExtensionMap[12] = { static ogl_StrToExtMap ExtensionMap[10] = {
{"GL_APPLE_client_storage", &ogl_ext_APPLE_client_storage, NULL},
{"GL_ARB_buffer_storage", &ogl_ext_ARB_buffer_storage, Load_ARB_buffer_storage}, {"GL_ARB_buffer_storage", &ogl_ext_ARB_buffer_storage, Load_ARB_buffer_storage},
{"GL_ARB_shader_storage_buffer_object", &ogl_ext_ARB_shader_storage_buffer_object, Load_ARB_shader_storage_buffer_object}, {"GL_ARB_shader_storage_buffer_object", &ogl_ext_ARB_shader_storage_buffer_object, Load_ARB_shader_storage_buffer_object},
{"GL_ARB_texture_compression", &ogl_ext_ARB_texture_compression, Load_ARB_texture_compression}, {"GL_ARB_texture_compression", &ogl_ext_ARB_texture_compression, Load_ARB_texture_compression},
@ -2400,10 +2397,9 @@ static ogl_StrToExtMap ExtensionMap[12] = {
{"GL_EXT_texture_sRGB", &ogl_ext_EXT_texture_sRGB, NULL}, {"GL_EXT_texture_sRGB", &ogl_ext_EXT_texture_sRGB, NULL},
{"GL_KHR_debug", &ogl_ext_KHR_debug, Load_KHR_debug}, {"GL_KHR_debug", &ogl_ext_KHR_debug, Load_KHR_debug},
{"GL_ARB_invalidate_subdata", &ogl_ext_ARB_invalidate_subdata, Load_ARB_invalidate_subdata}, {"GL_ARB_invalidate_subdata", &ogl_ext_ARB_invalidate_subdata, Load_ARB_invalidate_subdata},
{"GL_EXT_abgr", &ogl_ext_EXT_abgr, NULL},
}; };
static int g_extensionMapSize = 12; static int g_extensionMapSize = 10;
static ogl_StrToExtMap *FindExtEntry(const char *extensionName) static ogl_StrToExtMap *FindExtEntry(const char *extensionName)
{ {
@ -2420,7 +2416,6 @@ static ogl_StrToExtMap *FindExtEntry(const char *extensionName)
static void ClearExtensionVars(void) static void ClearExtensionVars(void)
{ {
ogl_ext_APPLE_client_storage = ogl_LOAD_FAILED;
ogl_ext_ARB_buffer_storage = ogl_LOAD_FAILED; ogl_ext_ARB_buffer_storage = ogl_LOAD_FAILED;
ogl_ext_ARB_shader_storage_buffer_object = ogl_LOAD_FAILED; ogl_ext_ARB_shader_storage_buffer_object = ogl_LOAD_FAILED;
ogl_ext_ARB_texture_compression = ogl_LOAD_FAILED; ogl_ext_ARB_texture_compression = ogl_LOAD_FAILED;
@ -2431,7 +2426,6 @@ static void ClearExtensionVars(void)
ogl_ext_EXT_texture_sRGB = ogl_LOAD_FAILED; ogl_ext_EXT_texture_sRGB = ogl_LOAD_FAILED;
ogl_ext_KHR_debug = ogl_LOAD_FAILED; ogl_ext_KHR_debug = ogl_LOAD_FAILED;
ogl_ext_ARB_invalidate_subdata = ogl_LOAD_FAILED; ogl_ext_ARB_invalidate_subdata = ogl_LOAD_FAILED;
ogl_ext_EXT_abgr = ogl_LOAD_FAILED;
} }

View file

@ -107,7 +107,6 @@ typedef unsigned int GLhandleARB;
extern "C" { extern "C" {
#endif /*__cplusplus*/ #endif /*__cplusplus*/
extern int ogl_ext_APPLE_client_storage;
extern int ogl_ext_ARB_buffer_storage; extern int ogl_ext_ARB_buffer_storage;
extern int ogl_ext_ARB_shader_storage_buffer_object; extern int ogl_ext_ARB_shader_storage_buffer_object;
extern int ogl_ext_ARB_texture_compression; extern int ogl_ext_ARB_texture_compression;
@ -118,9 +117,6 @@ extern int ogl_ext_EXT_texture_filter_anisotropic;
extern int ogl_ext_EXT_texture_sRGB; extern int ogl_ext_EXT_texture_sRGB;
extern int ogl_ext_KHR_debug; extern int ogl_ext_KHR_debug;
extern int ogl_ext_ARB_invalidate_subdata; extern int ogl_ext_ARB_invalidate_subdata;
extern int ogl_ext_EXT_abgr;
#define GL_UNPACK_CLIENT_STORAGE_APPLE 0x85B2
#define GL_BUFFER_IMMUTABLE_STORAGE 0x821F #define GL_BUFFER_IMMUTABLE_STORAGE 0x821F
#define GL_BUFFER_STORAGE_FLAGS 0x8220 #define GL_BUFFER_STORAGE_FLAGS 0x8220
@ -286,8 +282,6 @@ extern int ogl_ext_EXT_abgr;
#define GL_STACK_UNDERFLOW 0x0504 #define GL_STACK_UNDERFLOW 0x0504
#define GL_VERTEX_ARRAY 0x8074 #define GL_VERTEX_ARRAY 0x8074
#define GL_ABGR_EXT 0x8000
#define GL_2D 0x0600 #define GL_2D 0x0600
#define GL_2_BYTES 0x1407 #define GL_2_BYTES 0x1407
#define GL_3D 0x0601 #define GL_3D 0x0601

View file

@ -1284,7 +1284,7 @@ int ACSStringPool::InsertString(FString &str, unsigned int h, unsigned int bucke
} }
if (index == Pool.Size()) if (index == Pool.Size())
{ // There were no free entries; make a new one. { // There were no free entries; make a new one.
Pool.Reserve(1); Pool.Reserve(MIN_GC_SIZE);
FirstFreeEntry++; FirstFreeEntry++;
} }
else else

View file

@ -6380,6 +6380,11 @@ void P_DoCrunch(AActor *thing, FChangePosition *cpos)
mo->Translation = thing->BloodTranslation; mo->Translation = thing->BloodTranslation;
} }
if (mo->flags5 & MF5_PUFFGETSOWNER)
{
mo->target = thing;
}
if (!(cl_bloodtype <= 1)) mo->renderflags |= RF_INVISIBLE; if (!(cl_bloodtype <= 1)) mo->renderflags |= RF_INVISIBLE;
} }

View file

@ -169,10 +169,6 @@ static void I_DetectOS()
"32-bit Intel"; "32-bit Intel";
#elif defined __x86_64__ #elif defined __x86_64__
"64-bit Intel"; "64-bit Intel";
#elif defined __ppc__
"32-bit PowerPC";
#elif defined __ppc64__
"64-bit PowerPC";
#else #else
"Unknown"; "Unknown";
#endif #endif

View file

@ -112,13 +112,7 @@ EXTERN_CVAR(Bool, ticker )
EXTERN_CVAR(Bool, vid_vsync) EXTERN_CVAR(Bool, vid_vsync)
EXTERN_CVAR(Bool, vid_hidpi) EXTERN_CVAR(Bool, vid_hidpi)
#if defined __ppc__ || defined __ppc64__ CUSTOM_CVAR(Bool, swtruecolor, true, CVAR_ARCHIVE | CVAR_GLOBALCONFIG | CVAR_NOINITCALL)
static const bool TRUECOLOR_DEFAULT = false;
#else // other than PowerPC
static const bool TRUECOLOR_DEFAULT = true;
#endif // PowerPC
CUSTOM_CVAR(Bool, swtruecolor, TRUECOLOR_DEFAULT, CVAR_ARCHIVE | CVAR_GLOBALCONFIG | CVAR_NOINITCALL)
{ {
// Strictly speaking this doesn't require a mode switch, but it is the easiest // Strictly speaking this doesn't require a mode switch, but it is the easiest
// way to force a CreateFramebuffer call without a lot of refactoring. // way to force a CreateFramebuffer call without a lot of refactoring.
@ -892,7 +886,6 @@ CocoaFrameBuffer::CocoaFrameBuffer(int width, int height, bool bgra, bool fullsc
glGenTextures(1, &m_texture); glGenTextures(1, &m_texture);
glBindTexture(GL_TEXTURE_RECTANGLE_ARB, m_texture); glBindTexture(GL_TEXTURE_RECTANGLE_ARB, m_texture);
glPixelStorei(GL_UNPACK_CLIENT_STORAGE_APPLE, GL_TRUE);
glTexParameteri(GL_TEXTURE_RECTANGLE_ARB, GL_TEXTURE_MIN_FILTER, GL_NEAREST); glTexParameteri(GL_TEXTURE_RECTANGLE_ARB, GL_TEXTURE_MIN_FILTER, GL_NEAREST);
glTexParameteri(GL_TEXTURE_RECTANGLE_ARB, GL_TEXTURE_MAG_FILTER, GL_NEAREST); glTexParameteri(GL_TEXTURE_RECTANGLE_ARB, GL_TEXTURE_MAG_FILTER, GL_NEAREST);
@ -1103,15 +1096,7 @@ void CocoaFrameBuffer::Flip()
rbOpts.dirty = false; rbOpts.dirty = false;
} }
#ifdef __LITTLE_ENDIAN__ const GLenum format = IsBgra() ? GL_BGRA : GL_RGBA;
static const GLenum format = GL_RGBA;
#else // __BIG_ENDIAN__
static const GLenum format = GL_ABGR_EXT;
#endif // __LITTLE_ENDIAN__
if (IsBgra())
glTexImage2D(GL_TEXTURE_RECTANGLE_ARB, 0, GL_RGBA8, Width, Height, 0, GL_BGRA, GL_UNSIGNED_BYTE, m_pixelBuffer);
else
glTexImage2D(GL_TEXTURE_RECTANGLE_ARB, 0, GL_RGBA8, Width, Height, 0, format, GL_UNSIGNED_BYTE, m_pixelBuffer); glTexImage2D(GL_TEXTURE_RECTANGLE_ARB, 0, GL_RGBA8, Width, Height, 0, format, GL_UNSIGNED_BYTE, m_pixelBuffer);
glBegin(GL_QUADS); glBegin(GL_QUADS);

View file

@ -381,10 +381,6 @@ static NSString* GetArchitectureString()
return @"i386"; return @"i386";
#elif defined __x86_64__ #elif defined __x86_64__
return @"x86_64"; return @"x86_64";
#elif defined __ppc__
return @"ppc";
#elif defined __ppc64__
return @"ppc64";
#endif #endif
} }

View file

@ -5945,7 +5945,7 @@ FxRandomSeed::~FxRandomSeed()
FxExpression *FxRandomSeed::Resolve(FCompileContext &ctx) FxExpression *FxRandomSeed::Resolve(FCompileContext &ctx)
{ {
CHECKRESOLVED(); CHECKRESOLVED();
RESOLVE(seed, ctx); SAFE_RESOLVE(seed, ctx);
return this; return this;
}; };

View file

@ -112,6 +112,9 @@ struct FISoundChannel
}; };
void FindLoopTags(FileReader *fr, uint32_t *start, bool *startass, uint32_t *end, bool *endass);
enum SampleType enum SampleType
{ {
SampleType_UInt8, SampleType_UInt8,

View file

@ -97,80 +97,171 @@ CUSTOM_CVAR(Int, snd_streambuffersize, 64, CVAR_ARCHIVE | CVAR_GLOBALCONFIG)
//========================================================================== //==========================================================================
// //
// try to find the LOOP_START/LOOP_END tags // Try to find the LOOP_START/LOOP_END tags in a Vorbis Comment block
// //
// This is a brute force implementation, thanks in no snall part // We have to parse through the FLAC or Ogg headers manually, since sndfile
// that no decent documentation of Ogg headers seems to exist and // doesn't provide proper access to the comments and we'd rather not require
// all available tag libraries are horrendously bloated. // using libFLAC and libvorbisfile directly.
// So if we want to do this without any new third party dependencies,
// thanks to the lack of anything that would help to do this properly,
// this was the only solution.
// //
//========================================================================== //==========================================================================
void FindLoopTags(FileReader *fr, uint32_t *start, bool *startass, uint32_t *end, bool *endass) static void ParseVorbisComments(FileReader *fr, uint32_t *start, bool *startass, uint32_t *end, bool *endass)
{ {
unsigned char testbuf[256]; uint8_t vc_data[4];
fr->Seek(0, SEEK_SET); // The VC block starts with a 32LE integer for the vendor string length,
long got = fr->Read(testbuf, 256); // followed by the vendor string
auto eqp = testbuf - 1; if(fr->Read(vc_data, 4) != 4)
int count; return;
while(true) uint32_t vndr_len = vc_data[0] | (vc_data[1]<<8) | (vc_data[2]<<16) | (vc_data[3]<<24);
{
unsigned char *c = (unsigned char *)memchr(eqp + 1, '=', 256 - (eqp + 1 - testbuf));
if (c == nullptr) return; // If there is no '=' in the first 256 bytes there's also no metadata.
eqp = c; // Skip vendor string
while (*c >= 32 && *c < 127) c--; if(fr->Seek(vndr_len, SEEK_CUR) == -1)
if (*c != 0) return;
// Following the vendor string is a 32LE integer for the number of
// comments, followed by each comment.
if(fr->Read(vc_data, 4) != 4)
return;
size_t count = vc_data[0] | (vc_data[1]<<8) | (vc_data[2]<<16) | (vc_data[3]<<24);
for(size_t i = 0; i < count; i++)
{ {
// doesn't look like a valid tag, so try again // Each comment is a 32LE integer for the comment length, followed by
// the comment text (not null terminated!)
if(fr->Read(vc_data, 4) != 4)
return;
uint32_t length = vc_data[0] | (vc_data[1]<<8) | (vc_data[2]<<16) | (vc_data[3]<<24);
if(length >= 128)
{
// If the comment is "big", skip it
if(fr->Seek(length, SEEK_CUR) == -1)
return;
continue; continue;
} }
c -= 3;
int len = c[0] + 256*c[1] + 65536*c[2]; char strdat[128];
if (c[3] || len > 1000000 || len < (eqp - c - 3)) if(fr->Read(strdat, length) != (long)length)
{ return;
// length looks fishy so retry with the next '=' strdat[length] = 0;
continue;
} if(strnicmp(strdat, "LOOP_START=", 11) == 0)
c -= 4; S_ParseTimeTag(strdat + 11, startass, start);
count = c[0] + 256 * c[1]; else if(strnicmp(strdat, "LOOP_END=", 9) == 0)
if (c[2] || c[3] || count <= 0 || count > 1000) S_ParseTimeTag(strdat + 9, endass, end);
{
// very unlikely to have 1000 tags
continue;
}
c += 4;
fr->Seek(long(c - testbuf), SEEK_SET);
break; // looks like we found something.
}
for (int i = 0; i < count; i++)
{
int length = 0;
fr->Read(&length, 4);
length = LittleLong(length);
if (length == 0 || length > 1000000) return; // looks like we lost it...
if (length > 25)
{
// This tag is too long to be a valid time stamp so don't even bother.
fr->Seek(length, SEEK_CUR);
continue;
}
fr->Read(testbuf, length);
testbuf[length] = 0;
if (strnicmp((char*)testbuf, "LOOP_START=", 11) == 0)
{
S_ParseTimeTag((char*)testbuf + 11, startass, start);
}
else if (strnicmp((char*)testbuf, "LOOP_END=", 9) == 0)
{
S_ParseTimeTag((char*)testbuf + 9, endass, end);
}
} }
} }
static void FindFlacComments(FileReader *fr, uint32_t *loop_start, bool *startass, uint32_t *loop_end, bool *endass)
{
// Already verified the fLaC marker, so we're 4 bytes into the file
bool lastblock = false;
uint8_t header[4];
while(!lastblock && fr->Read(header, 4) == 4)
{
// The first byte of the block header contains the type and a flag
// indicating the last metadata block
char blocktype = header[0]&0x7f;
lastblock = !!(header[0]&0x80);
// Following the type is a 24BE integer for the size of the block
uint32_t blocksize = (header[1]<<16) | (header[2]<<8) | header[3];
// FLAC__METADATA_TYPE_VORBIS_COMMENT is 4
if(blocktype == 4)
{
ParseVorbisComments(fr, loop_start, startass, loop_end, endass);
return;
}
if(fr->Seek(blocksize, SEEK_CUR) == -1)
break;
}
}
static void FindOggComments(FileReader *fr, uint32_t *loop_start, bool *startass, uint32_t *loop_end, bool *endass)
{
uint8_t ogghead[27];
// We already read and verified the OggS marker, so skip the first 4 bytes
// of the Ogg page header.
while(fr->Read(ogghead+4, 23) == 23)
{
// The 19th byte of the Ogg header is a 32LE integer for the page
// number, and the 27th is a uint8 for the number of segments in the
// page.
uint32_t ogg_pagenum = ogghead[18] | (ogghead[19]<<8) | (ogghead[20]<<16) |
(ogghead[21]<<24);
uint8_t ogg_segments = ogghead[26];
// Following the Ogg page header is a series of uint8s for the length of
// each segment in the page. The page segment data follows contiguously
// after.
uint8_t segsizes[256];
if(fr->Read(segsizes, ogg_segments) != ogg_segments)
break;
// Find the segment with the Vorbis Comment packet (type 3)
for(int i = 0; i < ogg_segments; ++i)
{
uint8_t segsize = segsizes[i];
if(segsize > 16)
{
uint8_t vorbhead[7];
if(fr->Read(vorbhead, 7) != 7)
return;
if(vorbhead[0] == 3 && memcmp(vorbhead+1, "vorbis", 6) == 0)
{
// If the packet is 'laced', it spans multiple segments (a
// segment size of 255 indicates the next segment continues
// the packet, ending with a size less than 255). Vorbis
// packets always start and end on segment boundaries. A
// packet that's an exact multiple of 255 ends with a
// segment of 0 size.
while(segsize == 255 && ++i < ogg_segments)
segsize = segsizes[i];
// TODO: A Vorbis packet can theoretically span multiple
// Ogg pages (e.g. start in the last segment of one page
// and end in the first segment of a following page). That
// will require extra logic to decode as the VC block will
// be broken up with non-Vorbis data in-between. For now,
// just handle the common case where it's all in one page.
if(i < ogg_segments)
ParseVorbisComments(fr, loop_start, startass, loop_end, endass);
return;
}
segsize -= 7;
}
if(fr->Seek(segsize, SEEK_CUR) == -1)
return;
}
// Don't keep looking after the third page
if(ogg_pagenum >= 2)
break;
if(fr->Read(ogghead, 4) != 4 || memcmp(ogghead, "OggS", 4) != 0)
break;
}
}
void FindLoopTags(FileReader *fr, uint32_t *start, bool *startass, uint32_t *end, bool *endass)
{
uint8_t signature[4];
fr->Read(signature, 4);
if(memcmp(signature, "fLaC", 4) == 0)
FindFlacComments(fr, start, startass, end, endass);
else if(memcmp(signature, "OggS", 4) == 0)
FindOggComments(fr, start, startass, end, endass);
}
//========================================================================== //==========================================================================
// //
// SndFile_OpenSong // SndFile_OpenSong
@ -179,18 +270,12 @@ void FindLoopTags(FileReader *fr, uint32_t *start, bool *startass, uint32_t *end
MusInfo *SndFile_OpenSong(FileReader &fr) MusInfo *SndFile_OpenSong(FileReader &fr)
{ {
uint8_t signature[4];
fr.Seek(0, SEEK_SET); fr.Seek(0, SEEK_SET);
fr.Read(signature, 4);
uint32_t loop_start = 0, loop_end = ~0u; uint32_t loop_start = 0, loop_end = ~0u;
bool startass = false, endass = false; bool startass = false, endass = false;
if (!memcmp(signature, "OggS", 4) || !memcmp(signature, "fLaC", 4))
{
// Todo: Read loop points from metadata
FindLoopTags(&fr, &loop_start, &startass, &loop_end, &endass); FindLoopTags(&fr, &loop_start, &startass, &loop_end, &endass);
}
fr.Seek(0, SEEK_SET); fr.Seek(0, SEEK_SET);
auto decoder = SoundRenderer::CreateDecoder(&fr); auto decoder = SoundRenderer::CreateDecoder(&fr);
if (decoder == nullptr) return nullptr; if (decoder == nullptr) return nullptr;

View file

@ -1276,8 +1276,6 @@ std::pair<SoundHandle,bool> OpenALSoundRenderer::LoadSoundRaw(uint8_t *sfxdata,
return std::make_pair(retval, AL.SOFT_source_spatialize || channels==1); return std::make_pair(retval, AL.SOFT_source_spatialize || channels==1);
} }
void FindLoopTags(FileReader *fr, uint32_t *start, bool *startass, uint32_t *end, bool *endass);
std::pair<SoundHandle,bool> OpenALSoundRenderer::LoadSound(uint8_t *sfxdata, int length, bool monoize, FSoundLoadBuffer *pBuffer) std::pair<SoundHandle,bool> OpenALSoundRenderer::LoadSound(uint8_t *sfxdata, int length, bool monoize, FSoundLoadBuffer *pBuffer)
{ {
SoundHandle retval = { NULL }; SoundHandle retval = { NULL };
@ -1292,12 +1290,9 @@ std::pair<SoundHandle,bool> OpenALSoundRenderer::LoadSound(uint8_t *sfxdata, int
/* Only downmix to mono if we can't spatialize multi-channel sounds. */ /* Only downmix to mono if we can't spatialize multi-channel sounds. */
monoize = monoize && !AL.SOFT_source_spatialize; monoize = monoize && !AL.SOFT_source_spatialize;
if (!memcmp(sfxdata, "OggS", 4) || !memcmp(sfxdata, "FLAC", 4)) FindLoopTags(&reader, &loop_start, &startass, &loop_end, &endass);
{
MemoryReader mr((char*)sfxdata, length);
FindLoopTags(&mr, &loop_start, &startass, &loop_end, &endass);
}
reader.Seek(0, SEEK_SET);
std::unique_ptr<SoundDecoder> decoder(CreateDecoder(&reader)); std::unique_ptr<SoundDecoder> decoder(CreateDecoder(&reader));
if (!decoder) return std::make_pair(retval, true); if (!decoder) return std::make_pair(retval, true);