diff --git a/src/CMakeLists.txt b/src/CMakeLists.txt index 891691fa8..b13fabe9d 100644 --- a/src/CMakeLists.txt +++ b/src/CMakeLists.txt @@ -1113,6 +1113,7 @@ set (PCH_SOURCES textures/anim_switches.cpp textures/automaptexture.cpp textures/bitmap.cpp + textures/brightmaptexture.cpp textures/buildtexture.cpp textures/canvastexture.cpp textures/ddstexture.cpp diff --git a/src/gl/data/gl_data.cpp b/src/gl/data/gl_data.cpp index a773b337e..effc5cbc7 100644 --- a/src/gl/data/gl_data.cpp +++ b/src/gl/data/gl_data.cpp @@ -68,9 +68,6 @@ CUSTOM_CVAR(Bool, gl_notexturefill, false, 0) void gl_CreateSections(); -void AddAutoMaterials(); - - //========================================================================== @@ -279,11 +276,6 @@ void gl_RecalcVertexHeights(vertex_t * v) -void gl_InitData() -{ - AddAutoMaterials(); -} - //========================================================================== // // dumpgeometry diff --git a/src/gl/data/gl_data.h b/src/gl/data/gl_data.h index 518f330c9..96ee070cb 100644 --- a/src/gl/data/gl_data.h +++ b/src/gl/data/gl_data.h @@ -63,6 +63,5 @@ extern TArray currentmapsection; void gl_InitPortals(); void gl_BuildPortalCoverage(FPortalCoverage *coverage, subsector_t *subsector, const DVector2 &displacement); -void gl_InitData(); #endif diff --git a/src/gl/dynlights/gl_glow.cpp b/src/gl/dynlights/gl_glow.cpp index 030ec2188..9d44e38af 100644 --- a/src/gl/dynlights/gl_glow.cpp +++ b/src/gl/dynlights/gl_glow.cpp @@ -52,7 +52,7 @@ void gl_InitGlow(FScanner &sc) sc.MustGetString(); FTextureID flump=TexMan.CheckForTexture(sc.String, ETextureType::Flat,FTextureManager::TEXMAN_TryAny); FTexture *tex = TexMan[flump]; - if (tex) tex->gl_info.bAutoGlowing = tex->gl_info.bGlowing = tex->gl_info.bFullbright = true; + if (tex) tex->gl_info.bAutoGlowing = tex->bGlowing = tex->gl_info.bFullbright = true; } } else if (sc.Compare("WALLS")) @@ -63,7 +63,7 @@ void gl_InitGlow(FScanner &sc) sc.MustGetString(); FTextureID flump=TexMan.CheckForTexture(sc.String, ETextureType::Wall,FTextureManager::TEXMAN_TryAny); FTexture *tex = TexMan[flump]; - if (tex) tex->gl_info.bAutoGlowing = tex->gl_info.bGlowing = tex->gl_info.bFullbright = true; + if (tex) tex->gl_info.bAutoGlowing = tex->bGlowing = tex->gl_info.bFullbright = true; } } else if (sc.Compare("TEXTURE")) @@ -94,8 +94,8 @@ void gl_InitGlow(FScanner &sc) if (tex && color != 0) { tex->gl_info.bAutoGlowing = false; - tex->gl_info.bGlowing = true; - tex->gl_info.GlowColor = color; + tex->bGlowing = true; + tex->GlowColor = color; } } } diff --git a/src/gl/scene/gl_scene.cpp b/src/gl/scene/gl_scene.cpp index 9268d6066..cfc108a81 100644 --- a/src/gl/scene/gl_scene.cpp +++ b/src/gl/scene/gl_scene.cpp @@ -1013,7 +1013,6 @@ struct FGLInterface : public FRenderer int GetMaxViewPitch(bool down) override; void SetClearColor(int color) override; - void Init() override; uint32_t GetCaps() override; }; @@ -1098,17 +1097,6 @@ void FGLInterface::RenderView(player_t *player) GLRenderer->RenderView(player); } -//=========================================================================== -// -// -// -//=========================================================================== - -void FGLInterface::Init() -{ - gl_InitData(); -} - //=========================================================================== // // Camera texture rendering diff --git a/src/gl/system/gl_framebuffer.cpp b/src/gl/system/gl_framebuffer.cpp index efb2cbf5b..8a3000fe1 100644 --- a/src/gl/system/gl_framebuffer.cpp +++ b/src/gl/system/gl_framebuffer.cpp @@ -98,7 +98,6 @@ OpenGLFrameBuffer::OpenGLFrameBuffer(void *hMonitor, int width, int height, int mDebug = std::make_shared(); mDebug->Update(); gl_SetupMenu(); - gl_GenerateGlobalBrightmapFromColormap(); DoSetGamma(); } @@ -454,7 +453,6 @@ void OpenGLFrameBuffer::GameRestart() memcpy (SourcePalette, GPalette.BaseColors, sizeof(PalEntry)*256); UpdatePalette (); ScreenshotBuffer = NULL; - gl_GenerateGlobalBrightmapFromColormap(); GLRenderer->GetSpecialTextures(); } diff --git a/src/gl/textures/gl_material.cpp b/src/gl/textures/gl_material.cpp index 092854125..1ab90ef03 100644 --- a/src/gl/textures/gl_material.cpp +++ b/src/gl/textures/gl_material.cpp @@ -864,8 +864,8 @@ int FMaterial::GetAreas(FloatRect **pAreas) const if (mShaderIndex == SHADER_Default) // texture splitting can only be done if there's no attached effects { FTexture *tex = mBaseLayer->tex; - *pAreas = tex->gl_info.areas; - return tex->gl_info.areacount; + *pAreas = tex->areas; + return tex->areacount; } else { diff --git a/src/gl/textures/gl_texture.cpp b/src/gl/textures/gl_texture.cpp index 9c4db0f30..a74173325 100644 --- a/src/gl/textures/gl_texture.cpp +++ b/src/gl/textures/gl_texture.cpp @@ -117,57 +117,6 @@ int TexFormat[]={ -bool HasGlobalBrightmap; -FRemapTable GlobalBrightmap; - -//=========================================================================== -// -// Examines the colormap to see if some of the colors have to be -// considered fullbright all the time. -// -//=========================================================================== - -void gl_GenerateGlobalBrightmapFromColormap() -{ - HasGlobalBrightmap = false; - int lump = Wads.CheckNumForName("COLORMAP"); - if (lump == -1) lump = Wads.CheckNumForName("COLORMAP", ns_colormaps); - if (lump == -1) return; - FMemLump cmap = Wads.ReadLump(lump); - uint8_t palbuffer[768]; - ReadPalette(Wads.CheckNumForName("PLAYPAL"), palbuffer); - - const unsigned char *cmapdata = (const unsigned char *)cmap.GetMem(); - const uint8_t *paldata = palbuffer; - - const int black = 0; - const int white = ColorMatcher.Pick(255,255,255); - - - GlobalBrightmap.MakeIdentity(); - memset(GlobalBrightmap.Remap, white, 256); - for(int i=0;i<256;i++) GlobalBrightmap.Palette[i]=PalEntry(255,255,255,255); - for(int j=0;j<32;j++) - { - for(int i=0;i<256;i++) - { - // the palette comparison should be for ==0 but that gives false positives with Heretic - // and Hexen. - if (cmapdata[i+j*256]!=i || (paldata[3*i]<10 && paldata[3*i+1]<10 && paldata[3*i+2]<10)) - { - GlobalBrightmap.Remap[i]=black; - GlobalBrightmap.Palette[i] = PalEntry(255, 0, 0, 0); - } - } - } - for(int i=0;i<256;i++) - { - HasGlobalBrightmap |= GlobalBrightmap.Remap[i] == white; - if (GlobalBrightmap.Remap[i] == white) DPrintf(DMSG_NOTIFY, "Marked color %d as fullbright\n",i); - } -} - - //========================================================================== // // GL status data for a texture @@ -176,19 +125,13 @@ void gl_GenerateGlobalBrightmapFromColormap() FTexture::MiscGLInfo::MiscGLInfo() throw() { - bGlowing = false; - GlowColor = 0; GlowHeight = 128; bSkybox = false; bFullbright = false; - bBrightmapChecked = false; bDisableFullbright = false; bNoFilter = false; bNoCompress = false; bNoExpand = false; - areas = NULL; - areacount = 0; - mIsTransparent = -1; shaderspeed = 1.f; shaderindex = 0; Glossiness = 10.0f; @@ -208,287 +151,6 @@ FTexture::MiscGLInfo::~MiscGLInfo() if (SystemTexture[i] != NULL) delete SystemTexture[i]; SystemTexture[i] = NULL; } - - if (areas != NULL) delete [] areas; - areas = NULL; -} - -//=========================================================================== -// -// Checks if the texture has a default brightmap and creates it if so -// -//=========================================================================== -void FTexture::CreateDefaultBrightmap() -{ - if (!gl_info.bBrightmapChecked) - { - // Check for brightmaps - if (UseBasePalette() && HasGlobalBrightmap && - UseType != ETextureType::Decal && UseType != ETextureType::MiscPatch && UseType != ETextureType::FontChar && - Brightmap == NULL && bWarped == 0 - ) - { - // May have one - let's check when we use this texture - const uint8_t *texbuf = GetPixels(DefaultRenderStyle()); - const int white = ColorMatcher.Pick(255,255,255); - - int size = GetWidth() * GetHeight(); - for(int i=0;iGetTextureBuffer(this, w, h); - - if (buffer) - { - gl_info.GlowColor = averageColor((uint32_t *) buffer, w*h, 153); - delete[] buffer; - } - - // Black glow equals nothing so switch glowing off - if (gl_info.GlowColor == 0) gl_info.bGlowing = false; - } - data[0]=gl_info.GlowColor.r/255.0f; - data[1]=gl_info.GlowColor.g/255.0f; - data[2]=gl_info.GlowColor.b/255.0f; -} - -//=========================================================================== -// -// Finds gaps in the texture which can be skipped by the renderer -// This was mainly added to speed up one area in E4M6 of 007LTSD -// -//=========================================================================== - -bool FTexture::FindHoles(const unsigned char * buffer, int w, int h) -{ - const unsigned char * li; - int y,x; - int startdraw,lendraw; - int gaps[5][2]; - int gapc=0; - - - // already done! - if (gl_info.areacount) return false; - if (UseType == ETextureType::Flat) return false; // flats don't have transparent parts - gl_info.areacount=-1; //whatever happens next, it shouldn't be done twice! - - // large textures are excluded for performance reasons - if (h>512) return false; - - startdraw=-1; - lendraw=0; - for(y=0;y 0) - { - FloatRect * rcs = new FloatRect[gapc]; - - for (x = 0; x < gapc; x++) - { - // gaps are stored as texture (u/v) coordinates - rcs[x].width = rcs[x].left = -1.0f; - rcs[x].top = (float)gaps[x][0] / (float)h; - rcs[x].height = (float)gaps[x][1] / (float)h; - } - gl_info.areas = rcs; - } - else gl_info.areas = nullptr; - gl_info.areacount=gapc; - - return true; -} - -//---------------------------------------------------------------------------- -// -// -// -//---------------------------------------------------------------------------- - -void FTexture::CheckTrans(unsigned char * buffer, int size, int trans) -{ - if (gl_info.mIsTransparent == -1) - { - gl_info.mIsTransparent = trans; - if (trans == -1) - { - uint32_t * dwbuf = (uint32_t*)buffer; - for(int i=0;i>24; - - if (alpha != 0xff && alpha != 0) - { - gl_info.mIsTransparent = 1; - return; - } - } - gl_info.mIsTransparent = 0; - } - } -} - - -//=========================================================================== -// -// smooth the edges of transparent fields in the texture -// -//=========================================================================== - -#ifdef WORDS_BIGENDIAN -#define MSB 0 -#define SOME_MASK 0xffffff00 -#else -#define MSB 3 -#define SOME_MASK 0x00ffffff -#endif - -#define CHKPIX(ofs) (l1[(ofs)*4+MSB]==255 ? (( ((uint32_t*)l1)[0] = ((uint32_t*)l1)[ofs]&SOME_MASK), trans=true ) : false) - -bool FTexture::SmoothEdges(unsigned char * buffer,int w, int h) -{ - int x,y; - bool trans=buffer[MSB]==0; // If I set this to false here the code won't detect textures - // that only contain transparent pixels. - bool semitrans = false; - unsigned char * l1; - - if (h<=1 || w<=1) return false; // makes (a) no sense and (b) doesn't work with this code! - - l1=buffer; - - - if (l1[MSB]==0 && !CHKPIX(1)) CHKPIX(w); - else if (l1[MSB]<255) semitrans=true; - l1+=4; - for(x=1;xbNoDecals; - Rotations = source->Rotations; - UseType = source->UseType; - bMasked = false; - id.SetInvalid(); - SourceLump = -1; -} - -uint8_t *FBrightmapTexture::MakeTexture(FRenderStyle style) -{ - // This function is only necessary to satisfy the parent class's interface. - // This will never be called. - return nullptr; -} - -int FBrightmapTexture::CopyTrueColorPixels(FBitmap *bmp, int x, int y, int rotate, FCopyInfo *inf) -{ - SourcePic->CopyTrueColorTranslated(bmp, x, y, rotate, GlobalBrightmap.Palette); - return 0; -} - //========================================================================== // // Parses a material definition @@ -754,55 +380,6 @@ void gl_ParseBrightmap(FScanner &sc, int deflump) tex->gl_info.bDisableFullbright = disable_fullbright; } -//========================================================================== -// -// Search auto paths for extra material textures -// -//========================================================================== - -struct AutoTextureSearchPath -{ - const char *path; - FTexture *FTexture::*pointer; -}; - -static AutoTextureSearchPath autosearchpaths[] = -{ - { "brightmaps/auto/", &FTexture::Brightmap }, // For backwards compatibility - { "materials/brightmaps/auto/", &FTexture::Brightmap }, - { "materials/normalmaps/auto/", &FTexture::Normal }, - { "materials/specular/auto/", &FTexture::Specular }, - { "materials/metallic/auto/", &FTexture::Metallic }, - { "materials/roughness/auto/", &FTexture::Roughness }, - { "materials/ao/auto/", &FTexture::AmbientOcclusion } -}; - -void AddAutoMaterials() -{ - // Fixme: let this be driven by the texture manager, not the renderer. - int num = Wads.GetNumLumps(); - for (int i = 0; i < num; i++) - { - const char *name = Wads.GetLumpFullName(i); - for (const AutoTextureSearchPath &searchpath : autosearchpaths) - { - if (strstr(name, searchpath.path) == name) - { - TArray list; - FString texname = ExtractFileBase(name, false); - TexMan.ListTextures(texname, list); - auto bmtex = TexMan.FindTexture(name, ETextureType::Any, FTextureManager::TEXMAN_TryAny || FTextureManager::TEXMAN_DontCreate || FTextureManager::TEXMAN_ShortNameOnly ); - for (auto texid : list) - { - bmtex->bMasked = false; - auto tex = TexMan[texid]; - if (tex != nullptr) tex->*(searchpath.pointer) = bmtex; - } - } - } - } -} - //========================================================================== // // Parses a GLBoom+ detail texture definition diff --git a/src/gl/textures/gl_texture.h b/src/gl/textures/gl_texture.h index 44016f181..bc52c78c5 100644 --- a/src/gl/textures/gl_texture.h +++ b/src/gl/textures/gl_texture.h @@ -4,24 +4,6 @@ #include "r_defs.h" #include "textures/textures.h" -class FBrightmapTexture : public FWorldTexture -{ -public: - FBrightmapTexture (FTexture *source); - - uint8_t *MakeTexture(FRenderStyle style) override; - int CopyTrueColorPixels(FBitmap *bmp, int x, int y, int rotate, FCopyInfo *inf) override; - bool UseBasePalette() override { return false; } - -protected: - FTexture *SourcePic; -}; - - -void gl_GenerateGlobalBrightmapFromColormap(); - - - unsigned char *gl_CreateUpsampledTextureBuffer ( const FTexture *inputTexture, unsigned char *inputBuffer, const int inWidth, const int inHeight, int &outWidth, int &outHeight, bool hasAlpha ); int CheckDDPK3(FTexture *tex); int CheckExternalFile(FTexture *tex, bool & hascolorkey); diff --git a/src/r_renderer.h b/src/r_renderer.h index efaa8e9cd..fa73ea2b1 100644 --- a/src/r_renderer.h +++ b/src/r_renderer.h @@ -48,7 +48,6 @@ struct FRenderer virtual void OnModeSet () {} virtual void SetClearColor(int color) = 0; - virtual void Init() = 0; virtual void RenderTextureView (FCanvasTexture *tex, AActor *viewpoint, double fov) = 0; virtual void PreprocessLevel() {} virtual void CleanLevelData() {} diff --git a/src/r_utility.cpp b/src/r_utility.cpp index 9461e3046..8c97d1bf6 100644 --- a/src/r_utility.cpp +++ b/src/r_utility.cpp @@ -404,13 +404,8 @@ void R_Init () atterm (R_Shutdown); StartScreen->Progress(); - // Colormap init moved back to InitPalette() - //R_InitColormaps (); - //StartScreen->Progress(); - R_InitTranslationTables (); R_SetViewSize (screenblocks); - Renderer->Init(); } //========================================================================== diff --git a/src/swrenderer/drawers/r_draw.cpp b/src/swrenderer/drawers/r_draw.cpp index 180e886bf..3eb63a85f 100644 --- a/src/swrenderer/drawers/r_draw.cpp +++ b/src/swrenderer/drawers/r_draw.cpp @@ -81,7 +81,7 @@ namespace swrenderer uint32_t particle_texture[NUM_PARTICLE_TEXTURES][PARTICLE_TEXTURE_SIZE * PARTICLE_TEXTURE_SIZE]; - short zeroarray[MAXWIDTH]; + short zeroarray[MAXWIDTH] = { 0 }; short screenheightarray[MAXWIDTH]; void R_InitShadeMaps() diff --git a/src/swrenderer/r_swrenderer.cpp b/src/swrenderer/r_swrenderer.cpp index e2c2cefa7..89bb8e728 100644 --- a/src/swrenderer/r_swrenderer.cpp +++ b/src/swrenderer/r_swrenderer.cpp @@ -81,18 +81,14 @@ using namespace swrenderer; FSoftwareRenderer::FSoftwareRenderer() { + R_InitShadeMaps(); + InitSWColorMaps(); } FSoftwareRenderer::~FSoftwareRenderer() { } -void FSoftwareRenderer::Init() -{ - mScene.Init(); - InitSWColorMaps(); -} - void FSoftwareRenderer::PrecacheTexture(FTexture *tex, int cache) { bool isbgra = screen->IsBgra(); diff --git a/src/swrenderer/r_swrenderer.h b/src/swrenderer/r_swrenderer.h index 3fad93d21..75af702a7 100644 --- a/src/swrenderer/r_swrenderer.h +++ b/src/swrenderer/r_swrenderer.h @@ -28,7 +28,6 @@ struct FSoftwareRenderer : public FRenderer void OnModeSet() override; void SetClearColor(int color) override; - void Init() override; void RenderTextureView (FCanvasTexture *tex, AActor *viewpoint, double fov) override; void PreprocessLevel() override; diff --git a/src/swrenderer/scene/r_scene.cpp b/src/swrenderer/scene/r_scene.cpp index 566758b9c..3847c0d34 100644 --- a/src/swrenderer/scene/r_scene.cpp +++ b/src/swrenderer/scene/r_scene.cpp @@ -378,14 +378,6 @@ namespace swrenderer viewport->SetViewport(MainThread(), SCREENWIDTH, SCREENHEIGHT, trueratio); } - void RenderScene::Init() - { - // viewwidth / viewheight are set by the defaults - fillshort(zeroarray, MAXWIDTH, 0); - - R_InitShadeMaps(); - } - void RenderScene::Deinit() { MainThread()->TranslucentPass->Deinit(); diff --git a/src/swrenderer/scene/r_scene.h b/src/swrenderer/scene/r_scene.h index a5fd57bec..adc9e1449 100644 --- a/src/swrenderer/scene/r_scene.h +++ b/src/swrenderer/scene/r_scene.h @@ -44,7 +44,6 @@ namespace swrenderer RenderScene(); ~RenderScene(); - void Init(); void ScreenResized(); void Deinit(); diff --git a/src/textures/brightmaptexture.cpp b/src/textures/brightmaptexture.cpp new file mode 100644 index 000000000..feec1e422 --- /dev/null +++ b/src/textures/brightmaptexture.cpp @@ -0,0 +1,100 @@ +/* +** brightmaptexture.cpp +** The texture class for colormap based brightmaps. +** +**--------------------------------------------------------------------------- +** Copyright 2006-2018 Christoph Oelckers +** All rights reserved. +** +** Redistribution and use in source and binary forms, with or without +** modification, are permitted provided that the following conditions +** are met: +** +** 1. Redistributions of source code must retain the above copyright +** notice, this list of conditions and the following disclaimer. +** 2. Redistributions in binary form must reproduce the above copyright +** notice, this list of conditions and the following disclaimer in the +** documentation and/or other materials provided with the distribution. +** 3. The name of the author may not be used to endorse or promote products +** derived from this software without specific prior written permission. +** +** THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR +** IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES +** OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. +** IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, +** INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT +** NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, +** DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY +** THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +** (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF +** THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +**--------------------------------------------------------------------------- +** +** +*/ + +#include "doomtype.h" +#include "files.h" +#include "w_wad.h" +#include "templates.h" +#include "i_system.h" +#include "r_data/r_translate.h" +#include "bitmap.h" +#include "colormatcher.h" +#include "c_dispatch.h" +#include "v_video.h" +#include "m_fixed.h" +#include "textures/textures.h" +#include "v_palette.h" + +class FBrightmapTexture : public FWorldTexture +{ +public: + FBrightmapTexture (FTexture *source); + + uint8_t *MakeTexture(FRenderStyle style) override; + int CopyTrueColorPixels(FBitmap *bmp, int x, int y, int rotate, FCopyInfo *inf) override; + bool UseBasePalette() override { return false; } + +protected: + FTexture *SourcePic; +}; + +//=========================================================================== +// +// fake brightness maps +// These are generated for textures affected by a colormap with +// fullbright entries. +// +//=========================================================================== + +FBrightmapTexture::FBrightmapTexture (FTexture *source) +{ + Name = ""; + SourcePic = source; + CopySize(source); + bNoDecals = source->bNoDecals; + Rotations = source->Rotations; + UseType = source->UseType; + bMasked = false; + id.SetInvalid(); + SourceLump = -1; +} + +uint8_t *FBrightmapTexture::MakeTexture(FRenderStyle style) +{ + // This function is only necessary to satisfy the parent class's interface. + // This will never be called. + return nullptr; +} + +int FBrightmapTexture::CopyTrueColorPixels(FBitmap *bmp, int x, int y, int rotate, FCopyInfo *inf) +{ + SourcePic->CopyTrueColorTranslated(bmp, x, y, rotate, TexMan.GlobalBrightmap.Palette); + return 0; +} + +FTexture *CreateBrightmapTexture(FTexture *tex) +{ + return new FBrightmapTexture(tex); +} \ No newline at end of file diff --git a/src/textures/texture.cpp b/src/textures/texture.cpp index 4de99daad..c48c930cb 100644 --- a/src/textures/texture.cpp +++ b/src/textures/texture.cpp @@ -4,6 +4,7 @@ ** **--------------------------------------------------------------------------- ** Copyright 2004-2007 Randy Heit +** Copyright 2006-2018 Christoph Oelckers ** All rights reserved. ** ** Redistribution and use in source and binary forms, with or without @@ -47,6 +48,8 @@ #include "textures/textures.h" #include "v_palette.h" +FTexture *CreateBrightmapTexture(FTexture*); + // Make sprite offset adjustment user-configurable per renderer. int r_spriteadjustSW, r_spriteadjustHW; CUSTOM_CVAR(Int, r_spriteadjust, 2, CVAR_ARCHIVE | CVAR_GLOBALCONFIG) @@ -56,13 +59,12 @@ CUSTOM_CVAR(Int, r_spriteadjust, 2, CVAR_ARCHIVE | CVAR_GLOBALCONFIG) TexMan.SpriteAdjustChanged(); } -typedef FTexture * (*CreateFunc)(FileReader & file, int lumpnum); -struct TexCreateInfo -{ - CreateFunc TryCreate; - ETextureType usetype; -}; +//========================================================================== +// +// +// +//========================================================================== uint8_t FTexture::GrayMap[256]; @@ -70,10 +72,25 @@ void FTexture::InitGrayMap() { for (int i = 0; i < 256; ++i) { - GrayMap[i] = ColorMatcher.Pick (i, i, i); + GrayMap[i] = ColorMatcher.Pick(i, i, i); } } + +//========================================================================== +// +// +// +//========================================================================== + +typedef FTexture * (*CreateFunc)(FileReader & file, int lumpnum); + +struct TexCreateInfo +{ + CreateFunc TryCreate; + ETextureType usetype; +}; + FTexture *IMGZTexture_TryCreate(FileReader &, int lumpnum); FTexture *PNGTexture_TryCreate(FileReader &, int lumpnum); FTexture *JPEGTexture_TryCreate(FileReader &, int lumpnum); @@ -153,14 +170,24 @@ FTexture * FTexture::CreateTexture (const char *name, int lumpnum, ETextureType return tex; } +//========================================================================== +// +// +// +//========================================================================== FTexture::FTexture (const char *name, int lumpnum) : WidthBits(0), HeightBits(0), Scale(1,1), SourceLump(lumpnum), UseType(ETextureType::Any), bNoDecals(false), bNoRemap0(false), bWorldPanning(false), - bMasked(true), bAlphaTexture(false), bHasCanvas(false), bWarped(0), bComplex(false), bMultiPatch(false), bKeepAround(false), + bMasked(true), bAlphaTexture(false), bHasCanvas(false), bWarped(0), bComplex(false), bMultiPatch(false), bKeepAround(false), bFullNameTexture(false), Rotations(0xFFFF), SkyOffset(0), Width(0), Height(0), WidthMask(0) { + bBrightmapChecked = false; + bGlowing = false; + bTranslucent = -1; + + _LeftOffset[0] = _LeftOffset[1] = _TopOffset[0] = _TopOffset[1] = 0; id.SetInvalid(); if (name != NULL) @@ -181,7 +208,9 @@ FTexture::FTexture (const char *name, int lumpnum) FTexture::~FTexture () { FTexture *link = Wads.GetLinkedTexture(SourceLump); - if (link == this) Wads.SetLinkedTexture(SourceLump, NULL); + if (link == this) Wads.SetLinkedTexture(SourceLump, nullptr); + if (areas != nullptr) delete[] areas; + areas = nullptr; } void FTexture::Unload() @@ -189,6 +218,12 @@ void FTexture::Unload() PixelsBgra = std::vector(); } +//========================================================================== +// +// +// +//========================================================================== + const uint32_t *FTexture::GetColumnBgra(unsigned int column, const Span **spans_out) { const uint32_t *pixels = GetPixelsBgra(); @@ -216,6 +251,12 @@ const uint32_t *FTexture::GetPixelsBgra() return PixelsBgra.data(); } +//========================================================================== +// +// +// +//========================================================================== + bool FTexture::CheckModified (FRenderStyle) { return false; @@ -231,6 +272,12 @@ void FTexture::SetFrontSkyLayer () bNoRemap0 = true; } +//========================================================================== +// +// +// +//========================================================================== + void FTexture::CalcBitSize () { // WidthBits is rounded down, and HeightBits is rounded up @@ -258,6 +305,12 @@ void FTexture::CalcBitSize () HeightBits = i; } +//========================================================================== +// +// +// +//========================================================================== + FTexture::Span **FTexture::CreateSpans (const uint8_t *pixels) const { Span **spans, *span; @@ -357,6 +410,12 @@ void FTexture::FreeSpans (Span **spans) const M_Free (spans); } +//========================================================================== +// +// +// +//========================================================================== + void FTexture::GenerateBgraFromBitmap(const FBitmap &bitmap) { CreatePixelsBgraWithMipmaps(); @@ -399,6 +458,12 @@ int FTexture::MipmapLevels() const return MAX(widthbits, heightbits); } +//========================================================================== +// +// +// +//========================================================================== + void FTexture::GenerateBgraMipmaps() { struct Color4f @@ -520,6 +585,12 @@ void FTexture::GenerateBgraMipmaps() } } +//========================================================================== +// +// +// +//========================================================================== + void FTexture::GenerateBgraMipmapsFast() { uint32_t *src = PixelsBgra.data(); @@ -561,6 +632,12 @@ void FTexture::GenerateBgraMipmapsFast() } } +//========================================================================== +// +// +// +//========================================================================== + void FTexture::CopyToBlock (uint8_t *dest, int dwidth, int dheight, int xpos, int ypos, int rotate, const uint8_t *translation, FRenderStyle style) { const uint8_t *pixels = GetPixels(style); @@ -602,8 +679,12 @@ void FTexture::CopyToBlock (uint8_t *dest, int dwidth, int dheight, int xpos, in } } +//========================================================================== +// // Converts a texture between row-major and column-major format // by flipping it about the X=Y axis. +// +//========================================================================== void FTexture::FlipSquareBlock (uint8_t *block, int x, int y) { @@ -720,6 +801,12 @@ void FTexture::FlipNonSquareBlockRemap (uint8_t *dst, const uint8_t *src, int x, } } +//========================================================================== +// +// +// +//========================================================================== + void FTexture::FillBuffer(uint8_t *buff, int pitch, int height, FTextureFormat fmt) { const uint8_t *pix; @@ -787,7 +874,13 @@ int FTexture::CopyTrueColorTranslated(FBitmap *bmp, int x, int y, int rotate, Pa return 0; } -bool FTexture::UseBasePalette() +//========================================================================== +// +// +// +//========================================================================== + +bool FTexture::UseBasePalette() { return true; } @@ -914,8 +1007,345 @@ int FTexture::CheckRealHeight() return maxy; } +//========================================================================== +// +// Search auto paths for extra material textures +// +//========================================================================== + +void FTexture::AddAutoMaterials() +{ + struct AutoTextureSearchPath + { + const char *path; + FTexture *FTexture::*pointer; + }; + + static AutoTextureSearchPath autosearchpaths[] = + { + { "brightmaps/", &FTexture::Brightmap }, // For backwards compatibility, only for short names + { "materials/brightmaps/", &FTexture::Brightmap }, + { "materials/normalmaps/", &FTexture::Normal }, + { "materials/specular/", &FTexture::Specular }, + { "materials/metallic/", &FTexture::Metallic }, + { "materials/roughness/", &FTexture::Roughness }, + { "materials/ao/", &FTexture::AmbientOcclusion } + }; + int startindex = bFullNameTexture ? 1 : 0; + FString searchname = Name; + + if (bFullNameTexture) + { + auto dot = searchname.LastIndexOf('.'); + auto slash = searchname.LastIndexOf('/'); + if (dot > slash) searchname.Truncate(dot); + } + + for (int i = 0; i < countof(autosearchpaths); i++) + { + auto &layer = autosearchpaths[i]; + if (this->*(layer.pointer) == nullptr) // only if no explicit assignment had been done. + { + FStringf lookup("%s%s%s", layer.path, bFullNameTexture ? "" : "auto/", searchname.GetChars()); + auto lump = Wads.CheckNumForFullName(lookup, false, ns_global, true); + if (lump != -1) + { + auto bmtex = TexMan.FindTexture(Wads.GetLumpFullName(lump), ETextureType::Any, FTextureManager::TEXMAN_TryAny); + if (bmtex != nullptr) + { + bmtex->bMasked = false; + this->*(layer.pointer) = bmtex; + } + } + } + } +} + +//=========================================================================== +// +// Checks if the texture has a default brightmap and creates it if so +// +//=========================================================================== +void FTexture::CreateDefaultBrightmap() +{ + if (!bBrightmapChecked) + { + // Check for brightmaps + if (UseBasePalette() && TexMan.HasGlobalBrightmap && + UseType != ETextureType::Decal && UseType != ETextureType::MiscPatch && UseType != ETextureType::FontChar && + Brightmap == NULL && bWarped == 0 + ) + { + // May have one - let's check when we use this texture + const uint8_t *texbuf = GetPixels(DefaultRenderStyle()); + const int white = ColorMatcher.Pick(255, 255, 255); + + int size = GetWidth() * GetHeight(); + for (int i = 0; i512) return false; + + startdraw = -1; + lendraw = 0; + for (y = 0; y 0) + { + FloatRect * rcs = new FloatRect[gapc]; + + for (x = 0; x < gapc; x++) + { + // gaps are stored as texture (u/v) coordinates + rcs[x].width = rcs[x].left = -1.0f; + rcs[x].top = (float)gaps[x][0] / (float)h; + rcs[x].height = (float)gaps[x][1] / (float)h; + } + areas = rcs; + } + else areas = nullptr; + areacount = gapc; + + return true; +} + +//---------------------------------------------------------------------------- +// +// +// +//---------------------------------------------------------------------------- + +void FTexture::CheckTrans(unsigned char * buffer, int size, int trans) +{ + if (bTranslucent == -1) + { + bTranslucent = trans; + if (trans == -1) + { + uint32_t * dwbuf = (uint32_t*)buffer; + for (int i = 0; i> 24; + + if (alpha != 0xff && alpha != 0) + { + bTranslucent = 1; + return; + } + } + bTranslucent = 0; + } + } +} + + +//=========================================================================== +// +// smooth the edges of transparent fields in the texture +// +//=========================================================================== + +#ifdef WORDS_BIGENDIAN +#define MSB 0 +#define SOME_MASK 0xffffff00 +#else +#define MSB 3 +#define SOME_MASK 0x00ffffff +#endif + +#define CHKPIX(ofs) (l1[(ofs)*4+MSB]==255 ? (( ((uint32_t*)l1)[0] = ((uint32_t*)l1)[ofs]&SOME_MASK), trans=true ) : false) + +bool FTexture::SmoothEdges(unsigned char * buffer, int w, int h) +{ + int x, y; + bool trans = buffer[MSB] == 0; // If I set this to false here the code won't detect textures + // that only contain transparent pixels. + bool semitrans = false; + unsigned char * l1; + + if (h <= 1 || w <= 1) return false; // makes (a) no sense and (b) doesn't work with this code! + + l1 = buffer; + + + if (l1[MSB] == 0 && !CHKPIX(1)) CHKPIX(w); + else if (l1[MSB]<255) semitrans = true; + l1 += 4; + for (x = 1; xName, name) == 0) + + if (stricmp (tex->Name, name) == 0 ) { + // If we look for short names, we must ignore any long name texture. + if ((flags & TEXMAN_ShortNameOnly) && !tex->bFullNameTexture) + { + continue; + } // The name matches, so check the texture type if (usetype == ETextureType::Any) { @@ -210,7 +215,6 @@ FTextureID FTextureManager::CheckForTexture (const char *name, ETextureType uset } } } - i = Textures[i].HashNext; } if ((flags & TEXMAN_TryAny) && usetype != ETextureType::Any) @@ -242,6 +246,7 @@ FTextureID FTextureManager::CheckForTexture (const char *name, ETextureType uset tex = FTexture::CreateTexture("", lump, ETextureType::Override); if (tex != NULL) { + tex->AddAutoMaterials(); Wads.SetLinkedTexture(lump, tex); return AddTexture(tex); } @@ -981,6 +986,7 @@ FTexture *CreateShaderTexture(bool, bool); void FTextureManager::Init() { DeleteAll(); + GenerateGlobalBrightmapFromColormap(); SpriteFrames.Clear(); //if (BuildTileFiles.Size() == 0) CountBuildTiles (); FTexture::InitGrayMap(); @@ -1045,6 +1051,11 @@ void FTextureManager::Init() InitSwitchList(); InitPalettedVersions(); AdjustSpriteOffsets(); + // Add auto materials to each texture after everything has been set up. + for (auto &tex : Textures) + { + tex.Texture->AddAutoMaterials(); + } } //========================================================================== @@ -1057,7 +1068,6 @@ void FTextureManager::InitPalettedVersions() { int lump, lastlump = 0; - PalettedVersions.Clear(); while ((lump = Wads.FindLump("PALVERS", &lastlump)) != -1) { FScanner sc(lump); @@ -1077,7 +1087,10 @@ void FTextureManager::InitPalettedVersions() } if (pic1.isValid() && pic2.isValid()) { - PalettedVersions[pic1.GetIndex()] = pic2.GetIndex(); + FTexture *owner = TexMan[pic1]; + FTexture *owned = TexMan[pic2]; + + if (owner && owned) owner->PalVersion = owned; } } } @@ -1089,12 +1102,13 @@ void FTextureManager::InitPalettedVersions() // //========================================================================== +// fixme: The way this is used, it is mostly useless. FTextureID FTextureManager::PalCheck(FTextureID tex) { if (vid_nopalsubstitutions) return tex; - int *newtex = PalettedVersions.CheckKey(tex.GetIndex()); - if (newtex == NULL || *newtex == 0) return tex; - return *newtex; + auto ftex = operator[](tex); + if (ftex != nullptr && ftex->PalVersion != nullptr) return ftex->PalVersion->id; + return tex; } //=========================================================================== @@ -1292,6 +1306,55 @@ void FTextureManager::SpriteAdjustChanged() } } +//=========================================================================== +// +// Examines the colormap to see if some of the colors have to be +// considered fullbright all the time. +// +//=========================================================================== + +void FTextureManager::GenerateGlobalBrightmapFromColormap() +{ + Wads.CheckNumForFullName("textures/tgapal", false, 0, true); + HasGlobalBrightmap = false; + int lump = Wads.CheckNumForName("COLORMAP"); + if (lump == -1) lump = Wads.CheckNumForName("COLORMAP", ns_colormaps); + if (lump == -1) return; + FMemLump cmap = Wads.ReadLump(lump); + uint8_t palbuffer[768]; + ReadPalette(Wads.CheckNumForName("PLAYPAL"), palbuffer); + + const unsigned char *cmapdata = (const unsigned char *)cmap.GetMem(); + const uint8_t *paldata = palbuffer; + + const int black = 0; + const int white = ColorMatcher.Pick(255, 255, 255); + + + GlobalBrightmap.MakeIdentity(); + memset(GlobalBrightmap.Remap, white, 256); + for (int i = 0; i<256; i++) GlobalBrightmap.Palette[i] = PalEntry(255, 255, 255, 255); + for (int j = 0; j<32; j++) + { + for (int i = 0; i<256; i++) + { + // the palette comparison should be for ==0 but that gives false positives with Heretic + // and Hexen. + if (cmapdata[i + j * 256] != i || (paldata[3 * i]<10 && paldata[3 * i + 1]<10 && paldata[3 * i + 2]<10)) + { + GlobalBrightmap.Remap[i] = black; + GlobalBrightmap.Palette[i] = PalEntry(255, 0, 0, 0); + } + } + } + for (int i = 0; i<256; i++) + { + HasGlobalBrightmap |= GlobalBrightmap.Remap[i] == white; + if (GlobalBrightmap.Remap[i] == white) DPrintf(DMSG_NOTIFY, "Marked color %d as fullbright\n", i); + } +} + + //========================================================================== // // diff --git a/src/textures/textures.h b/src/textures/textures.h index f867d766d..a076f1441 100644 --- a/src/textures/textures.h +++ b/src/textures/textures.h @@ -171,6 +171,7 @@ public: static FTexture *CreateTexture(const char *name, int lumpnum, ETextureType usetype); static FTexture *CreateTexture(int lumpnum, ETextureType usetype); virtual ~FTexture (); + void AddAutoMaterials(); //int16_t LeftOffset, TopOffset; @@ -181,6 +182,11 @@ public: int SourceLump; FTextureID id; + // None of the following pointers are owned by this texture, they are all controlled by the texture manager. + + // Paletted variant + FTexture *PalVersion = nullptr; + // Material layers FTexture *Brightmap = nullptr; FTexture *Normal = nullptr; // Normal map texture FTexture *Specular = nullptr; // Specular light texture for the diffuse+normal+specular light model @@ -203,9 +209,16 @@ public: // doing it per patch. uint8_t bMultiPatch:1; // This is a multipatch texture (we really could use real type info for textures...) uint8_t bKeepAround:1; // This texture was used as part of a multi-patch texture. Do not free it. + uint8_t bFullNameTexture : 1; + uint8_t bBrightmapChecked : 1; // Set to 1 if brightmap has been checked + uint8_t bGlowing : 1; // Texture glow color + int8_t bTranslucent : 2; uint16_t Rotations; int16_t SkyOffset; + FloatRect *areas = nullptr; + int areacount = 0; + PalEntry GlowColor = 0; struct Span @@ -373,13 +386,6 @@ protected: bNoDecals = other->bNoDecals; Rotations = other->Rotations; gl_info = other->gl_info; - Brightmap = NULL; - Normal = NULL; - Specular = NULL; - Metallic = NULL; - Roughness = NULL; - AmbientOcclusion = NULL; - gl_info.areas = NULL; } std::vector PixelsBgra; @@ -411,18 +417,13 @@ public: FGLTexture *SystemTexture[2]; float Glossiness; float SpecularLevel; - PalEntry GlowColor; int GlowHeight; - FloatRect *areas; - int areacount; int shaderindex; float shaderspeed; int mIsTransparent:2; - bool bGlowing:1; // Texture glows bool bAutoGlowing : 1; // Glow info is determined from texture image. bool bFullbright:1; // always draw fullbright bool bSkybox:1; // This is a skybox - char bBrightmapChecked:1; // Set to 1 if brightmap has been checked bool bDisableFullbright:1; // This texture will not be displayed as fullbright sprite bool bNoFilter:1; bool bNoCompress:1; @@ -434,7 +435,7 @@ public: MiscGLInfo gl_info; void GetGlowColor(float *data); - bool isGlowing() { return gl_info.bGlowing; } + bool isGlowing() { return bGlowing; } bool isFullbright() { return gl_info.bFullbright; } void CreateDefaultBrightmap(); bool FindHoles(const unsigned char * buffer, int w, int h); @@ -597,6 +598,7 @@ private: void ParseAnimatedDoor(FScanner &sc); void InitPalettedVersions(); + void GenerateGlobalBrightmapFromColormap(); // Switches @@ -616,7 +618,6 @@ private: int HashFirst[HASH_SIZE]; FTextureID DefaultTexture; TArray FirstTextureForFile; - TMap PalettedVersions; // maps from normal -> paletted version TArray > BuildTileData; TArray mAnimations; @@ -624,6 +625,8 @@ private: TArray mAnimatedDoors; public: + bool HasGlobalBrightmap; + FRemapTable GlobalBrightmap; short sintable[2048]; // for texture warping enum { diff --git a/src/w_wad.cpp b/src/w_wad.cpp index 31e65cd9b..0976f5ed7 100644 --- a/src/w_wad.cpp +++ b/src/w_wad.cpp @@ -109,6 +109,7 @@ void uppercopy (char *to, const char *from) FWadCollection::FWadCollection () : FirstLumpIndex(NULL), NextLumpIndex(NULL), FirstLumpIndex_FullName(NULL), NextLumpIndex_FullName(NULL), + FirstLumpIndex_NoExt(NULL), NextLumpIndex_NoExt(NULL), NumLumps(0) { } @@ -140,11 +141,21 @@ void FWadCollection::DeleteAll () delete[] NextLumpIndex_FullName; NextLumpIndex_FullName = NULL; } + if (FirstLumpIndex_NoExt != NULL) + { + delete[] FirstLumpIndex_NoExt; + FirstLumpIndex_NoExt = NULL; + } + if (NextLumpIndex_NoExt != NULL) + { + delete[] NextLumpIndex_NoExt; + NextLumpIndex_NoExt = NULL; + } LumpInfo.Clear(); NumLumps = 0; - // we must count backward to enssure that embedded WADs are deleted before + // we must count backward to ensure that embedded WADs are deleted before // the ones that contain their data. for (int i = Files.Size() - 1; i >= 0; --i) { @@ -192,6 +203,8 @@ void FWadCollection::InitMultipleFiles (TArray &filenames) NextLumpIndex = new uint32_t[NumLumps]; FirstLumpIndex_FullName = new uint32_t[NumLumps]; NextLumpIndex_FullName = new uint32_t[NumLumps]; + FirstLumpIndex_NoExt = new uint32_t[NumLumps]; + NextLumpIndex_NoExt = new uint32_t[NumLumps]; InitHashChains (); LumpInfo.ShrinkToFit(); Files.ShrinkToFit(); @@ -533,7 +546,7 @@ int FWadCollection::GetNumForName (const char *name, int space) // //========================================================================== -int FWadCollection::CheckNumForFullName (const char *name, bool trynormal, int namespc) +int FWadCollection::CheckNumForFullName (const char *name, bool trynormal, int namespc, bool ignoreext) { uint32_t i; @@ -541,12 +554,19 @@ int FWadCollection::CheckNumForFullName (const char *name, bool trynormal, int n { return -1; } + uint32_t *fli = ignoreext ? FirstLumpIndex_NoExt : FirstLumpIndex_FullName; + uint32_t *nli = ignoreext ? NextLumpIndex_NoExt : NextLumpIndex_FullName; + auto len = strlen(name); - i = FirstLumpIndex_FullName[MakeKey(name) % NumLumps]; - - while (i != NULL_INDEX && stricmp(name, LumpInfo[i].lump->FullName)) + for (i = fli[MakeKey(name) % NumLumps]; i != NULL_INDEX; i = nli[i]) { - i = NextLumpIndex_FullName[i]; + if (strnicmp(name, LumpInfo[i].lump->FullName, len)) continue; + if (LumpInfo[i].lump->FullName[len] == 0) break; // this is a full match + if (ignoreext && LumpInfo[i].lump->FullName[len] == '.') + { + // is this the last '.' in the last path element, indicating that the remaining part of the name is only an extension? + if (strpbrk(LumpInfo[i].lump->FullName.GetChars() + len + 1, "./") == nullptr) break; + } } if (i != NULL_INDEX) return i; @@ -733,6 +753,8 @@ void FWadCollection::InitHashChains (void) memset (NextLumpIndex, 255, NumLumps*sizeof(NextLumpIndex[0])); memset (FirstLumpIndex_FullName, 255, NumLumps*sizeof(FirstLumpIndex_FullName[0])); memset (NextLumpIndex_FullName, 255, NumLumps*sizeof(NextLumpIndex_FullName[0])); + memset(FirstLumpIndex_NoExt, 255, NumLumps * sizeof(FirstLumpIndex_NoExt[0])); + memset(NextLumpIndex_NoExt, 255, NumLumps * sizeof(NextLumpIndex_NoExt[0])); // Now set up the chains for (i = 0; i < (unsigned)NumLumps; i++) @@ -748,6 +770,16 @@ void FWadCollection::InitHashChains (void) j = MakeKey(LumpInfo[i].lump->FullName) % NumLumps; NextLumpIndex_FullName[i] = FirstLumpIndex_FullName[j]; FirstLumpIndex_FullName[j] = i; + + FString nameNoExt = LumpInfo[i].lump->FullName; + auto dot = nameNoExt.LastIndexOf('.'); + auto slash = nameNoExt.LastIndexOf('/'); + if (dot > slash) nameNoExt.Truncate(dot); + + j = MakeKey(nameNoExt) % NumLumps; + NextLumpIndex_NoExt[i] = FirstLumpIndex_NoExt[j]; + FirstLumpIndex_NoExt[j] = i; + } } } diff --git a/src/w_wad.h b/src/w_wad.h index 9f33ac2c1..30d73d33e 100644 --- a/src/w_wad.h +++ b/src/w_wad.h @@ -135,7 +135,7 @@ public: inline int GetNumForName (const uint8_t *name) { return GetNumForName ((const char *)name); } inline int GetNumForName (const uint8_t *name, int ns) { return GetNumForName ((const char *)name, ns); } - int CheckNumForFullName (const char *name, bool trynormal = false, int namespc = ns_global); + int CheckNumForFullName (const char *name, bool trynormal = false, int namespc = ns_global, bool ignoreext = false); int CheckNumForFullName (const char *name, int wadfile); int GetNumForFullName (const char *name); @@ -194,6 +194,9 @@ protected: uint32_t *FirstLumpIndex_FullName; // The same information for fully qualified paths from .zips uint32_t *NextLumpIndex_FullName; + uint32_t *FirstLumpIndex_NoExt; // The same information for fully qualified paths from .zips + uint32_t *NextLumpIndex_NoExt; + uint32_t NumLumps; // Not necessarily the same as LumpInfo.Size() uint32_t NumWads;