/* ** gltexture.cpp ** The texture classes for hardware rendering ** (Even though they are named 'gl' there is nothing hardware dependent ** in this file. That is all encapsulated in the GLTexture class.) ** **--------------------------------------------------------------------------- ** Copyright 2004-2005 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. ** 4. When not used as part of GZDoom or a GZDoom derivative, this code will be ** covered by the terms of the GNU Lesser General Public License as published ** by the Free Software Foundation; either version 2.1 of the License, or (at ** your option) any later version. ** ** THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR ** IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES ** OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. ** IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, ** INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT ** NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, ** DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY ** THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT ** (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF ** THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. **--------------------------------------------------------------------------- ** */ #include "gl/gl_include.h" #include "w_wad.h" #include "m_png.h" #include "r_draw.h" #include "sbar.h" #include "gi.h" #include "cmdlib.h" #include "stats.h" #include "r_main.h" #include "templates.h" #include "sc_man.h" #include "r_translate.h" #include "colormatcher.h" #include "gl/gl_struct.h" #include "gl/gl_framebuffer.h" #include "gl/gl_texture.h" #include "gl/gl_functions.h" #include "gl/gl_shader.h" #include "gl/gl_translate.h" #include "gl/glsl_state.h" CUSTOM_CVAR(Bool, gl_warp_shader, false, CVAR_ARCHIVE|CVAR_GLOBALCONFIG|CVAR_NOINITCALL) { if (self && !(gl.flags & RFL_GLSL)) self=0; } CUSTOM_CVAR(Bool, gl_fog_shader, false, CVAR_ARCHIVE|CVAR_GLOBALCONFIG|CVAR_NOINITCALL) { if (self && !(gl.flags & RFL_GLSL)) self=0; } CUSTOM_CVAR(Bool, gl_colormap_shader, false, CVAR_ARCHIVE|CVAR_GLOBALCONFIG|CVAR_NOINITCALL) { if (self && !(gl.flags & RFL_GLSL)) self=0; } CUSTOM_CVAR(Bool, gl_brightmap_shader, false, CVAR_ARCHIVE|CVAR_GLOBALCONFIG|CVAR_NOINITCALL) { if (self && !(gl.flags & RFL_GLSL)) self=0; } // Only for testing for now. This isn't working fully yet. CUSTOM_CVAR(Bool, gl_glsl_renderer, false, CVAR_ARCHIVE|CVAR_GLOBALCONFIG|CVAR_NOINITCALL) { if (!(gl.flags & RFL_GLSL)) { if (self) self=0; } else { GLShader::Unbind(); FGLTexture::FlushAll(); } } CUSTOM_CVAR(Bool, gl_texture_usehires, true, CVAR_ARCHIVE|CVAR_NOINITCALL) { FGLTexture::FlushAll(); } EXTERN_CVAR(Bool, gl_render_precise) EXTERN_CVAR(Bool, gl_depthfog) CVAR(Bool, gl_precache, false, CVAR_ARCHIVE) static bool HasGlobalBrightmap; static FRemapTable GlobalBrightmap; //=========================================================================== // // Examines the colormap to see if some of the colors have to be // considered fullbright all the time. // //=========================================================================== void gl_GenerateGlobalBrightmapFromColormap() { FMemLump cmap = Wads.ReadLump("COLORMAP"); FMemLump palette = Wads.ReadLump("PLAYPAL"); const unsigned char *cmapdata = (const unsigned char *)cmap.GetMem(); const unsigned char *paldata = (const unsigned char *)palette.GetMem(); 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(0,0,0); } } } for(int i=0;i<256;i++) { HasGlobalBrightmap |= GlobalBrightmap.Remap[i] == black; //if (GlobalBrightmap[i]) Printf("Marked color %d as fullbright\n",i); } } //=========================================================================== // // multi-format pixel copy with colormap application // requires one of the previously defined conversion classes to work // //=========================================================================== template void iCopyColors(unsigned char * pout, const unsigned char * pin, int cm, int count, int step) { int i; int fac; switch(cm) { case CM_DEFAULT: for(i=0;i>4; pout[0] = IcePalette[gray][0]; pout[1] = IcePalette[gray][1]; pout[2] = IcePalette[gray][2]; pout[3] = 255; pout+=4; pin+=step; } break; case CM_SHADE: // Alpha shade uses the red channel for true color pics for(i=0;i, iCopyColors, iCopyColors, iCopyColors, iCopyColors, iCopyColors, iCopyColors, iCopyColors, iCopyColors }; //=========================================================================== // // True Color texture copy function // This excludes all the cases that force downconversion to the // base palette because they wouldn't be used anyway. // //=========================================================================== void FGLBitmap::CopyPixelDataRGB(int originx, int originy, const BYTE * patch, int srcwidth, int srcheight, int step_x, int step_y, int rotate, int ct, FCopyInfo *inf) { if (ClipCopyPixelRect(Width, Height, originx, originy, patch, srcwidth, srcheight, step_x, step_y, rotate)) { BYTE *buffer = GetPixels() + 4*originx + Pitch*originy; for (int y=0;y> 8; gl_InverseMap(gray, pout[i].r, pout[i].g, pout[i].b); pout[i].a = pin[i].a; } break; case CM_GOLDMAP: // Heretic's golden invulnerability map for(i=0;i> 8; gl_GoldMap(gray, pout[i].r, pout[i].g, pout[i].b); pout[i].a = pin[i].a; } break; case CM_REDMAP: // Skulltag's red Doomsphere map for(i=0;i> 8; gl_RedMap(gray, pout[i].r, pout[i].g, pout[i].b); pout[i].a = pin[i].a; } break; case CM_GREENMAP: // Skulltags's Guardsphere map for(i=0;i> 8; gl_GreenMap(gray, pout[i].r, pout[i].g, pout[i].b); pout[i].a = pin[i].a; } break; case CM_GRAY: // this is used for colorization of blood. // To get the best results the brightness is taken from // the most intense component and not averaged because that would be too dark. for(i=0;i>12; pout[i].r = IcePalette[gray][0]; pout[i].g = IcePalette[gray][1]; pout[i].b = IcePalette[gray][2]; pout[i].a = pin[i].a; } break; default: // Boom colormaps. if (cm>=CM_FIRSTCOLORMAP && cm>8; gl_Desaturate(gray, pin[i].r, pin[i].g, pin[i].b, pout[i].r, pout[i].g, pout[i].b, fac); pout[i].a = pin[i].a; } } else if (pin!=pout) { memcpy(pout, pin, count * sizeof(PalEntry)); } break; } } //=========================================================================== // // Paletted to True Color texture copy function // //=========================================================================== void FGLBitmap::CopyPixelData(int originx, int originy, const BYTE * patch, int srcwidth, int srcheight, int step_x, int step_y, int rotate, PalEntry * palette, FCopyInfo *inf) { PalEntry penew[256]; int x,y,pos,i; if (ClipCopyPixelRect(Width, Height, originx, originy, patch, srcwidth, srcheight, step_x, step_y, rotate)) { BYTE *buffer = GetPixels() + 4*originx + Pitch*originy; // CM_SHADE is an alpha map with 0==transparent and 1==opaque if (cm == CM_SHADE) { for(int i=0;i<256;i++) { if (palette[i].a != 0) penew[i]=PalEntry(i, 255,255,255); else penew[i]=PalEntry(0,255,255,255); // If the palette contains transparent colors keep them. } } else { // apply any translation. // The ice and blood color translations are done directly // because that yields better results. switch(translation) { case CM_GRAY: ModifyPalette(penew, palette, CM_GRAY, 256); break; case CM_ICE: ModifyPalette(penew, palette, CM_ICE, 256); break; default: { PalEntry *ptrans = GLTranslationPalette::GetPalette(translation); if (ptrans) { for(i = 0; i < 256; i++) { penew[i] = (ptrans[i]&0xffffff) | (palette[i]&0xff000000); } break; } } case 0: memcpy(penew, palette, 256*sizeof(PalEntry)); break; } if (cm!=0) { // Apply color modifications like invulnerability, desaturation and Boom colormaps ModifyPalette(penew, penew, cm, 256); } } // Now penew contains the actual palette that is to be used for creating the image. // convert the image according to the translated palette. // Please note that the alpha of the passed palette is inverted. This is // so that the base palette can be used without constantly changing it. // This can also handle full PNG translucency. for (y=0;y(buffer[pos+3] + (( 255-buffer[pos+3]) * (255-penew[v].a))/255, 0, 255); } */ } } } } //=========================================================================== // // Camera texture rendering // //=========================================================================== void FCanvasTexture::RenderGLView (AActor *viewpoint, int fov) { gl_RenderTextureView(this, viewpoint, fov); bNeedsUpdate = false; bDidUpdate = true; bFirstUpdate = false; } //========================================================================== // // Precaches a GL texture // //========================================================================== void FTexture::PrecacheGL() { if (gl_precache) { FGLTexture * gltex = FGLTexture::ValidateTexture(this); if (gltex) { if (UseType==FTexture::TEX_Sprite) { gltex->BindPatch(CM_DEFAULT); } else { gltex->Bind (CM_DEFAULT, 0, 0, true); } } } } //========================================================================== // // Precaches a GL texture // //========================================================================== void FTexture::UncacheGL() { if (Native) { FGLTexture * gltex = FGLTexture::ValidateTexture(this); if (gltex) gltex->Clean(true); } } //=========================================================================== // // fake brightness maps // These are generated for textures affected by a colormap with // fullbright entries. // These textures are only used internally by the GL renderer so // all code for software rendering support is missing // //=========================================================================== FBrightmapTexture::FBrightmapTexture (FTexture *source) { memcpy(Name, source->Name, 9); SourcePic = source; CopySize(source); bNoDecals = source->bNoDecals; Rotations = source->Rotations; UseType = source->UseType; } FBrightmapTexture::~FBrightmapTexture () { Unload(); } const BYTE *FBrightmapTexture::GetColumn (unsigned int column, const Span **spans_out) { // not needed return NULL; } const BYTE *FBrightmapTexture::GetPixels () { // not needed return NULL; } void FBrightmapTexture::Unload () { } int FBrightmapTexture::CopyTrueColorPixels(FBitmap *bmp, int x, int y, int rotate, FCopyInfo *inf) { SourcePic->CopyTrueColorTranslated(bmp, x, y, rotate, &GlobalBrightmap); return 0; } //=========================================================================== // // The GL texture maintenance class // //=========================================================================== TArray FGLTexture::gltextures; //=========================================================================== // // Constructor // //=========================================================================== FGLTexture::FGLTexture(FTexture * tx) { tex = tx; glpatch=NULL; gltexture=NULL; Shader = NULL; HiresLump=-1; hirestexture = NULL; areacount = 0; areas = NULL; createWarped = false; bHasColorkey = false; for (int i=GLUSE_PATCH; i<=GLUSE_TEXTURE; i++) { Width[i] = tex->GetWidth(); Height[i] = tex->GetHeight(); LeftOffset[i] = tex->LeftOffset; TopOffset[i] = tex->TopOffset; RenderWidth[i] = tex->GetScaledWidth(); RenderHeight[i] = tex->GetScaledHeight(); } scalex = tex->xScale/(float)FRACUNIT; scaley = tex->yScale/(float)FRACUNIT; // a little adjustment to make sprites look better with texture filtering: // create a 1 pixel wide empty frame around them. if (tex->UseType == FTexture::TEX_Sprite || tex->UseType == FTexture::TEX_SkinSprite || tex->UseType == FTexture::TEX_Decal) { RenderWidth[GLUSE_PATCH]+=2; RenderHeight[GLUSE_PATCH]+=2; Width[GLUSE_PATCH]+=2; Height[GLUSE_PATCH]+=2; LeftOffset[GLUSE_PATCH]+=1; TopOffset[GLUSE_PATCH]+=1; } if ((gl.flags & RFL_GLSL) && tx->UseBasePalette() && HasGlobalBrightmap && tx->UseType != FTexture::TEX_Autopage && tx->UseType != FTexture::TEX_Decal && tx->UseType != FTexture::TEX_MiscPatch && tx->UseType != FTexture::TEX_FontChar && tex->bm_info.Brightmap == NULL && tx->bWarped == 0 ) { tex->bm_info.Brightmap = new FBrightmapTexture(tx); tex->bm_info.Brightmap->bm_info.bIsBrightmap=-1; } bIsTransparent = -1; if (tex->bHasCanvas) scaley=-scaley; index = gltextures.Push(this); } //=========================================================================== // // Destructor // //=========================================================================== FGLTexture::~FGLTexture() { Clean(true); if (areas) delete [] areas; if (hirestexture) delete hirestexture; for(unsigned i=0;ileft=-(float)GetScaledLeftOffset(i); r->top=-(float)GetScaledTopOffset(i); r->width=(float)TextureWidth(i); r->height=(float)TextureHeight(i); } //=========================================================================== // // 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 FGLTexture::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 (areacount) return false; if (tex->UseType==FTexture::TEX_Flat) return false; // flats don't have transparent parts areacount=-1; //whatever happens next, it shouldn't be done twice! // large textures are excluded for performance reasons if (h>256) return false; startdraw=-1; lendraw=0; for(y=0;ybm_info.bIsBrightmap==-1) { DWORD * dwbuf = (DWORD*)buffer; for(int i=0;ibm_info.bIsBrightmap = 1; break; } } if (tex->bm_info.bIsBrightmap == -1) { tex->bm_info.bIsBrightmap = 0; return false; } } else if (tex->bMasked && !tex->bm_info.bIsBrightmap) { tex->bMasked=SmoothEdges(buffer, w, h, ispatch); if (tex->bMasked && !ispatch) FindHoles(buffer, w, h); } return true; } //=========================================================================== // // Checks for transparent pixels if there is no simpler means to get // this information // //=========================================================================== void FGLTexture::CheckTrans(unsigned char * buffer, int size, int trans) { if (bIsTransparent == -1) { bIsTransparent = trans; if (trans == -1) { DWORD * dwbuf = (DWORD*)buffer; if (bIsTransparent == -1) for(int i=0;i>24; if (alpha != 0xff && alpha != 0) { bIsTransparent = 1; return; } } } bIsTransparent = 0; } } //=========================================================================== // // Deletes all allocated resources // //=========================================================================== void FGLTexture::Clean(bool all) { WorldTextureInfo::Clean(all); PatchTextureInfo::Clean(all); createWarped = false; } //=========================================================================== // // FGLTexture::WarpBuffer // //=========================================================================== BYTE *FGLTexture::WarpBuffer(BYTE *buffer, int Width, int Height, int warp) { DWORD *in = (DWORD*)buffer; DWORD *out = (DWORD*)new BYTE[4*Width*Height]; float Speed = static_cast(tex)->GetSpeed(); static_cast(tex)->GenTime = r_FrameTime; static DWORD linebuffer[256]; // anything larger will bring down performance so it is excluded above. DWORD timebase = DWORD(r_FrameTime*Speed*23/28); int xsize = Width; int ysize = Height; int xmask = xsize - 1; int ymask = ysize - 1; int ds_xbits; int i,x; if (warp == 1) { for(ds_xbits=-1,i=Width; i; i>>=1, ds_xbits++); for (x = xsize-1; x >= 0; x--) { int yt, yf = (finesine[(timebase+(x+17)*128)&FINEMASK]>>13) & ymask; const DWORD *source = in + x; DWORD *dest = out + x; for (yt = ysize; yt; yt--, yf = (yf+1)&ymask, dest += xsize) { *dest = *(source+(yf<= 0; y--) { int xt, xf = (finesine[(timebase+y*128)&FINEMASK]>>13) & xmask; DWORD *source = out + (y<>=1, ybits++); DWORD timebase = (r_FrameTime * Speed * 40 / 28); for (x = xsize-1; x >= 0; x--) { for (int y = ysize-1; y >= 0; y--) { int xt = (x + 128 + ((finesine[(y*128 + timebase*5 + 900) & 8191]*2)>>FRACBITS) + ((finesine[(x*256 + timebase*4 + 300) & 8191]*2)>>FRACBITS)) & xmask; int yt = (y + 128 + ((finesine[(y*128 + timebase*3 + 700) & 8191]*2)>>FRACBITS) + ((finesine[(x*256 + timebase*4 + 1200) & 8191]*2)>>FRACBITS)) & ymask; const DWORD *source = in + (xt << ybits) + yt; DWORD *dest = out + (x << ybits) + y; *dest = *source; } } } delete [] buffer; return (BYTE*)out; } //=========================================================================== // // Initializes the buffer for the texture data // //=========================================================================== unsigned char * FGLTexture::CreateTexBuffer(ETexUse use, int _cm, int translation, int & w, int & h, bool allowhires) { unsigned char * buffer; intptr_t cm = _cm; int W, H; // Textures that are already scaled in the texture lump will not get replaced // by hires textures if (gl_texture_usehires && allowhires && scalex==1.f && scaley==1.f) { buffer = LoadHiresTexture (&w, &h, _cm); if (buffer) { return buffer; } } W = w = Width[use]; H = h = Height[use]; buffer=new unsigned char[W*(H+1)*4]; memset(buffer, 0, W * (H+1) * 4); FGLBitmap bmp(buffer, W*4, W, H); bmp.SetTranslationInfo(cm, translation); if (tex->bComplex) { FBitmap imgCreate; // The texture contains special processing so it must be composited using with the // base bitmap class and then be converted as a whole. if (imgCreate.Create(W, H)) { memset(imgCreate.GetPixels(), 0, W * H * 4); int trans = tex->CopyTrueColorPixels(&imgCreate, GetLeftOffset(use) - tex->LeftOffset, GetTopOffset(use) - tex->TopOffset); bmp.CopyPixelDataRGB(0, 0, imgCreate.GetPixels(), W, H, 4, W * 4, 0, CF_BGRA); CheckTrans(buffer, W*H, trans); } } else if (translation<=0) { int trans = tex->CopyTrueColorPixels(&bmp, GetLeftOffset(use) - tex->LeftOffset, GetTopOffset(use) - tex->TopOffset); CheckTrans(buffer, W*H, trans); } else { // When using translations everything must be mapped to the base palette. // Since FTexture's method is doing exactly that by calling GetPixels let's use that here // to do all the dirty work for us. ;) tex->FTexture::CopyTrueColorPixels(&bmp, GetLeftOffset(use) - tex->LeftOffset, GetTopOffset(use) - tex->TopOffset); } if ((!(gl.flags & RFL_GLSL) || !gl_warp_shader) && tex->bWarped && W <= 256 && H <= 256) { buffer = WarpBuffer(buffer, W, H, tex->bWarped); createWarped = true; } return buffer; } //=========================================================================== // // Gets texture coordinate info for world (wall/flat) textures // The wrapper class is there to provide a set of coordinate // functions to access the texture // //=========================================================================== const WorldTextureInfo * FGLTexture::GetWorldTextureInfo() { if (tex->UseType==FTexture::TEX_Null) return NULL; // Cannot register a NULL texture! if (!gltexture) gltexture=new GLTexture(Width[GLUSE_TEXTURE], Height[GLUSE_TEXTURE], true, true); if (gltexture) return (WorldTextureInfo*)this; return NULL; } //=========================================================================== // // Gets texture coordinate info for sprites // The wrapper class is there to provide a set of coordinate // functions to access the texture // //=========================================================================== const PatchTextureInfo * FGLTexture::GetPatchTextureInfo() { if (tex->UseType==FTexture::TEX_Null) return NULL; // Cannot register a NULL texture! if (!glpatch) { glpatch=new GLTexture(Width[GLUSE_PATCH], Height[GLUSE_PATCH], false, false); } if (glpatch) return (PatchTextureInfo*)this; return NULL; } //=========================================================================== // // Binds a texture to the renderer // //=========================================================================== const WorldTextureInfo * FGLTexture::Bind(int texunit, int cm, int clampmode, int translation, bool is2d) { bool usebright = false; translation = GLTranslationPalette::GetInternalTranslation(translation); if (GetWorldTextureInfo()) { if (texunit == 0) { FTexture *brightmap = tex->bm_info.Brightmap; if (brightmap && (gl_glsl_renderer || (gl_brightmap_shader && !is2d)) && translation >= 0 && cm >= CM_DEFAULT && cm <= CM_DESAT31 && gl_brightmapenabled) { FGLTexture *bmgltex = FGLTexture::ValidateTexture(brightmap); bmgltex->Bind(1, CM_DEFAULT, clampmode, 0); if (brightmap->bm_info.bIsBrightmap == 0) { delete brightmap; tex->bm_info.Brightmap = NULL; } else usebright = true; } if (!gl_glsl_renderer) { if (gl.flags & RFL_GLSL) { if (createWarped && gl_warp_shader && tex->bWarped!=0) { Clean(true); GetWorldTextureInfo(); } if ((gl_warp_shader && tex->bWarped!=0) || (gl_fog_shader && !is2d && gl_depthfog) || (usebright) || ((tex->bHasCanvas || gl_colormap_shader) && cm!=CM_DEFAULT && /*!(cm>=CM_DESAT1 && cm<=CM_DESAT31) &&*/ cm!=CM_SHADE && gl_texturemode != TM_MASK)) { Shader->Bind(cm, usebright, tex->bWarped? static_cast(tex)->GetSpeed() : 0.f); if (cm != CM_SHADE) cm = CM_DEFAULT; } else { GLShader::Unbind(); } } if (tex->bWarped == 0 || !gl_warp_shader) { // If this is a warped texture that needs updating // delete all system textures created for this if (tex->CheckModified() && !tex->bHasCanvas && HiresLump<0 && HiresLump!=-2) { gltexture->Clean(true); } } } else { glsl->SetBrightmap(usebright); glsl->SetWarp(tex->bWarped, static_cast(tex)->GetSpeed()); if (cm != CM_SHADE) cm = CM_DEFAULT; } } // Bind it to the system. // clamping in x-direction may cause problems when rendering segs if (!gltexture->Bind(texunit, cm, translation, gl_render_precise? clampmode&GLT_CLAMPY : clampmode)) { int w,h; // Create this texture unsigned char * buffer = CreateTexBuffer(GLUSE_TEXTURE, cm, translation, w, h); ProcessData(buffer, w, h, cm, false); if (!gltexture->CreateTexture(buffer, w, h, true, texunit, cm, translation)) { // could not create texture delete buffer; return NULL; } delete buffer; } if (texunit == 0) gltexture->SetTextureClamp(gl_render_precise? clampmode&GLT_CLAMPY : clampmode); if (tex->bHasCanvas) static_cast(tex)->NeedUpdate(); return (WorldTextureInfo*)this; } return NULL; } const WorldTextureInfo * FGLTexture::Bind(int cm, int clampmode, int translation, bool is2d) { return Bind(0, cm, clampmode, translation, is2d); } //=========================================================================== // // Binds a sprite to the renderer // //=========================================================================== const PatchTextureInfo * FGLTexture::BindPatch(int texunit, int cm, int translation) { bool usebright = false; int transparm = translation; translation = GLTranslationPalette::GetInternalTranslation(translation); if (GetPatchTextureInfo()) { if (texunit == 0) { FTexture *brightmap = tex->bm_info.Brightmap; if (brightmap && (gl_glsl_renderer || gl_brightmap_shader) && translation >= 0 && transparm >= 0 && cm >= CM_DEFAULT && cm <= CM_DESAT31 && gl_brightmapenabled) { FGLTexture *bmgltex = FGLTexture::ValidateTexture(brightmap); bmgltex->BindPatch(1, CM_DEFAULT, 0); if (brightmap->bm_info.bIsBrightmap == 0) { delete brightmap; tex->bm_info.Brightmap = NULL; } else { usebright = true; } } if (!gl_glsl_renderer) { if (gl.flags & RFL_GLSL) { if (createWarped && gl_warp_shader && tex->bWarped!=0) { Clean(true); GetPatchTextureInfo(); } if ((gl_warp_shader && tex->bWarped!=0) || (usebright) || ((tex->bHasCanvas || gl_colormap_shader) && cm!=CM_DEFAULT && /*!(cm>=CM_DESAT1 && cm<=CM_DESAT31) &&*/ cm!=CM_SHADE && gl_texturemode != TM_MASK)) { Shader->Bind(cm, usebright, tex->bWarped? static_cast(tex)->GetSpeed() : 0.f); if (cm != CM_SHADE) cm = CM_DEFAULT; } else { GLShader::Unbind(); } } if (tex->bWarped == 0 || !gl_warp_shader) { // If this is a warped texture that needs updating // delete all system textures created for this if (tex->CheckModified() && !tex->bHasCanvas && HiresLump<0 && HiresLump!=-2) { glpatch->Clean(true); } } } else { glsl->SetBrightmap(usebright); glsl->SetWarp(tex->bWarped, static_cast(tex)->GetSpeed()); if (cm != CM_SHADE) cm = CM_DEFAULT; } } // Bind it to the system. For multitexturing this // should be the only thing that needs adjusting if (!glpatch->Bind(texunit, cm, translation, -1)) { int w, h; // Create this texture unsigned char * buffer = CreateTexBuffer(GLUSE_PATCH, cm, translation, w, h, false); ProcessData(buffer, w, h, cm, true); if (!glpatch->CreateTexture(buffer, w, h, false, texunit, cm, translation)) { // could not create texture delete buffer; return NULL; } delete buffer; } if (gl_render_precise) { gl.TexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE); gl.TexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE); } return (PatchTextureInfo*)this; } return NULL; } const PatchTextureInfo * FGLTexture::BindPatch(int cm, int translation) { return BindPatch(0, cm, translation); } //========================================================================== // // Flushes all hardware dependent data // //========================================================================== void FGLTexture::FlushAll() { for(int i=gltextures.Size()-1;i>=0;i--) { gltextures[i]->Clean(true); } } //========================================================================== // // Deletes all hardware dependent data // //========================================================================== void FGLTexture::DeleteAll() { for(int i=gltextures.Size()-1;i>=0;i--) { gltextures[i]->tex->KillNative(); } gltextures.Clear(); } //========================================================================== // // Gets a texture from the texture manager and checks its validity for // GL rendering. // //========================================================================== FGLTexture * FGLTexture::ValidateTexture(FTexture * tex) { if (tex && tex->UseType!=FTexture::TEX_Null) { FGLTexture *gltex = static_cast(tex->GetNative(false)); if (gltex) { // This can't be put in the constructor because many // textures are created before the GL renderer is operable if ((gl.flags & RFL_GLSL) && !gltex->Shader) switch(tex->bWarped) { default: gltex->Shader = GLShader::Find("Default"); break; case 1: gltex->Shader = GLShader::Find("Warp 1"); break; case 2: gltex->Shader = GLShader::Find("Warp 2"); break; } } return gltex; } return NULL; } FGLTexture * FGLTexture::ValidateTexture(FTextureID no, bool translate) { return FGLTexture::ValidateTexture(translate? TexMan(no) : TexMan[no]); } //========================================================================== // // Parses a brightmap definition // //========================================================================== void gl_ParseBrightmap(FScanner &sc, int deflump) { int type = FTexture::TEX_Any; bool disable_fullbright=false; bool thiswad = false; bool iwad = false; int maplump = -1; FString maplumpname; sc.MustGetString(); if (sc.Compare("texture")) type = FTexture::TEX_Wall; else if (sc.Compare("flat")) type = FTexture::TEX_Flat; else if (sc.Compare("sprite")) type = FTexture::TEX_Sprite; else sc.UnGet(); sc.MustGetString(); FTextureID no = TexMan.CheckForTexture(sc.String, type); FTexture *tex = TexMan[no]; sc.MustGetToken('{'); while (!sc.CheckToken('}')) { sc.MustGetString(); if (sc.Compare("disablefullbright")) { // This can also be used without a brightness map to disable // fullbright in rotations that only use brightness maps on // other angles. disable_fullbright = true; } else if (sc.Compare("thiswad")) { // only affects textures defined in the WAD containing the definition file. thiswad = true; } else if (sc.Compare ("iwad")) { // only affects textures defined in the IWAD. iwad = true; } else if (sc.Compare ("map")) { sc.MustGetString(); if (maplump >= 0) { Printf("Multiple brightmap definitions in texture %s\n", tex? tex->Name : "(null)"); } maplump = Wads.CheckNumForFullName(sc.String); // Try a normal WAD name lookup only if it's a proper name without path separator and // not longer than 8 characters. if (maplump==-1 && strlen(sc.String) <= 8 && !strchr(sc.String, '/')) maplump = Wads.CheckNumForName(sc.String); if (maplump==-1) Printf("Brightmap '%s' not found in texture '%s'\n", sc.String, tex? tex->Name : "(null)"); maplumpname = sc.String; } } if (!tex) { return; } if (thiswad || iwad) { bool useme = false; int lumpnum = tex->GetSourceLump(); if (lumpnum != -1) { if (iwad && Wads.GetLumpFile(lumpnum) <= FWadCollection::IWAD_FILENUM) useme = true; if (thiswad && Wads.GetLumpFile(lumpnum) == deflump) useme = true; } if (!useme) return; } if (maplump != -1) { FTexture *brightmap = FTexture::CreateTexture(maplump, tex->UseType); if (!brightmap) { Printf("Unable to create texture from '%s' in brightmap definition for '%s'\n", maplumpname.GetChars(), tex->Name); return; } tex->bm_info.Brightmap = brightmap; brightmap->bm_info.bIsBrightmap = true; } tex->bm_info.bBrightmapDisablesFullbright = disable_fullbright; }