Support 8bpp textures
When textures.xml specifies format="alpha", the input is expected to be an 8-bit greyscale PNG, and the output will be an 8-bit uncompressed alpha-only DDS. Add format override to CTextureProperties, to select between e.g. GL_ALPHA and GL_LUMINANCE for 8-bit textures. This is needed so fonts can use the new texture system. This was SVN commit r14015.
This commit is contained in:
parent
6a2fac7a58
commit
8799bd98b0
@ -1,4 +1,4 @@
|
||||
/* Copyright (C) 2010 Wildfire Games.
|
||||
/* Copyright (C) 2013 Wildfire Games.
|
||||
* This file is part of 0 A.D.
|
||||
*
|
||||
* 0 A.D. is free software: you can redistribute it and/or modify
|
||||
@ -65,6 +65,7 @@ struct CTextureConverter::ConversionRequest
|
||||
nvtt::CompressionOptions compressionOptions;
|
||||
nvtt::OutputOptions outputOptions;
|
||||
bool isDXT1a; // see comment in RunThread
|
||||
bool is8bpp;
|
||||
};
|
||||
|
||||
/**
|
||||
@ -148,6 +149,8 @@ CTextureConverter::SettingsFile* CTextureConverter::LoadSettings(const VfsPath&
|
||||
p.settings.format = FMT_DXT5;
|
||||
else if (v == "rgba")
|
||||
p.settings.format = FMT_RGBA;
|
||||
else if (v == "alpha")
|
||||
p.settings.format = FMT_ALPHA;
|
||||
else
|
||||
LOGERROR(L"Invalid attribute value <file format='%hs'>", v.c_str());
|
||||
}
|
||||
@ -337,8 +340,21 @@ bool CTextureConverter::ConvertTexture(const CTexturePtr& texture, const VfsPath
|
||||
// Check whether there's any alpha channel
|
||||
bool hasAlpha = ((tex.flags & TEX_ALPHA) != 0);
|
||||
|
||||
if (settings.format == FMT_ALPHA)
|
||||
{
|
||||
// Convert to uncompressed 8-bit with no mipmaps
|
||||
if (tex_transform_to(&tex, (tex.flags | TEX_GREY) & ~(TEX_DXT | TEX_MIPMAPS | TEX_ALPHA)) < 0)
|
||||
{
|
||||
LOGERROR(L"Failed to transform texture \"%ls\"", src.string().c_str());
|
||||
tex_free(&tex);
|
||||
return false;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
// TODO: grayscale images will fail on some systems
|
||||
// see http://trac.wildfiregames.com/ticket/1640
|
||||
// (plain_transform doesn't know how to construct the alpha channel)
|
||||
if (tex.flags & TEX_GREY)
|
||||
{
|
||||
LOGERROR(L"Failed to convert grayscale texture \"%ls\" - only RGB textures are currently supported", src.string().c_str());
|
||||
@ -352,6 +368,7 @@ bool CTextureConverter::ConvertTexture(const CTexturePtr& texture, const VfsPath
|
||||
tex_free(&tex);
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
// Check if the texture has all alpha=255, so we can automatically
|
||||
// switch from DXT3/DXT5 to DXT1 with no loss
|
||||
@ -385,6 +402,7 @@ bool CTextureConverter::ConvertTexture(const CTexturePtr& texture, const VfsPath
|
||||
request->inputOptions.setAlphaMode(nvtt::AlphaMode_None);
|
||||
|
||||
request->isDXT1a = false;
|
||||
request->is8bpp = false;
|
||||
|
||||
if (settings.format == FMT_RGBA)
|
||||
{
|
||||
@ -392,6 +410,12 @@ bool CTextureConverter::ConvertTexture(const CTexturePtr& texture, const VfsPath
|
||||
// Change the default component order (see tex_dds.cpp decode_pf)
|
||||
request->compressionOptions.setPixelFormat(32, 0xFF, 0xFF00, 0xFF0000, 0xFF000000u);
|
||||
}
|
||||
else if (settings.format == FMT_ALPHA)
|
||||
{
|
||||
request->compressionOptions.setFormat(nvtt::Format_RGBA);
|
||||
request->compressionOptions.setPixelFormat(8, 0x00, 0x00, 0x00, 0xFF);
|
||||
request->is8bpp = true;
|
||||
}
|
||||
else if (!hasAlpha)
|
||||
{
|
||||
// if no alpha channel then there's no point using DXT3 or DXT5
|
||||
@ -431,7 +455,24 @@ bool CTextureConverter::ConvertTexture(const CTexturePtr& texture, const VfsPath
|
||||
|
||||
// Load the texture data
|
||||
request->inputOptions.setTextureLayout(nvtt::TextureType_2D, tex.w, tex.h);
|
||||
if (tex.bpp == 32)
|
||||
{
|
||||
request->inputOptions.setMipmapData(tex_get_data(&tex), tex.w, tex.h);
|
||||
}
|
||||
else // bpp == 8
|
||||
{
|
||||
// NVTT requires 32-bit input data, so convert
|
||||
const u8* input = tex_get_data(&tex);
|
||||
u8* rgba = new u8[tex.w * tex.h * 4];
|
||||
u8* p = rgba;
|
||||
for (size_t i = 0; i < tex.w * tex.h; i++)
|
||||
{
|
||||
p[0] = p[1] = p[2] = p[3] = *input++;
|
||||
p += 4;
|
||||
}
|
||||
request->inputOptions.setMipmapData(rgba, tex.w, tex.h);
|
||||
delete[] rgba;
|
||||
}
|
||||
|
||||
// NVTT copies the texture data so we can free it now
|
||||
tex_free(&tex);
|
||||
@ -562,6 +603,10 @@ void* CTextureConverter::RunThread(void* data)
|
||||
// set the flag here.
|
||||
if (request->isDXT1a && result->ret && result->output.buffer.size() > 80)
|
||||
result->output.buffer[80] |= 1; // DDPF_ALPHAPIXELS in DDS_PIXELFORMAT.dwFlags
|
||||
// Ugly hack: NVTT always sets DDPF_RGB, even if we're trying to output 8-bit
|
||||
// alpha-only DDS with no RGB components. Unset that flag.
|
||||
if (request->is8bpp)
|
||||
result->output.buffer[80] &= ~0x40; // DDPF_RGB in DDS_PIXELFORMAT.dwFlags
|
||||
|
||||
// Push the result onto the queue
|
||||
pthread_mutex_lock(&textureConverter->m_WorkerMutex);
|
||||
|
@ -69,7 +69,8 @@ public:
|
||||
FMT_DXT1,
|
||||
FMT_DXT3,
|
||||
FMT_DXT5,
|
||||
FMT_RGBA
|
||||
FMT_RGBA,
|
||||
FMT_ALPHA
|
||||
};
|
||||
|
||||
enum EMipmap
|
||||
|
@ -1,4 +1,4 @@
|
||||
/* Copyright (C) 2012 Wildfire Games.
|
||||
/* Copyright (C) 2013 Wildfire Games.
|
||||
* This file is part of 0 A.D.
|
||||
*
|
||||
* 0 A.D. is free software: you can redistribute it and/or modify
|
||||
@ -48,6 +48,7 @@ struct TPhash
|
||||
boost::hash_combine(seed, a.m_WrapS);
|
||||
boost::hash_combine(seed, a.m_WrapT);
|
||||
boost::hash_combine(seed, a.m_Aniso);
|
||||
boost::hash_combine(seed, a.m_Format);
|
||||
return seed;
|
||||
}
|
||||
std::size_t operator()(CTexturePtr const& a) const
|
||||
@ -64,7 +65,7 @@ struct TPequal_to
|
||||
{
|
||||
return a.m_Path == b.m_Path && a.m_Filter == b.m_Filter
|
||||
&& a.m_WrapS == b.m_WrapS && a.m_WrapT == b.m_WrapT
|
||||
&& a.m_Aniso == b.m_Aniso;
|
||||
&& a.m_Aniso == b.m_Aniso && a.m_Format == b.m_Format;
|
||||
}
|
||||
bool operator()(CTexturePtr const& a, CTexturePtr const& b) const
|
||||
{
|
||||
@ -215,7 +216,7 @@ public:
|
||||
(void)ogl_tex_set_filter(h, filter);
|
||||
|
||||
// Upload to GL
|
||||
if (!m_DisableGL && ogl_tex_upload(h) < 0)
|
||||
if (!m_DisableGL && ogl_tex_upload(h, texture->m_Properties.m_Format) < 0)
|
||||
{
|
||||
LOGERROR(L"Texture failed to upload: \"%ls\"", texture->m_Properties.m_Path.string().c_str());
|
||||
|
||||
|
@ -132,7 +132,7 @@ public:
|
||||
*/
|
||||
explicit CTextureProperties(const VfsPath& path) :
|
||||
m_Path(path), m_Filter(GL_LINEAR_MIPMAP_LINEAR),
|
||||
m_WrapS(GL_REPEAT), m_WrapT(GL_REPEAT), m_Aniso(1.0f)
|
||||
m_WrapS(GL_REPEAT), m_WrapT(GL_REPEAT), m_Aniso(1.0f), m_Format(0)
|
||||
{
|
||||
}
|
||||
|
||||
@ -157,6 +157,12 @@ public:
|
||||
*/
|
||||
void SetMaxAnisotropy(float aniso) { m_Aniso = aniso; }
|
||||
|
||||
/**
|
||||
* Set GL texture upload format, to override the default.
|
||||
* Typically GL_ALPHA or GL_LUMINANCE for 8-bit textures.
|
||||
*/
|
||||
void SetFormatOverride(GLenum format) { m_Format = format; }
|
||||
|
||||
// TODO: rather than this static definition of texture properties
|
||||
// (especially anisotropy), maybe we want something that can be more
|
||||
// easily tweaked in an Options menu? e.g. the caller just specifies
|
||||
@ -175,11 +181,13 @@ public:
|
||||
// or something a bit like that.
|
||||
|
||||
private:
|
||||
// Must update TPhash, TPequal_to when changing these fields
|
||||
VfsPath m_Path;
|
||||
GLint m_Filter;
|
||||
GLint m_WrapS;
|
||||
GLint m_WrapT;
|
||||
float m_Aniso;
|
||||
GLenum m_Format;
|
||||
};
|
||||
|
||||
/**
|
||||
|
@ -398,7 +398,7 @@ static Status decode_pf(const DDS_PIXELFORMAT* pf, size_t& bpp, size_t& flags)
|
||||
|
||||
// determine type
|
||||
const size_t pf_flags = (size_t)read_le32(&pf->dwFlags);
|
||||
// .. uncompressed
|
||||
// .. uncompressed RGB/RGBA
|
||||
if(pf_flags & DDPF_RGB)
|
||||
{
|
||||
const size_t pf_bpp = (size_t)read_le32(&pf->dwRGBBitCount);
|
||||
@ -415,7 +415,7 @@ static Status decode_pf(const DDS_PIXELFORMAT* pf, size_t& bpp, size_t& flags)
|
||||
{
|
||||
// something weird other than RGBA or BGRA
|
||||
if(pf_a_mask != 0xFF000000)
|
||||
goto unsupported_component_ordering;
|
||||
WARN_RETURN(ERR::TEX_FMT_INVALID);
|
||||
flags |= TEX_ALPHA;
|
||||
}
|
||||
|
||||
@ -429,12 +429,28 @@ static Status decode_pf(const DDS_PIXELFORMAT* pf, size_t& bpp, size_t& flags)
|
||||
// DDS is storing images in a format that requires no processing,
|
||||
// we do not allow any weird orderings that require runtime work.
|
||||
// instead, the artists must export with the correct settings.
|
||||
unsupported_component_ordering:
|
||||
WARN_RETURN(ERR::TEX_FMT_INVALID);
|
||||
}
|
||||
|
||||
RETURN_STATUS_IF_ERR(tex_validate_plain_format(bpp, (int)flags));
|
||||
}
|
||||
// .. uncompressed 8bpp greyscale
|
||||
else if(pf_flags & DDPF_ALPHAPIXELS)
|
||||
{
|
||||
const size_t pf_bpp = (size_t)read_le32(&pf->dwRGBBitCount);
|
||||
const size_t pf_a_mask = (size_t)read_le32(&pf->dwABitMask);
|
||||
|
||||
bpp = pf_bpp;
|
||||
|
||||
if(pf_bpp != 8)
|
||||
WARN_RETURN(ERR::TEX_FMT_INVALID);
|
||||
|
||||
if(pf_a_mask != 0xFF)
|
||||
WARN_RETURN(ERR::TEX_FMT_INVALID);
|
||||
flags |= TEX_GREY;
|
||||
|
||||
RETURN_STATUS_IF_ERR(tex_validate_plain_format(bpp, (int)flags));
|
||||
}
|
||||
// .. compressed
|
||||
else if(pf_flags & DDPF_FOURCC)
|
||||
{
|
||||
|
Loading…
Reference in New Issue
Block a user