- changed the handling of alpha textures. The only special case they need is with palette-less textures and this can be handled far more easily and robustly with a predefined translation instead of passing another parameter through all the layers of the texture management code. This also fixes problems with paletted PNGs that get used as an alpha texture because the old method clobbered the image's palette.

This commit is contained in:
Christoph Oelckers 2014-09-09 13:21:36 +02:00
parent 4bb320a27c
commit acf6c259d8
12 changed files with 75 additions and 93 deletions

View file

@ -142,7 +142,11 @@ void gl_GetRenderStyle(FRenderStyle style, bool drawopaque, bool allowcolorblend
int blendequation = renderops[style.BlendOp&15];
int texturemode = drawopaque? TM_OPAQUE : TM_MODULATE;
if (style.Flags & STYLEF_ColorIsFixed)
if (style.Flags & STYLEF_RedIsAlpha)
{
texturemode = TM_REDTOALPHA;
}
else if (style.Flags & STYLEF_ColorIsFixed)
{
texturemode = TM_MASK;
}

View file

@ -8,6 +8,7 @@
#include "gl/textures/gl_material.h"
#include "c_cvars.h"
#include "r_defs.h"
#include "r_data/r_translate.h"
class FVertexBuffer;
class FShader;
@ -100,9 +101,16 @@ public:
void SetMaterial(FMaterial *mat, int clampmode, int translation, int overrideshader, bool alphatexture)
{
// textures without their own palette are a special case for use as an alpha texture:
// They use the color index directly as an alpha value instead of using the palette's red.
// To handle this case, we need to set a special translation for such textures.
if (alphatexture)
{
if (mat->tex->UseBasePalette()) translation = TRANSLATION(TRANSLATION_Standard, 8);
}
mEffectState = overrideshader >= 0? overrideshader : mat->mShaderIndex;
mShaderTimer = mat->tex->gl_info.shaderspeed;
mat->Bind(clampmode, translation, alphatexture);
mat->Bind(clampmode, translation);
}
void Apply();

View file

@ -16,9 +16,10 @@ enum RenderFlags
enum TexMode
{
TM_MODULATE = 0, // (r, g, b, a)
TM_MASK = 1, // (1, 1, 1, a)
TM_OPAQUE = 2, // (r, g, b, 1)
TM_INVERSE = 3, // (1-r, 1-g, 1-b, a)
TM_MASK, // (1, 1, 1, a)
TM_OPAQUE, // (r, g, b, 1)
TM_INVERSE, // (1-r, 1-g, 1-b, a)
TM_REDTOALPHA, // (1, 1, 1, r)
};
struct RenderContext

View file

@ -148,11 +148,11 @@ bool OpenGLFrameBuffer::WipeStartScreen(int type)
}
wipestartscreen = new FHardwareTexture(Width, Height, true);
wipestartscreen->CreateTexture(NULL, Width, Height, 0, false, 0, false);
wipestartscreen->CreateTexture(NULL, Width, Height, 0, false, 0);
GLRenderer->mSamplerManager->Bind(0, CLAMP_NOFILTER);
GLRenderer->mSamplerManager->Bind(1, CLAMP_NONE);
glFinish();
wipestartscreen->Bind(0, false, false, false);
wipestartscreen->Bind(0, false, false);
glCopyTexSubImage2D(GL_TEXTURE_2D, 0, 0, 0, 0, 0, Width, Height);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE);
@ -171,10 +171,10 @@ bool OpenGLFrameBuffer::WipeStartScreen(int type)
void OpenGLFrameBuffer::WipeEndScreen()
{
wipeendscreen = new FHardwareTexture(Width, Height, true);
wipeendscreen->CreateTexture(NULL, Width, Height, 0, false, 0, false);
wipeendscreen->CreateTexture(NULL, Width, Height, 0, false, 0);
GLRenderer->mSamplerManager->Bind(0, CLAMP_NOFILTER);
glFinish();
wipeendscreen->Bind(0, false, false, false);
wipeendscreen->Bind(0, false, false);
glCopyTexSubImage2D(GL_TEXTURE_2D, 0, 0, 0, 0, 0, Width, Height);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST);
@ -286,7 +286,7 @@ bool OpenGLFrameBuffer::Wiper_Crossfade::Run(int ticks, OpenGLFrameBuffer *fb)
gl_RenderState.AlphaFunc(GL_GEQUAL, 0.f);
gl_RenderState.ResetColor();
gl_RenderState.Apply();
fb->wipestartscreen->Bind(0, 0, false, false);
fb->wipestartscreen->Bind(0, 0, false);
FFlatVertex *ptr;
unsigned int offset, count;
@ -301,7 +301,7 @@ bool OpenGLFrameBuffer::Wiper_Crossfade::Run(int ticks, OpenGLFrameBuffer *fb)
ptr++;
GLRenderer->mVBO->RenderCurrent(ptr, GL_TRIANGLE_STRIP, &offset, &count);
fb->wipeendscreen->Bind(0, 0, false, false);
fb->wipeendscreen->Bind(0, 0, false);
gl_RenderState.SetColorAlpha(0xffffff, clamp(Clock/32.f, 0.f, 1.f));
gl_RenderState.Apply();
GLRenderer->mVBO->RenderArray(GL_TRIANGLE_STRIP, offset, count);
@ -348,7 +348,7 @@ bool OpenGLFrameBuffer::Wiper_Melt::Run(int ticks, OpenGLFrameBuffer *fb)
gl_RenderState.SetTextureMode(TM_OPAQUE);
gl_RenderState.ResetColor();
gl_RenderState.Apply();
fb->wipeendscreen->Bind(0, 0, false, false);
fb->wipeendscreen->Bind(0, 0, false);
FFlatVertex *ptr;
ptr = GLRenderer->mVBO->GetBuffer();
ptr->Set(0, 0, 0, 0, vb);
@ -364,7 +364,7 @@ bool OpenGLFrameBuffer::Wiper_Melt::Run(int ticks, OpenGLFrameBuffer *fb)
int i, dy;
bool done = false;
fb->wipestartscreen->Bind(0, 0, false, false);
fb->wipestartscreen->Bind(0, 0, false);
// Copy the old screen in vertical strips on top of the new one.
while (ticks--)
{
@ -496,7 +496,7 @@ bool OpenGLFrameBuffer::Wiper_Burn::Run(int ticks, OpenGLFrameBuffer *fb)
gl_RenderState.AlphaFunc(GL_GEQUAL, 0.f);
gl_RenderState.ResetColor();
gl_RenderState.Apply();
fb->wipestartscreen->Bind(0, 0, false, false);
fb->wipestartscreen->Bind(0, 0, false);
FFlatVertex *ptr;
unsigned int offset, count;
ptr = GLRenderer->mVBO->GetBuffer();
@ -516,9 +516,9 @@ bool OpenGLFrameBuffer::Wiper_Burn::Run(int ticks, OpenGLFrameBuffer *fb)
gl_RenderState.Apply();
// Burn the new screen on top of it.
fb->wipeendscreen->Bind(0, 0, false, false);
fb->wipeendscreen->Bind(0, 0, false);
BurnTexture->CreateTexture(rgb_buffer, WIDTH, HEIGHT, 1, true, 0, false);
BurnTexture->CreateTexture(rgb_buffer, WIDTH, HEIGHT, 1, true, 0);
GLRenderer->mVBO->RenderArray(GL_TRIANGLE_STRIP, offset, count);
gl_RenderState.SetEffect(EFF_NONE);

View file

@ -51,7 +51,7 @@
//
//===========================================================================
template<class T>
void iCopyColors(unsigned char * pout, const unsigned char * pin, bool alphatex, int count, int step)
void iCopyColors(unsigned char * pout, const unsigned char * pin, int count, int step)
{
int i;
@ -69,7 +69,7 @@ void iCopyColors(unsigned char * pout, const unsigned char * pin, bool alphatex,
}
}
typedef void (*CopyFunc)(unsigned char * pout, const unsigned char * pin, bool alphatex, int count, int step);
typedef void (*CopyFunc)(unsigned char * pout, const unsigned char * pin, int count, int step);
static CopyFunc copyfuncs[]={
iCopyColors<cRGB>,
@ -99,7 +99,7 @@ void FGLBitmap::CopyPixelDataRGB(int originx, int originy,
BYTE *buffer = GetPixels() + 4*originx + Pitch*originy;
for (int y=0;y<srcheight;y++)
{
copyfuncs[ct](&buffer[y*Pitch], &patch[y*step_y], alphatex, srcwidth, step_x);
copyfuncs[ct](&buffer[y*Pitch], &patch[y*step_y], srcwidth, step_x);
}
}
}
@ -120,18 +120,7 @@ void FGLBitmap::CopyPixelData(int originx, int originy, const BYTE * patch, int
{
BYTE *buffer = GetPixels() + 4*originx + Pitch*originy;
// alpha map with 0==transparent and 1==opaque
if (alphatex)
{
for (int i = 0; i<256; i++)
{
if (palette[i].a != 0)
penew[i] = PalEntry(255, i, 255, 255);
else
penew[i] = PalEntry(255, 0, 255, 255); // If the palette contains transparent colors keep them.
}
}
else if (translation > 0)
if (translation > 0)
{
PalEntry *ptrans = GLTranslationPalette::GetPalette(translation);
if (ptrans)

View file

@ -7,34 +7,25 @@
class FGLBitmap : public FBitmap
{
bool alphatex;
int translation;
public:
FGLBitmap()
{
alphatex = false;
translation = 0;
}
FGLBitmap(BYTE *buffer, int pitch, int width, int height)
: FBitmap(buffer, pitch, width, height)
{
alphatex = false;
translation = 0;
}
void SetTranslationInfo(int _trans)
{
if (_trans == -1) alphatex = true;
else if (_trans != -1337) translation = _trans;
if (_trans != -1337) translation = _trans;
}
void SetAlphaTex()
{
alphatex = true;
}
virtual void CopyPixelDataRGB(int originx, int originy, const BYTE *patch, int srcwidth,
int srcheight, int step_x, int step_y, int rotate, int ct, FCopyInfo *inf = NULL);
virtual void CopyPixelData(int originx, int originy, const BYTE * patch, int srcwidth, int srcheight,

View file

@ -184,18 +184,13 @@ void FHardwareTexture::Resize(int width, int height, unsigned char *src_data, un
//
//===========================================================================
unsigned int FHardwareTexture::CreateTexture(unsigned char * buffer, int w, int h, int texunit, bool mipmap, int translation, bool alphatexture)
unsigned int FHardwareTexture::CreateTexture(unsigned char * buffer, int w, int h, int texunit, bool mipmap, int translation)
{
int rh,rw;
int texformat=TexFormat[gl_texture_format];
bool deletebuffer=false;
if (alphatexture)
{
texformat = GL_R8;
translation = TRANS_Alpha;
}
else if (forcenocompression)
if (forcenocompression)
{
texformat = GL_RGBA8;
}
@ -245,11 +240,6 @@ unsigned int FHardwareTexture::CreateTexture(unsigned char * buffer, int w, int
glTex->mipmapped = true;
}
if (alphatexture)
{
static const GLint swizzleMask[] = {GL_ONE, GL_ONE, GL_ONE, GL_RED};
glTexParameteriv(GL_TEXTURE_2D, GL_TEXTURE_SWIZZLE_RGBA, swizzleMask);
}
if (texunit != 0) glActiveTexture(GL_TEXTURE0);
return glTex->glTexID;
}
@ -362,9 +352,8 @@ FHardwareTexture::TranslatedTexture *FHardwareTexture::GetTexID(int translation)
// Binds this patch
//
//===========================================================================
unsigned int FHardwareTexture::Bind(int texunit, int translation, bool alphatexture, bool needmipmap)
unsigned int FHardwareTexture::Bind(int texunit, int translation, bool needmipmap)
{
if (alphatexture) translation = TRANS_Alpha;
TranslatedTexture *pTex = GetTexID(translation);
if (pTex->glTexID != 0)

View file

@ -20,11 +20,6 @@ enum EInvalid
Invalid = 0
};
enum ETranslation
{
TRANS_Alpha = INT_MAX
};
enum
{
GLT_CLAMPX=1,
@ -66,7 +61,6 @@ private:
TArray<TranslatedTexture> glTex_Translated;
unsigned int glDepthID; // only used by camera textures
void LoadImage(unsigned char * buffer,int w, int h, TranslatedTexture *glTex, bool mipmap, bool alphatexture, int texunit);
TranslatedTexture * GetTexID(int translation);
int GetDepthBuffer();
@ -81,8 +75,8 @@ public:
void BindToFrameBuffer();
unsigned int Bind(int texunit, int translation, bool alphatexture, bool needmipmap);
unsigned int CreateTexture(unsigned char * buffer, int w, int h, int texunit, bool mipmap, int translation, bool alphatexture);
unsigned int Bind(int texunit, int translation, bool needmipmap);
unsigned int CreateTexture(unsigned char * buffer, int w, int h, int texunit, bool mipmap, int translation);
void Clean(bool all);
};

View file

@ -109,7 +109,7 @@ FGLTexture::~FGLTexture()
// Checks for the presence of a hires texture replacement and loads it
//
//==========================================================================
unsigned char *FGLTexture::LoadHiresTexture(FTexture *tex, int *width, int *height, bool alphatexture)
unsigned char *FGLTexture::LoadHiresTexture(FTexture *tex, int *width, int *height)
{
if (HiresLump==-1)
{
@ -131,8 +131,6 @@ unsigned char *FGLTexture::LoadHiresTexture(FTexture *tex, int *width, int *heig
memset(buffer, 0, w * (h+1) * 4);
FGLBitmap bmp(buffer, w*4, w, h);
if (alphatexture) bmp.SetAlphaTex();
int trans = hirestexture->CopyTrueColorPixels(&bmp, 0, 0);
hirestexture->CheckTrans(buffer, w*h, trans);
@ -181,7 +179,7 @@ void FGLTexture::Clean(bool all)
//
//===========================================================================
unsigned char * FGLTexture::CreateTexBuffer(int translation, int & w, int & h, FTexture *hirescheck, bool alphatexture)
unsigned char * FGLTexture::CreateTexBuffer(int translation, int & w, int & h, FTexture *hirescheck)
{
unsigned char * buffer;
int W, H;
@ -191,7 +189,7 @@ unsigned char * FGLTexture::CreateTexBuffer(int translation, int & w, int & h, F
// by hires textures
if (gl_texture_usehires && hirescheck != NULL)
{
buffer = LoadHiresTexture (hirescheck, &w, &h, alphatexture);
buffer = LoadHiresTexture (hirescheck, &w, &h);
if (buffer)
{
return buffer;
@ -207,7 +205,6 @@ unsigned char * FGLTexture::CreateTexBuffer(int translation, int & w, int & h, F
FGLBitmap bmp(buffer, W*4, W, H);
bmp.SetTranslationInfo(translation);
if (alphatexture) bmp.SetAlphaTex();
if (tex->bComplex)
{
@ -241,7 +238,7 @@ unsigned char * FGLTexture::CreateTexBuffer(int translation, int & w, int & h, F
// [BB] The hqnx upsampling (not the scaleN one) destroys partial transparency, don't upsamle textures using it.
// [BB] Potentially upsample the buffer.
return gl_CreateUpsampledTextureBuffer ( tex, buffer, W, H, w, h, bIsTransparent || alphatexture);
return gl_CreateUpsampledTextureBuffer ( tex, buffer, W, H, w, h, !!bIsTransparent);
}
@ -267,7 +264,7 @@ FHardwareTexture *FGLTexture::CreateHwTexture()
//
//===========================================================================
const FHardwareTexture *FGLTexture::Bind(int texunit, int clampmode, int translation, bool alphatexture, FTexture *hirescheck)
const FHardwareTexture *FGLTexture::Bind(int texunit, int clampmode, int translation, FTexture *hirescheck)
{
int usebright = false;
@ -288,7 +285,7 @@ const FHardwareTexture *FGLTexture::Bind(int texunit, int clampmode, int transla
}
// Bind it to the system.
if (!hwtex->Bind(texunit, translation, alphatexture, needmipmap))
if (!hwtex->Bind(texunit, translation, needmipmap))
{
int w=0, h=0;
@ -298,10 +295,10 @@ const FHardwareTexture *FGLTexture::Bind(int texunit, int clampmode, int transla
if (!tex->bHasCanvas)
{
buffer = CreateTexBuffer(translation, w, h, hirescheck, alphatexture);
buffer = CreateTexBuffer(translation, w, h, hirescheck);
tex->ProcessData(buffer, w, h, false);
}
if (!hwtex->CreateTexture(buffer, w, h, texunit, needmipmap, translation, alphatexture))
if (!hwtex->CreateTexture(buffer, w, h, texunit, needmipmap, translation))
{
// could not create texture
delete[] buffer;
@ -614,16 +611,14 @@ outl:
static FMaterial *last;
static int lastclamp;
static int lasttrans;
static bool lastalpha;
void FMaterial::Bind(int clampmode, int translation, bool alphatexture)
void FMaterial::Bind(int clampmode, int translation)
{
// avoid rebinding the same texture multiple times.
if (this == last && lastclamp == clampmode && translation == lasttrans && lastalpha == alphatexture) return;
if (this == last && lastclamp == clampmode && translation == lasttrans) return;
last = this;
lastclamp = clampmode;
lastalpha = alphatexture;
lasttrans = translation;
int usebright = false;
@ -633,7 +628,7 @@ void FMaterial::Bind(int clampmode, int translation, bool alphatexture)
if (tex->bHasCanvas) clampmode = CLAMP_CAMTEX;
else if (tex->bWarped && clampmode <= CLAMP_XY) clampmode = CLAMP_NONE;
const FHardwareTexture *gltexture = mBaseLayer->Bind(0, clampmode, translation, alphatexture, allowhires? tex:NULL);
const FHardwareTexture *gltexture = mBaseLayer->Bind(0, clampmode, translation, allowhires? tex:NULL);
if (gltexture != NULL)
{
for(unsigned i=0;i<mTextureLayers.Size();i++)
@ -649,7 +644,7 @@ void FMaterial::Bind(int clampmode, int translation, bool alphatexture)
{
layer = mTextureLayers[i].texture;
}
layer->gl_info.SystemTexture[mExpanded]->Bind(i+1, clampmode, 0, false, NULL);
layer->gl_info.SystemTexture[mExpanded]->Bind(i+1, clampmode, 0, NULL);
maxbound = i+1;
}
}
@ -669,7 +664,7 @@ void FMaterial::Bind(int clampmode, int translation, bool alphatexture)
//===========================================================================
void FMaterial::Precache()
{
Bind(0, 0, false);
Bind(0, 0);
}
//===========================================================================
@ -749,7 +744,7 @@ void FMaterial::BindToFrameBuffer()
if (mBaseLayer->mHwTexture == NULL)
{
// must create the hardware texture first
mBaseLayer->Bind(0, 0, 0, false, NULL);
mBaseLayer->Bind(0, 0, 0, NULL);
FHardwareTexture::Unbind(0);
ClearLastTexture();
}

View file

@ -67,18 +67,17 @@ private:
bool bHasColorkey; // only for hires
bool bExpand;
unsigned char * LoadHiresTexture(FTexture *hirescheck, int *width, int *height, bool alphatexture);
unsigned char * LoadHiresTexture(FTexture *hirescheck, int *width, int *height);
FHardwareTexture *CreateHwTexture();
const FHardwareTexture *Bind(int texunit, int clamp, int translation, bool alphatexture, FTexture *hirescheck);
const FHardwareTexture *BindPatch(int texunit, int translation, bool alphatexture);
const FHardwareTexture *Bind(int texunit, int clamp, int translation, FTexture *hirescheck);
public:
FGLTexture(FTexture * tx, bool expandpatches);
~FGLTexture();
unsigned char * CreateTexBuffer(int translation, int & w, int & h, FTexture *hirescheck, bool alphatexture);
unsigned char * CreateTexBuffer(int translation, int & w, int & h, FTexture *hirescheck);
void Clean(bool all);
int Dump(int i);
@ -138,12 +137,11 @@ public:
return mTextureLayers.Size() + 1;
}
//void Bind(int clamp = 0, int translation = 0, int overrideshader = 0, bool alphatexture = false);
void Bind(int clamp, int translation, bool alphatexture);
void Bind(int clamp, int translation);
unsigned char * CreateTexBuffer(int translation, int & w, int & h, bool allowhires=true) const
{
return mBaseLayer->CreateTexBuffer(translation, w, h, allowhires? tex:NULL, 0);
return mBaseLayer->CreateTexBuffer(translation, w, h, allowhires? tex : NULL);
}
void Clean(bool f)

View file

@ -824,6 +824,15 @@ void R_InitTranslationTables ()
remap->Remap[i] = IcePaletteRemap[v];
remap->Palette[i] = PalEntry(255, IcePalette[v][0], IcePalette[v][1], IcePalette[v][2]);
}
// The alphatexture translation. Since alphatextures use the red channel this is just a standard grayscale mapping.
PushIdentityTable(TRANSLATION_Standard);
remap = translationtables[TRANSLATION_Standard][8];
for (i = 0; i < 256; i++)
{
remap->Remap[i] = i;
remap->Palette[i] = PalEntry(255, i, i, i);
}
}
//----------------------------------------------------------------------------

View file

@ -60,17 +60,21 @@ vec4 getTexel(vec2 st)
//
switch (uTextureMode)
{
case 1:
case 1: // TM_MASK
texel.rgb = vec3(1.0,1.0,1.0);
break;
case 2:
case 2: // TM_OPAQUE
texel.a = 1.0;
break;
case 3:
case 3: // TM_INVERSE
texel = vec4(1.0-texel.r, 1.0-texel.b, 1.0-texel.g, texel.a);
break;
case 4: // TM_REDTOALPHA
texel = vec4(1.0, 1.0, 1.0, texel.r);
break;
}
texel *= uObjectColor;