Texture system refactoring and cleanup, fixes #2455, patch by IronNerd.
This was SVN commit r14835.
This commit is contained in:
parent
a068935789
commit
a5639631ee
@ -232,7 +232,7 @@ void CHeightMipmap::DumpToDisk(const VfsPath& filename) const
|
|||||||
AllocateAligned(buf, hdr_size+img_size, maxSectorSize);
|
AllocateAligned(buf, hdr_size+img_size, maxSectorSize);
|
||||||
void* img = buf.get() + hdr_size;
|
void* img = buf.get() + hdr_size;
|
||||||
Tex t;
|
Tex t;
|
||||||
WARN_IF_ERR(tex_wrap(w, h, bpp, flags, buf, hdr_size, &t));
|
WARN_IF_ERR(t.wrap(w, h, bpp, flags, buf, hdr_size));
|
||||||
|
|
||||||
memset(img, 0x00, img_size);
|
memset(img, 0x00, img_size);
|
||||||
size_t yoff = 0;
|
size_t yoff = 0;
|
||||||
@ -253,9 +253,7 @@ void CHeightMipmap::DumpToDisk(const VfsPath& filename) const
|
|||||||
}
|
}
|
||||||
|
|
||||||
DynArray da;
|
DynArray da;
|
||||||
WARN_IF_ERR(tex_encode(&t, filename.Extension(), &da));
|
WARN_IF_ERR(t.encode(filename.Extension(), &da));
|
||||||
g_VFS->CreateFile(filename, DummySharedPtr(da.base), da.pos);
|
g_VFS->CreateFile(filename, DummySharedPtr(da.base), da.pos);
|
||||||
(void)da_free(&da);
|
(void)da_free(&da);
|
||||||
|
|
||||||
tex_free(&t);
|
|
||||||
}
|
}
|
||||||
|
@ -333,7 +333,7 @@ void CTerrainTextureEntry::LoadAlphaMaps(VfsPath &amtype)
|
|||||||
|
|
||||||
// upload the composite texture
|
// upload the composite texture
|
||||||
Tex t;
|
Tex t;
|
||||||
(void)tex_wrap(total_w, total_h, 8, TEX_GREY, data, 0, &t);
|
(void)t.wrap(total_w, total_h, 8, TEX_GREY, data, 0);
|
||||||
|
|
||||||
// uncomment the following to save a png of the generated texture
|
// uncomment the following to save a png of the generated texture
|
||||||
// in the public/ directory, for debugging
|
// in the public/ directory, for debugging
|
||||||
|
@ -331,22 +331,21 @@ bool CTextureConverter::ConvertTexture(const CTexturePtr& texture, const VfsPath
|
|||||||
}
|
}
|
||||||
|
|
||||||
Tex tex;
|
Tex tex;
|
||||||
if (tex_decode(file, fileSize, &tex) < 0)
|
if (tex.decode(file, fileSize) < 0)
|
||||||
{
|
{
|
||||||
LOGERROR(L"Failed to decode texture \"%ls\"", src.string().c_str());
|
LOGERROR(L"Failed to decode texture \"%ls\"", src.string().c_str());
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
// Check whether there's any alpha channel
|
// Check whether there's any alpha channel
|
||||||
bool hasAlpha = ((tex.flags & TEX_ALPHA) != 0);
|
bool hasAlpha = ((tex.m_Flags & TEX_ALPHA) != 0);
|
||||||
|
|
||||||
if (settings.format == FMT_ALPHA)
|
if (settings.format == FMT_ALPHA)
|
||||||
{
|
{
|
||||||
// Convert to uncompressed 8-bit with no mipmaps
|
// Convert to uncompressed 8-bit with no mipmaps
|
||||||
if (tex_transform_to(&tex, (tex.flags | TEX_GREY) & ~(TEX_DXT | TEX_MIPMAPS | TEX_ALPHA)) < 0)
|
if (tex.transform_to((tex.m_Flags | TEX_GREY) & ~(TEX_DXT | TEX_MIPMAPS | TEX_ALPHA)) < 0)
|
||||||
{
|
{
|
||||||
LOGERROR(L"Failed to transform texture \"%ls\"", src.string().c_str());
|
LOGERROR(L"Failed to transform texture \"%ls\"", src.string().c_str());
|
||||||
tex_free(&tex);
|
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -355,17 +354,16 @@ bool CTextureConverter::ConvertTexture(const CTexturePtr& texture, const VfsPath
|
|||||||
// TODO: grayscale images will fail on some systems
|
// TODO: grayscale images will fail on some systems
|
||||||
// see http://trac.wildfiregames.com/ticket/1640
|
// see http://trac.wildfiregames.com/ticket/1640
|
||||||
// (plain_transform doesn't know how to construct the alpha channel)
|
// (plain_transform doesn't know how to construct the alpha channel)
|
||||||
if (tex.flags & TEX_GREY)
|
if (tex.m_Flags & TEX_GREY)
|
||||||
{
|
{
|
||||||
LOGERROR(L"Failed to convert grayscale texture \"%ls\" - only RGB textures are currently supported", src.string().c_str());
|
LOGERROR(L"Failed to convert grayscale texture \"%ls\" - only RGB textures are currently supported", src.string().c_str());
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
// Convert to uncompressed BGRA with no mipmaps
|
// Convert to uncompressed BGRA with no mipmaps
|
||||||
if (tex_transform_to(&tex, (tex.flags | TEX_BGR | TEX_ALPHA) & ~(TEX_DXT | TEX_MIPMAPS)) < 0)
|
if (tex.transform_to((tex.m_Flags | TEX_BGR | TEX_ALPHA) & ~(TEX_DXT | TEX_MIPMAPS)) < 0)
|
||||||
{
|
{
|
||||||
LOGERROR(L"Failed to transform texture \"%ls\"", src.string().c_str());
|
LOGERROR(L"Failed to transform texture \"%ls\"", src.string().c_str());
|
||||||
tex_free(&tex);
|
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -375,8 +373,8 @@ bool CTextureConverter::ConvertTexture(const CTexturePtr& texture, const VfsPath
|
|||||||
if (hasAlpha)
|
if (hasAlpha)
|
||||||
{
|
{
|
||||||
hasAlpha = false;
|
hasAlpha = false;
|
||||||
u8* data = tex_get_data(&tex);
|
u8* data = tex.get_data();
|
||||||
for (size_t i = 0; i < tex.w * tex.h; ++i)
|
for (size_t i = 0; i < tex.m_Width * tex.m_Height; ++i)
|
||||||
{
|
{
|
||||||
if (data[i*4+3] != 0xFF)
|
if (data[i*4+3] != 0xFF)
|
||||||
{
|
{
|
||||||
@ -454,29 +452,26 @@ bool CTextureConverter::ConvertTexture(const CTexturePtr& texture, const VfsPath
|
|||||||
// TODO: normal maps, gamma, etc
|
// TODO: normal maps, gamma, etc
|
||||||
|
|
||||||
// Load the texture data
|
// Load the texture data
|
||||||
request->inputOptions.setTextureLayout(nvtt::TextureType_2D, tex.w, tex.h);
|
request->inputOptions.setTextureLayout(nvtt::TextureType_2D, tex.m_Width, tex.m_Height);
|
||||||
if (tex.bpp == 32)
|
if (tex.m_Bpp == 32)
|
||||||
{
|
{
|
||||||
request->inputOptions.setMipmapData(tex_get_data(&tex), tex.w, tex.h);
|
request->inputOptions.setMipmapData(tex.get_data(), tex.m_Width, tex.m_Height);
|
||||||
}
|
}
|
||||||
else // bpp == 8
|
else // bpp == 8
|
||||||
{
|
{
|
||||||
// NVTT requires 32-bit input data, so convert
|
// NVTT requires 32-bit input data, so convert
|
||||||
const u8* input = tex_get_data(&tex);
|
const u8* input = tex.get_data();
|
||||||
u8* rgba = new u8[tex.w * tex.h * 4];
|
u8* rgba = new u8[tex.m_Width * tex.m_Height * 4];
|
||||||
u8* p = rgba;
|
u8* p = rgba;
|
||||||
for (size_t i = 0; i < tex.w * tex.h; i++)
|
for (size_t i = 0; i < tex.m_Width * tex.m_Height; i++)
|
||||||
{
|
{
|
||||||
p[0] = p[1] = p[2] = p[3] = *input++;
|
p[0] = p[1] = p[2] = p[3] = *input++;
|
||||||
p += 4;
|
p += 4;
|
||||||
}
|
}
|
||||||
request->inputOptions.setMipmapData(rgba, tex.w, tex.h);
|
request->inputOptions.setMipmapData(rgba, tex.m_Width, tex.m_Height);
|
||||||
delete[] rgba;
|
delete[] rgba;
|
||||||
}
|
}
|
||||||
|
|
||||||
// NVTT copies the texture data so we can free it now
|
|
||||||
tex_free(&tex);
|
|
||||||
|
|
||||||
pthread_mutex_lock(&m_WorkerMutex);
|
pthread_mutex_lock(&m_WorkerMutex);
|
||||||
m_RequestQueue.push_back(request);
|
m_RequestQueue.push_back(request);
|
||||||
pthread_mutex_unlock(&m_WorkerMutex);
|
pthread_mutex_unlock(&m_WorkerMutex);
|
||||||
|
@ -94,7 +94,7 @@ public:
|
|||||||
data.get()[1] = 64;
|
data.get()[1] = 64;
|
||||||
data.get()[2] = 64;
|
data.get()[2] = 64;
|
||||||
Tex t;
|
Tex t;
|
||||||
(void)tex_wrap(1, 1, 24, 0, data, 0, &t);
|
(void)t.wrap(1, 1, 24, 0, data, 0);
|
||||||
|
|
||||||
m_DefaultHandle = ogl_tex_wrap(&t, m_VFS, L"(default texture)");
|
m_DefaultHandle = ogl_tex_wrap(&t, m_VFS, L"(default texture)");
|
||||||
(void)ogl_tex_set_filter(m_DefaultHandle, GL_LINEAR);
|
(void)ogl_tex_set_filter(m_DefaultHandle, GL_LINEAR);
|
||||||
@ -111,7 +111,7 @@ public:
|
|||||||
data.get()[1] = 0;
|
data.get()[1] = 0;
|
||||||
data.get()[2] = 255;
|
data.get()[2] = 255;
|
||||||
Tex t;
|
Tex t;
|
||||||
(void)tex_wrap(1, 1, 24, 0, data, 0, &t);
|
(void)t.wrap(1, 1, 24, 0, data, 0);
|
||||||
|
|
||||||
m_ErrorHandle = ogl_tex_wrap(&t, m_VFS, L"(error texture)");
|
m_ErrorHandle = ogl_tex_wrap(&t, m_VFS, L"(error texture)");
|
||||||
(void)ogl_tex_set_filter(m_ErrorHandle, GL_LINEAR);
|
(void)ogl_tex_set_filter(m_ErrorHandle, GL_LINEAR);
|
||||||
|
@ -78,11 +78,11 @@ public:
|
|||||||
TS_ASSERT_OK(m_VFS->LoadFile(dest, file, fileSize));
|
TS_ASSERT_OK(m_VFS->LoadFile(dest, file, fileSize));
|
||||||
|
|
||||||
Tex tex;
|
Tex tex;
|
||||||
TS_ASSERT_OK(tex_decode(file, fileSize, &tex));
|
TS_ASSERT_OK(tex.decode(file, fileSize));
|
||||||
|
|
||||||
TS_ASSERT_OK(tex_transform_to(&tex, (tex.flags | TEX_BGR | TEX_ALPHA) & ~(TEX_DXT | TEX_MIPMAPS)));
|
TS_ASSERT_OK(tex.transform_to((tex.m_Flags | TEX_BGR | TEX_ALPHA) & ~(TEX_DXT | TEX_MIPMAPS)));
|
||||||
|
|
||||||
u8* texdata = tex_get_data(&tex);
|
u8* texdata = tex.get_data();
|
||||||
|
|
||||||
// The source texture is repeated after 4 pixels, so the compressed texture
|
// The source texture is repeated after 4 pixels, so the compressed texture
|
||||||
// should be identical after 4 pixels
|
// should be identical after 4 pixels
|
||||||
@ -97,7 +97,5 @@ public:
|
|||||||
// if (i % 4 == 0) printf("\n");
|
// if (i % 4 == 0) printf("\n");
|
||||||
// printf("%02x ", texdata[i]);
|
// printf("%02x ", texdata[i]);
|
||||||
// }
|
// }
|
||||||
|
|
||||||
tex_free(&tex);
|
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
@ -60,17 +60,17 @@ static Status load_sys_cursor(const PIVFS& vfs, const VfsPath& pathname, int hx,
|
|||||||
shared_ptr<u8> file; size_t fileSize;
|
shared_ptr<u8> file; size_t fileSize;
|
||||||
RETURN_STATUS_IF_ERR(vfs->LoadFile(pathname, file, fileSize));
|
RETURN_STATUS_IF_ERR(vfs->LoadFile(pathname, file, fileSize));
|
||||||
|
|
||||||
ScopedTex t;
|
Tex t;
|
||||||
RETURN_STATUS_IF_ERR(tex_decode(file, fileSize, &t));
|
RETURN_STATUS_IF_ERR(t.decode(file, fileSize));
|
||||||
|
|
||||||
// convert to required BGRA format.
|
// convert to required BGRA format.
|
||||||
const size_t flags = (t.flags | TEX_BGR) & ~TEX_DXT;
|
const size_t flags = (t.m_Flags | TEX_BGR) & ~TEX_DXT;
|
||||||
RETURN_STATUS_IF_ERR(tex_transform_to(&t, flags));
|
RETURN_STATUS_IF_ERR(t.transform_to(flags));
|
||||||
void* bgra_img = tex_get_data(&t);
|
void* bgra_img = t.get_data();
|
||||||
if(!bgra_img)
|
if(!bgra_img)
|
||||||
WARN_RETURN(ERR::FAIL);
|
WARN_RETURN(ERR::FAIL);
|
||||||
|
|
||||||
RETURN_STATUS_IF_ERR(sys_cursor_create((int)t.w, (int)t.h, bgra_img, hx, hy, cursor));
|
RETURN_STATUS_IF_ERR(sys_cursor_create((int)t.m_Width, (int)t.m_Height, bgra_img, hx, hy, cursor));
|
||||||
return INFO::OK;
|
return INFO::OK;
|
||||||
#endif
|
#endif
|
||||||
}
|
}
|
||||||
|
@ -449,7 +449,7 @@ static void OglTex_dtor(OglTex* ot)
|
|||||||
{
|
{
|
||||||
if(ot->flags & OT_TEX_VALID)
|
if(ot->flags & OT_TEX_VALID)
|
||||||
{
|
{
|
||||||
tex_free(&ot->t);
|
ot->t.free();
|
||||||
ot->flags &= ~OT_TEX_VALID;
|
ot->flags &= ~OT_TEX_VALID;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -473,7 +473,7 @@ static Status OglTex_reload(OglTex* ot, const PIVFS& vfs, const VfsPath& pathnam
|
|||||||
{
|
{
|
||||||
shared_ptr<u8> file; size_t fileSize;
|
shared_ptr<u8> file; size_t fileSize;
|
||||||
RETURN_STATUS_IF_ERR(vfs->LoadFile(pathname, file, fileSize));
|
RETURN_STATUS_IF_ERR(vfs->LoadFile(pathname, file, fileSize));
|
||||||
if(tex_decode(file, fileSize, &ot->t) >= 0)
|
if(ot->t.decode(file, fileSize) >= 0)
|
||||||
ot->flags |= OT_TEX_VALID;
|
ot->flags |= OT_TEX_VALID;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -491,13 +491,13 @@ static Status OglTex_validate(const OglTex* ot)
|
|||||||
{
|
{
|
||||||
if(ot->flags & OT_TEX_VALID)
|
if(ot->flags & OT_TEX_VALID)
|
||||||
{
|
{
|
||||||
RETURN_STATUS_IF_ERR(tex_validate(&ot->t));
|
RETURN_STATUS_IF_ERR(ot->t.validate());
|
||||||
|
|
||||||
// width, height
|
// width, height
|
||||||
// (note: this is done here because tex.cpp doesn't impose any
|
// (note: this is done here because tex.cpp doesn't impose any
|
||||||
// restrictions on dimensions, while OpenGL does).
|
// restrictions on dimensions, while OpenGL does).
|
||||||
size_t w = ot->t.w;
|
size_t w = ot->t.m_Width;
|
||||||
size_t h = ot->t.h;
|
size_t h = ot->t.m_Height;
|
||||||
// .. == 0; texture file probably not loaded successfully.
|
// .. == 0; texture file probably not loaded successfully.
|
||||||
if(w == 0 || h == 0)
|
if(w == 0 || h == 0)
|
||||||
WARN_RETURN(ERR::_11);
|
WARN_RETURN(ERR::_11);
|
||||||
@ -794,12 +794,12 @@ static Status get_mipmaps(Tex* t, GLint filter, int q_flags, int* plevels_to_ski
|
|||||||
{
|
{
|
||||||
// decisions:
|
// decisions:
|
||||||
// .. does filter call for uploading mipmaps?
|
// .. does filter call for uploading mipmaps?
|
||||||
const bool need_mipmaps = are_mipmaps_needed(t->w, t->h, filter);
|
const bool need_mipmaps = are_mipmaps_needed(t->m_Width, t->m_Height, filter);
|
||||||
// .. does the image data include mipmaps? (stored as separate
|
// .. does the image data include mipmaps? (stored as separate
|
||||||
// images after the regular texels)
|
// images after the regular texels)
|
||||||
const bool includes_mipmaps = (t->flags & TEX_MIPMAPS) != 0;
|
const bool includes_mipmaps = (t->m_Flags & TEX_MIPMAPS) != 0;
|
||||||
// .. is this texture in S3TC format? (more generally, "compressed")
|
// .. is this texture in S3TC format? (more generally, "compressed")
|
||||||
const bool is_s3tc = (t->flags & TEX_DXT) != 0;
|
const bool is_s3tc = (t->m_Flags & TEX_DXT) != 0;
|
||||||
|
|
||||||
*plevels_to_skip = TEX_BASE_LEVEL_ONLY;
|
*plevels_to_skip = TEX_BASE_LEVEL_ONLY;
|
||||||
if(!need_mipmaps)
|
if(!need_mipmaps)
|
||||||
@ -833,7 +833,7 @@ static Status get_mipmaps(Tex* t, GLint filter, int q_flags, int* plevels_to_ski
|
|||||||
// we will generate mipmaps in software.
|
// we will generate mipmaps in software.
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
RETURN_STATUS_IF_ERR(tex_transform_to(t, t->flags|TEX_MIPMAPS));
|
RETURN_STATUS_IF_ERR(t->transform_to(t->m_Flags|TEX_MIPMAPS));
|
||||||
*plevels_to_skip = 0; // t contains mipmaps
|
*plevels_to_skip = 0; // t contains mipmaps
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -843,7 +843,7 @@ static Status get_mipmaps(Tex* t, GLint filter, int q_flags, int* plevels_to_ski
|
|||||||
// if OpenGL's texture dimension limit is too small, use the
|
// if OpenGL's texture dimension limit is too small, use the
|
||||||
// higher mipmap levels. NB: the minimum guaranteed size is
|
// higher mipmap levels. NB: the minimum guaranteed size is
|
||||||
// far too low, and menu background textures may be large.
|
// far too low, and menu background textures may be large.
|
||||||
GLint w = (GLint)t->w, h = (GLint)t->h;
|
GLint w = (GLint)t->m_Width, h = (GLint)t->m_Height;
|
||||||
while(w > ogl_max_tex_size || h > ogl_max_tex_size)
|
while(w > ogl_max_tex_size || h > ogl_max_tex_size)
|
||||||
{
|
{
|
||||||
(*plevels_to_skip)++;
|
(*plevels_to_skip)++;
|
||||||
@ -893,13 +893,13 @@ static void upload_compressed_level(size_t level, size_t level_w, size_t level_h
|
|||||||
// pre: <t> is valid for OpenGL use; texture is bound.
|
// pre: <t> is valid for OpenGL use; texture is bound.
|
||||||
static void upload_impl(Tex* t, GLenum fmt, GLint int_fmt, int levels_to_skip, u32* uploaded_size)
|
static void upload_impl(Tex* t, GLenum fmt, GLint int_fmt, int levels_to_skip, u32* uploaded_size)
|
||||||
{
|
{
|
||||||
const GLsizei w = (GLsizei)t->w;
|
const GLsizei w = (GLsizei)t->m_Width;
|
||||||
const GLsizei h = (GLsizei)t->h;
|
const GLsizei h = (GLsizei)t->m_Height;
|
||||||
const size_t bpp = t->bpp;
|
const size_t bpp = t->m_Bpp;
|
||||||
const u8* data = (const u8*)tex_get_data(t);
|
const u8* data = (const u8*)t->get_data();
|
||||||
const UploadParams up = { fmt, int_fmt, uploaded_size };
|
const UploadParams up = { fmt, int_fmt, uploaded_size };
|
||||||
|
|
||||||
if(t->flags & TEX_DXT)
|
if(t->m_Flags & TEX_DXT)
|
||||||
tex_util_foreach_mipmap(w, h, bpp, data, levels_to_skip, 4, upload_compressed_level, (void*)&up);
|
tex_util_foreach_mipmap(w, h, bpp, data, levels_to_skip, 4, upload_compressed_level, (void*)&up);
|
||||||
else
|
else
|
||||||
tex_util_foreach_mipmap(w, h, bpp, data, levels_to_skip, 1, upload_level, (void*)&up);
|
tex_util_foreach_mipmap(w, h, bpp, data, levels_to_skip, 1, upload_level, (void*)&up);
|
||||||
@ -932,11 +932,11 @@ Status ogl_tex_upload(const Handle ht, GLenum fmt_ovr, int q_flags_ovr, GLint in
|
|||||||
if(ot->flags & OT_TEX_VALID)
|
if(ot->flags & OT_TEX_VALID)
|
||||||
{
|
{
|
||||||
// decompress S3TC if that's not supported by OpenGL.
|
// decompress S3TC if that's not supported by OpenGL.
|
||||||
if((t->flags & TEX_DXT) && !have_s3tc)
|
if((t->m_Flags & TEX_DXT) && !have_s3tc)
|
||||||
(void)tex_transform_to(t, t->flags & ~TEX_DXT);
|
(void)t->transform_to(t->m_Flags & ~TEX_DXT);
|
||||||
|
|
||||||
// determine fmt and int_fmt, allowing for user override.
|
// determine fmt and int_fmt, allowing for user override.
|
||||||
ot->fmt = choose_fmt(t->bpp, t->flags);
|
ot->fmt = choose_fmt(t->m_Bpp, t->m_Flags);
|
||||||
if(fmt_ovr) ot->fmt = fmt_ovr;
|
if(fmt_ovr) ot->fmt = fmt_ovr;
|
||||||
if(q_flags_ovr) ot->q_flags = q_flags_ovr;
|
if(q_flags_ovr) ot->q_flags = q_flags_ovr;
|
||||||
ot->int_fmt = choose_int_fmt(ot->fmt, ot->q_flags);
|
ot->int_fmt = choose_int_fmt(ot->fmt, ot->q_flags);
|
||||||
@ -964,13 +964,10 @@ Status ogl_tex_upload(const Handle ht, GLenum fmt_ovr, int q_flags_ovr, GLint in
|
|||||||
ot->flags |= OT_IS_UPLOADED;
|
ot->flags |= OT_IS_UPLOADED;
|
||||||
|
|
||||||
// see rationale for <refs> at declaration of OglTex.
|
// see rationale for <refs> at declaration of OglTex.
|
||||||
// note: tex_free is safe even if this OglTex was wrapped -
|
|
||||||
// the Tex contains a mem handle.
|
|
||||||
intptr_t refs = h_get_refcnt(ht);
|
intptr_t refs = h_get_refcnt(ht);
|
||||||
if(refs == 1)
|
if(refs == 1)
|
||||||
{
|
{
|
||||||
// note: we verify above that OT_TEX_VALID is set
|
// note: we verify above that OT_TEX_VALID is set
|
||||||
tex_free(t);
|
|
||||||
ot->flags &= ~OT_TEX_VALID;
|
ot->flags &= ~OT_TEX_VALID;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -992,11 +989,11 @@ Status ogl_tex_get_size(Handle ht, size_t* w, size_t* h, size_t* bpp)
|
|||||||
H_DEREF(ht, OglTex, ot);
|
H_DEREF(ht, OglTex, ot);
|
||||||
|
|
||||||
if(w)
|
if(w)
|
||||||
*w = ot->t.w;
|
*w = ot->t.m_Width;
|
||||||
if(h)
|
if(h)
|
||||||
*h = ot->t.h;
|
*h = ot->t.m_Height;
|
||||||
if(bpp)
|
if(bpp)
|
||||||
*bpp = ot->t.bpp;
|
*bpp = ot->t.m_Bpp;
|
||||||
return INFO::OK;
|
return INFO::OK;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -1009,7 +1006,7 @@ Status ogl_tex_get_format(Handle ht, size_t* flags, GLenum* fmt)
|
|||||||
H_DEREF(ht, OglTex, ot);
|
H_DEREF(ht, OglTex, ot);
|
||||||
|
|
||||||
if(flags)
|
if(flags)
|
||||||
*flags = ot->t.flags;
|
*flags = ot->t.m_Flags;
|
||||||
if(fmt)
|
if(fmt)
|
||||||
{
|
{
|
||||||
ENSURE(ot->flags & OT_IS_UPLOADED);
|
ENSURE(ot->flags & OT_IS_UPLOADED);
|
||||||
@ -1030,7 +1027,7 @@ Status ogl_tex_get_data(Handle ht, u8** p)
|
|||||||
{
|
{
|
||||||
H_DEREF(ht, OglTex, ot);
|
H_DEREF(ht, OglTex, ot);
|
||||||
|
|
||||||
*p = tex_get_data(&ot->t);
|
*p = ot->t.get_data();
|
||||||
return INFO::OK;
|
return INFO::OK;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -1048,7 +1045,7 @@ extern Status ogl_tex_get_average_colour(Handle ht, u32* p)
|
|||||||
H_DEREF(ht, OglTex, ot);
|
H_DEREF(ht, OglTex, ot);
|
||||||
warn_if_uploaded(ht, ot);
|
warn_if_uploaded(ht, ot);
|
||||||
|
|
||||||
*p = tex_get_average_colour(&ot->t);
|
*p = ot->t.get_average_colour();
|
||||||
return INFO::OK;
|
return INFO::OK;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -1111,7 +1108,7 @@ Status ogl_tex_get_texture_id(Handle ht, GLuint* id)
|
|||||||
Status ogl_tex_transform(Handle ht, size_t transforms)
|
Status ogl_tex_transform(Handle ht, size_t transforms)
|
||||||
{
|
{
|
||||||
H_DEREF(ht, OglTex, ot);
|
H_DEREF(ht, OglTex, ot);
|
||||||
Status ret = tex_transform(&ot->t, transforms);
|
Status ret = ot->t.transform(transforms);
|
||||||
return ret;
|
return ret;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -1121,7 +1118,7 @@ Status ogl_tex_transform(Handle ht, size_t transforms)
|
|||||||
Status ogl_tex_transform_to(Handle ht, size_t new_flags)
|
Status ogl_tex_transform_to(Handle ht, size_t new_flags)
|
||||||
{
|
{
|
||||||
H_DEREF(ht, OglTex, ot);
|
H_DEREF(ht, OglTex, ot);
|
||||||
Status ret = tex_transform_to(&ot->t, new_flags);
|
Status ret = ot->t.transform_to(new_flags);
|
||||||
return ret;
|
return ret;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -35,27 +35,31 @@ class TestTex : public CxxTest::TestSuite
|
|||||||
shared_ptr<u8> img(new u8[size], ArrayDeleter());
|
shared_ptr<u8> img(new u8[size], ArrayDeleter());
|
||||||
std::generate(img.get(), img.get()+size, rand);
|
std::generate(img.get(), img.get()+size, rand);
|
||||||
|
|
||||||
// wrap in Tex
|
// create the DynArray that will be wrapped in a Tex Object
|
||||||
Tex t;
|
|
||||||
TS_ASSERT_OK(tex_wrap(w, h, bpp, flags, img, 0, &t));
|
|
||||||
|
|
||||||
// encode to file format
|
|
||||||
DynArray da;
|
DynArray da;
|
||||||
TS_ASSERT_OK(tex_encode(&t, extension, &da));
|
|
||||||
memset(&t, 0, sizeof(t));
|
|
||||||
|
|
||||||
// decode from file format
|
// Once the Tex created here goes out of scope, the DynArray should be freed
|
||||||
shared_ptr<u8> ptr = DummySharedPtr(da.base);
|
{
|
||||||
TS_ASSERT_OK(tex_decode(ptr, da.cur_size, &t));
|
// wrap in Tex
|
||||||
|
Tex t;
|
||||||
|
TS_ASSERT_OK(t.wrap(w, h, bpp, flags, img, 0));
|
||||||
|
|
||||||
// make sure pixel format gets converted completely to plain
|
// encode to file format
|
||||||
TS_ASSERT_OK(tex_transform_to(&t, 0));
|
TS_ASSERT_OK(t.encode(extension, &da));
|
||||||
|
memset(&t, 0, sizeof(t));
|
||||||
|
|
||||||
// compare img
|
// decode from file format
|
||||||
TS_ASSERT_SAME_DATA(tex_get_data(&t), img.get(), size);
|
shared_ptr<u8> ptr = DummySharedPtr(da.base);
|
||||||
|
TS_ASSERT_OK(t.decode(ptr, da.cur_size));
|
||||||
|
|
||||||
|
// make sure pixel format gets converted completely to plain
|
||||||
|
TS_ASSERT_OK(t.transform_to(0));
|
||||||
|
|
||||||
|
// compare img
|
||||||
|
TS_ASSERT_SAME_DATA(t.get_data(), img.get(), size);
|
||||||
|
}
|
||||||
|
|
||||||
// cleanup
|
// cleanup
|
||||||
tex_free(&t);
|
|
||||||
TS_ASSERT_OK(da_free(&da));
|
TS_ASSERT_OK(da_free(&da));
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -136,10 +140,10 @@ public:
|
|||||||
// assumes 2x2 box filter algorithm with rounding
|
// assumes 2x2 box filter algorithm with rounding
|
||||||
static const u8 mipmap[] = { 0x6C,0x79,0x87 };
|
static const u8 mipmap[] = { 0x6C,0x79,0x87 };
|
||||||
Tex t;
|
Tex t;
|
||||||
TS_ASSERT_OK(tex_wrap(2, 2, 24, 0, img, 0, &t));
|
TS_ASSERT_OK(t.wrap(2, 2, 24, 0, img, 0));
|
||||||
TS_ASSERT_OK(tex_transform_to(&t, TEX_MIPMAPS));
|
TS_ASSERT_OK(t.transform_to(TEX_MIPMAPS));
|
||||||
const u8* const out_img = tex_get_data(&t);
|
const u8* const out_img = t.get_data();
|
||||||
TS_ASSERT_EQUALS((int)tex_img_size(&t), 12+3);
|
TS_ASSERT_EQUALS((int)t.img_size(), 12+3);
|
||||||
TS_ASSERT_SAME_DATA(out_img, imgData, 12);
|
TS_ASSERT_SAME_DATA(out_img, imgData, 12);
|
||||||
TS_ASSERT_SAME_DATA(out_img+12, mipmap, 3);
|
TS_ASSERT_SAME_DATA(out_img+12, mipmap, 3);
|
||||||
}
|
}
|
||||||
@ -149,13 +153,13 @@ public:
|
|||||||
shared_ptr<u8> img(new u8[100*100*4], ArrayDeleter());
|
shared_ptr<u8> img(new u8[100*100*4], ArrayDeleter());
|
||||||
|
|
||||||
Tex t;
|
Tex t;
|
||||||
TS_ASSERT_OK(tex_wrap(100, 100, 32, TEX_ALPHA, img, 0, &t));
|
TS_ASSERT_OK(t.wrap(100, 100, 32, TEX_ALPHA, img, 0));
|
||||||
TS_ASSERT_EQUALS((int)tex_img_size(&t), 40000);
|
TS_ASSERT_EQUALS((int)t.img_size(), 40000);
|
||||||
|
|
||||||
// DXT rounds up to 4x4 blocks; DXT1a is 4bpp
|
// DXT rounds up to 4x4 blocks; DXT1a is 4bpp
|
||||||
Tex t2;
|
Tex t2;
|
||||||
TS_ASSERT_OK(tex_wrap(97, 97, 4, DXT1A, img, 0, &t2));
|
TS_ASSERT_OK(t2.wrap(97, 97, 4, DXT1A, img, 0));
|
||||||
TS_ASSERT_EQUALS((int)tex_img_size(&t2), 5000);
|
TS_ASSERT_EQUALS((int)t2.img_size(), 5000);
|
||||||
}
|
}
|
||||||
|
|
||||||
void test_s3tc_decode()
|
void test_s3tc_decode()
|
||||||
@ -176,17 +180,15 @@ public:
|
|||||||
|
|
||||||
// wrap in Tex
|
// wrap in Tex
|
||||||
Tex t;
|
Tex t;
|
||||||
TS_ASSERT_OK(tex_wrap(w, h, bpp, flags, img, 0, &t));
|
TS_ASSERT_OK(t.wrap(w, h, bpp, flags, img, 0));
|
||||||
|
|
||||||
// decompress S3TC
|
// decompress S3TC
|
||||||
TS_ASSERT_OK(tex_transform_to(&t, 0));
|
TS_ASSERT_OK(t.transform_to(0));
|
||||||
|
|
||||||
// compare img
|
// compare img
|
||||||
TS_ASSERT_SAME_DATA(tex_get_data(&t), expected, 48);
|
TS_ASSERT_SAME_DATA(t.get_data(), expected, 48);
|
||||||
|
|
||||||
// cleanup
|
// cleanup
|
||||||
tex_free(&t);
|
|
||||||
|
|
||||||
tex_codec_unregister_all();
|
tex_codec_unregister_all();
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
@ -57,41 +57,41 @@ STATUS_ADD_DEFINITIONS(texStatusDefinitions);
|
|||||||
//-----------------------------------------------------------------------------
|
//-----------------------------------------------------------------------------
|
||||||
|
|
||||||
// be careful not to use other tex_* APIs here because they call us.
|
// be careful not to use other tex_* APIs here because they call us.
|
||||||
Status tex_validate(const Tex* t)
|
Status Tex::validate() const
|
||||||
{
|
{
|
||||||
if(t->flags & TEX_UNDEFINED_FLAGS)
|
if(m_Flags & TEX_UNDEFINED_FLAGS)
|
||||||
WARN_RETURN(ERR::_1);
|
WARN_RETURN(ERR::_1);
|
||||||
|
|
||||||
// pixel data (only check validity if the image is still in memory;
|
// pixel data (only check validity if the image is still in memory;
|
||||||
// ogl_tex frees the data after uploading to GL)
|
// ogl_tex frees the data after uploading to GL)
|
||||||
if(t->data)
|
if(m_Data)
|
||||||
{
|
{
|
||||||
// file size smaller than header+pixels.
|
// file size smaller than header+pixels.
|
||||||
// possible causes: texture file header is invalid,
|
// possible causes: texture file header is invalid,
|
||||||
// or file wasn't loaded completely.
|
// or file wasn't loaded completely.
|
||||||
if(t->dataSize < t->ofs + t->w*t->h*t->bpp/8)
|
if(m_DataSize < m_Ofs + m_Width*m_Height*m_Bpp/8)
|
||||||
WARN_RETURN(ERR::_2);
|
WARN_RETURN(ERR::_2);
|
||||||
}
|
}
|
||||||
|
|
||||||
// bits per pixel
|
// bits per pixel
|
||||||
// (we don't bother checking all values; a sanity check is enough)
|
// (we don't bother checking all values; a sanity check is enough)
|
||||||
if(t->bpp % 4 || t->bpp > 32)
|
if(m_Bpp % 4 || m_Bpp > 32)
|
||||||
WARN_RETURN(ERR::_3);
|
WARN_RETURN(ERR::_3);
|
||||||
|
|
||||||
// flags
|
// flags
|
||||||
// .. DXT value
|
// .. DXT value
|
||||||
const size_t dxt = t->flags & TEX_DXT;
|
const size_t dxt = m_Flags & TEX_DXT;
|
||||||
if(dxt != 0 && dxt != 1 && dxt != DXT1A && dxt != 3 && dxt != 5)
|
if(dxt != 0 && dxt != 1 && dxt != DXT1A && dxt != 3 && dxt != 5)
|
||||||
WARN_RETURN(ERR::_4);
|
WARN_RETURN(ERR::_4);
|
||||||
// .. orientation
|
// .. orientation
|
||||||
const size_t orientation = t->flags & TEX_ORIENTATION;
|
const size_t orientation = m_Flags & TEX_ORIENTATION;
|
||||||
if(orientation == (TEX_BOTTOM_UP|TEX_TOP_DOWN))
|
if(orientation == (TEX_BOTTOM_UP|TEX_TOP_DOWN))
|
||||||
WARN_RETURN(ERR::_5);
|
WARN_RETURN(ERR::_5);
|
||||||
|
|
||||||
return INFO::OK;
|
return INFO::OK;
|
||||||
}
|
}
|
||||||
|
|
||||||
#define CHECK_TEX(t) RETURN_STATUS_IF_ERR(tex_validate(t))
|
#define CHECK_TEX(t) RETURN_STATUS_IF_ERR((t->validate()))
|
||||||
|
|
||||||
|
|
||||||
// check if the given texture format is acceptable: 8bpp grey,
|
// check if the given texture format is acceptable: 8bpp grey,
|
||||||
@ -257,15 +257,15 @@ static Status add_mipmaps(Tex* t, size_t w, size_t h, size_t bpp, void* newData,
|
|||||||
// the only place this is used (ogl_tex_upload) requires POT anyway.
|
// the only place this is used (ogl_tex_upload) requires POT anyway.
|
||||||
if(!is_pow2(w) || !is_pow2(h))
|
if(!is_pow2(w) || !is_pow2(h))
|
||||||
WARN_RETURN(ERR::TEX_INVALID_SIZE);
|
WARN_RETURN(ERR::TEX_INVALID_SIZE);
|
||||||
t->flags |= TEX_MIPMAPS; // must come before tex_img_size!
|
t->m_Flags |= TEX_MIPMAPS; // must come before tex_img_size!
|
||||||
const size_t mipmap_size = tex_img_size(t);
|
const size_t mipmap_size = t->img_size();
|
||||||
shared_ptr<u8> mipmapData;
|
shared_ptr<u8> mipmapData;
|
||||||
AllocateAligned(mipmapData, mipmap_size);
|
AllocateAligned(mipmapData, mipmap_size);
|
||||||
CreateLevelData cld = { bpp/8, w, h, (const u8*)newData, dataSize };
|
CreateLevelData cld = { bpp/8, w, h, (const u8*)newData, dataSize };
|
||||||
tex_util_foreach_mipmap(w, h, bpp, mipmapData.get(), 0, 1, create_level, &cld);
|
tex_util_foreach_mipmap(w, h, bpp, mipmapData.get(), 0, 1, create_level, &cld);
|
||||||
t->data = mipmapData;
|
t->m_Data = mipmapData;
|
||||||
t->dataSize = mipmap_size;
|
t->m_DataSize = mipmap_size;
|
||||||
t->ofs = 0;
|
t->m_Ofs = 0;
|
||||||
|
|
||||||
return INFO::OK;
|
return INFO::OK;
|
||||||
}
|
}
|
||||||
@ -293,9 +293,9 @@ TIMER_ACCRUE(tc_plain_transform);
|
|||||||
CHECK_TEX(t);
|
CHECK_TEX(t);
|
||||||
|
|
||||||
// extract texture info
|
// extract texture info
|
||||||
const size_t w = t->w, h = t->h, bpp = t->bpp;
|
const size_t w = t->m_Width, h = t->m_Height, bpp = t->m_Bpp;
|
||||||
const size_t flags = t->flags;
|
const size_t flags = t->m_Flags;
|
||||||
u8* const srcStorage = tex_get_data(t);
|
u8* const srcStorage = t->get_data();
|
||||||
|
|
||||||
// sanity checks (not errors, we just can't handle these cases)
|
// sanity checks (not errors, we just can't handle these cases)
|
||||||
// .. unknown transform
|
// .. unknown transform
|
||||||
@ -307,7 +307,7 @@ TIMER_ACCRUE(tc_plain_transform);
|
|||||||
if(!transforms)
|
if(!transforms)
|
||||||
return INFO::OK;
|
return INFO::OK;
|
||||||
|
|
||||||
const size_t srcSize = tex_img_size(t);
|
const size_t srcSize = t->img_size();
|
||||||
size_t dstSize = srcSize;
|
size_t dstSize = srcSize;
|
||||||
|
|
||||||
if(transforms & TEX_ALPHA)
|
if(transforms & TEX_ALPHA)
|
||||||
@ -316,7 +316,7 @@ TIMER_ACCRUE(tc_plain_transform);
|
|||||||
if(bpp == 24)
|
if(bpp == 24)
|
||||||
{
|
{
|
||||||
dstSize = (srcSize / 3) * 4;
|
dstSize = (srcSize / 3) * 4;
|
||||||
t->bpp = 32;
|
t->m_Bpp = 32;
|
||||||
}
|
}
|
||||||
// remove alpha channel
|
// remove alpha channel
|
||||||
else if(bpp == 32)
|
else if(bpp == 32)
|
||||||
@ -448,11 +448,11 @@ TIMER_ACCRUE(tc_plain_transform);
|
|||||||
return INFO::TEX_CODEC_CANNOT_HANDLE;
|
return INFO::TEX_CODEC_CANNOT_HANDLE;
|
||||||
}
|
}
|
||||||
|
|
||||||
t->data = dstStorage;
|
t->m_Data = dstStorage;
|
||||||
t->dataSize = dstSize;
|
t->m_DataSize = dstSize;
|
||||||
t->ofs = 0;
|
t->m_Ofs = 0;
|
||||||
|
|
||||||
if(!(t->flags & TEX_MIPMAPS) && transforms & TEX_MIPMAPS)
|
if(!(t->m_Flags & TEX_MIPMAPS) && transforms & TEX_MIPMAPS)
|
||||||
RETURN_STATUS_IF_ERR(add_mipmaps(t, w, h, bpp, dstStorage.get(), dstSize));
|
RETURN_STATUS_IF_ERR(add_mipmaps(t, w, h, bpp, dstStorage.get(), dstSize));
|
||||||
|
|
||||||
CHECK_TEX(t);
|
CHECK_TEX(t);
|
||||||
@ -464,38 +464,38 @@ TIMER_ADD_CLIENT(tc_transform);
|
|||||||
|
|
||||||
// change <t>'s pixel format by flipping the state of all TEX_* flags
|
// change <t>'s pixel format by flipping the state of all TEX_* flags
|
||||||
// that are set in transforms.
|
// that are set in transforms.
|
||||||
Status tex_transform(Tex* t, size_t transforms)
|
Status Tex::transform(size_t transforms)
|
||||||
{
|
{
|
||||||
TIMER_ACCRUE(tc_transform);
|
TIMER_ACCRUE(tc_transform);
|
||||||
CHECK_TEX(t);
|
CHECK_TEX(this);
|
||||||
|
|
||||||
const size_t target_flags = t->flags ^ transforms;
|
const size_t target_flags = m_Flags ^ transforms;
|
||||||
size_t remaining_transforms;
|
size_t remaining_transforms;
|
||||||
for(;;)
|
for(;;)
|
||||||
{
|
{
|
||||||
remaining_transforms = target_flags ^ t->flags;
|
remaining_transforms = target_flags ^ m_Flags;
|
||||||
// we're finished (all required transforms have been done)
|
// we're finished (all required transforms have been done)
|
||||||
if(remaining_transforms == 0)
|
if(remaining_transforms == 0)
|
||||||
return INFO::OK;
|
return INFO::OK;
|
||||||
|
|
||||||
Status ret = tex_codec_transform(t, remaining_transforms);
|
Status ret = tex_codec_transform(this, remaining_transforms);
|
||||||
if(ret != INFO::OK)
|
if(ret != INFO::OK)
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
// last chance
|
// last chance
|
||||||
RETURN_STATUS_IF_ERR(plain_transform(t, remaining_transforms));
|
RETURN_STATUS_IF_ERR(plain_transform(this, remaining_transforms));
|
||||||
return INFO::OK;
|
return INFO::OK;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
// change <t>'s pixel format to the new format specified by <new_flags>.
|
// change <t>'s pixel format to the new format specified by <new_flags>.
|
||||||
// (note: this is equivalent to tex_transform(t, t->flags^new_flags).
|
// (note: this is equivalent to tex_transform(t, t->flags^new_flags).
|
||||||
Status tex_transform_to(Tex* t, size_t new_flags)
|
Status Tex::transform_to(size_t new_flags)
|
||||||
{
|
{
|
||||||
// tex_transform takes care of validating <t>
|
// tex_transform takes care of validating <t>
|
||||||
const size_t transforms = t->flags ^ new_flags;
|
const size_t transforms = m_Flags ^ new_flags;
|
||||||
return tex_transform(t, transforms);
|
return transform(transforms);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
@ -520,9 +520,9 @@ void tex_set_global_orientation(int o)
|
|||||||
static void flip_to_global_orientation(Tex* t)
|
static void flip_to_global_orientation(Tex* t)
|
||||||
{
|
{
|
||||||
// (can't use normal CHECK_TEX due to void return)
|
// (can't use normal CHECK_TEX due to void return)
|
||||||
WARN_IF_ERR(tex_validate(t));
|
WARN_IF_ERR(t->validate());
|
||||||
|
|
||||||
size_t orientation = t->flags & TEX_ORIENTATION;
|
size_t orientation = t->m_Flags & TEX_ORIENTATION;
|
||||||
// if codec knows which way around the image is (i.e. not DDS):
|
// if codec knows which way around the image is (i.e. not DDS):
|
||||||
if(orientation)
|
if(orientation)
|
||||||
{
|
{
|
||||||
@ -534,10 +534,10 @@ static void flip_to_global_orientation(Tex* t)
|
|||||||
// indicate image is at global orientation. this is still done even
|
// indicate image is at global orientation. this is still done even
|
||||||
// if the codec doesn't know: the default orientation should be chosen
|
// if the codec doesn't know: the default orientation should be chosen
|
||||||
// to make that work correctly (see "Default Orientation" in docs).
|
// to make that work correctly (see "Default Orientation" in docs).
|
||||||
t->flags = (t->flags & ~TEX_ORIENTATION) | global_orientation;
|
t->m_Flags = (t->m_Flags & ~TEX_ORIENTATION) | global_orientation;
|
||||||
|
|
||||||
// (can't use normal CHECK_TEX due to void return)
|
// (can't use normal CHECK_TEX due to void return)
|
||||||
WARN_IF_ERR(tex_validate(t));
|
WARN_IF_ERR(t->validate());
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
@ -590,29 +590,29 @@ bool tex_is_known_extension(const VfsPath& pathname)
|
|||||||
//
|
//
|
||||||
// we need only add bookkeeping information and "wrap" it in
|
// we need only add bookkeeping information and "wrap" it in
|
||||||
// our Tex struct, hence the name.
|
// our Tex struct, hence the name.
|
||||||
Status tex_wrap(size_t w, size_t h, size_t bpp, size_t flags, const shared_ptr<u8>& data, size_t ofs, Tex* t)
|
Status Tex::wrap(size_t w, size_t h, size_t bpp, size_t flags, const shared_ptr<u8>& data, size_t ofs)
|
||||||
{
|
{
|
||||||
t->w = w;
|
m_Width = w;
|
||||||
t->h = h;
|
m_Height = h;
|
||||||
t->bpp = bpp;
|
m_Bpp = bpp;
|
||||||
t->flags = flags;
|
m_Flags = flags;
|
||||||
t->data = data;
|
m_Data = data;
|
||||||
t->dataSize = ofs + w*h*bpp/8;
|
m_DataSize = ofs + w*h*bpp/8;
|
||||||
t->ofs = ofs;
|
m_Ofs = ofs;
|
||||||
|
|
||||||
CHECK_TEX(t);
|
CHECK_TEX(this);
|
||||||
return INFO::OK;
|
return INFO::OK;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
// free all resources associated with the image and make further
|
// free all resources associated with the image and make further
|
||||||
// use of it impossible.
|
// use of it impossible.
|
||||||
void tex_free(Tex* t)
|
void Tex::free()
|
||||||
{
|
{
|
||||||
// do not validate <t> - this is called from tex_load if loading
|
// do not validate <t> - this is called from tex_load if loading
|
||||||
// failed, so not all fields may be valid.
|
// failed, so not all fields may be valid.
|
||||||
|
|
||||||
t->data.reset();
|
m_Data.reset();
|
||||||
|
|
||||||
// do not zero out the fields! that could lead to trouble since
|
// do not zero out the fields! that could lead to trouble since
|
||||||
// ogl_tex_upload followed by ogl_tex_free is legit, but would
|
// ogl_tex_upload followed by ogl_tex_free is legit, but would
|
||||||
@ -626,47 +626,49 @@ void tex_free(Tex* t)
|
|||||||
|
|
||||||
// returns a pointer to the image data (pixels), taking into account any
|
// returns a pointer to the image data (pixels), taking into account any
|
||||||
// header(s) that may come before it.
|
// header(s) that may come before it.
|
||||||
u8* tex_get_data(const Tex* t)
|
u8* Tex::get_data()
|
||||||
{
|
{
|
||||||
// (can't use normal CHECK_TEX due to u8* return value)
|
// (can't use normal CHECK_TEX due to u8* return value)
|
||||||
WARN_IF_ERR(tex_validate(t));
|
WARN_IF_ERR(validate());
|
||||||
|
|
||||||
u8* p = t->data.get();
|
u8* p = m_Data.get();
|
||||||
if(!p)
|
if(!p)
|
||||||
return 0;
|
return 0;
|
||||||
return p + t->ofs;
|
return p + m_Ofs;
|
||||||
}
|
}
|
||||||
|
|
||||||
// returns colour of 1x1 mipmap level
|
// returns colour of 1x1 mipmap level
|
||||||
u32 tex_get_average_colour(const Tex* t)
|
u32 Tex::get_average_colour() const
|
||||||
{
|
{
|
||||||
// require mipmaps
|
// require mipmaps
|
||||||
if(!(t->flags & TEX_MIPMAPS))
|
if(!(m_Flags & TEX_MIPMAPS))
|
||||||
return 0;
|
return 0;
|
||||||
|
|
||||||
// find the total size of image data
|
// find the total size of image data
|
||||||
size_t size = tex_img_size(t);
|
size_t size = img_size();
|
||||||
|
|
||||||
// compute the size of the last (1x1) mipmap level
|
// compute the size of the last (1x1) mipmap level
|
||||||
const size_t data_padding = (t->flags & TEX_DXT)? 4 : 1;
|
const size_t data_padding = (m_Flags & TEX_DXT)? 4 : 1;
|
||||||
size_t last_level_size = (size_t)(data_padding * data_padding * t->bpp/8);
|
size_t last_level_size = (size_t)(data_padding * data_padding * m_Bpp/8);
|
||||||
|
|
||||||
// construct a new texture based on the current one,
|
// construct a new texture based on the current one,
|
||||||
// but set its data pointer offset to the last mipmap level's data
|
// but only include the last mipmap level
|
||||||
Tex basetex = *t;
|
// do this so that we can use the general conversion methods for the pixel data
|
||||||
basetex.w = 1;
|
Tex basetex = *this;
|
||||||
basetex.h = 1;
|
uint8_t *data = new uint8_t[last_level_size];
|
||||||
basetex.ofs += size - last_level_size;
|
memcpy(data, m_Data.get() + m_Ofs + size - last_level_size, last_level_size);
|
||||||
|
boost::shared_ptr<uint8_t> sdata(data);
|
||||||
|
basetex.wrap(1, 1, m_Bpp, m_Flags, sdata, 0);
|
||||||
|
|
||||||
// convert to BGRA
|
// convert to BGRA
|
||||||
WARN_IF_ERR(tex_transform_to(&basetex, TEX_BGR | TEX_ALPHA));
|
WARN_IF_ERR(basetex.transform_to(TEX_BGR | TEX_ALPHA));
|
||||||
|
|
||||||
// extract components into u32
|
// extract components into u32
|
||||||
ENSURE(basetex.dataSize >= basetex.ofs+4);
|
ENSURE(basetex.m_DataSize >= basetex.m_Ofs+4);
|
||||||
u8 b = basetex.data.get()[basetex.ofs];
|
u8 b = basetex.m_Data.get()[basetex.m_Ofs];
|
||||||
u8 g = basetex.data.get()[basetex.ofs+1];
|
u8 g = basetex.m_Data.get()[basetex.m_Ofs+1];
|
||||||
u8 r = basetex.data.get()[basetex.ofs+2];
|
u8 r = basetex.m_Data.get()[basetex.m_Ofs+2];
|
||||||
u8 a = basetex.data.get()[basetex.ofs+3];
|
u8 a = basetex.m_Data.get()[basetex.m_Ofs+3];
|
||||||
return b + (g << 8) + (r << 16) + (a << 24);
|
return b + (g << 8) + (r << 16) + (a << 24);
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -680,15 +682,15 @@ static void add_level_size(size_t UNUSED(level), size_t UNUSED(level_w), size_t
|
|||||||
// return total byte size of the image pixels. (including mipmaps!)
|
// return total byte size of the image pixels. (including mipmaps!)
|
||||||
// this is preferable to calculating manually because it's
|
// this is preferable to calculating manually because it's
|
||||||
// less error-prone (e.g. confusing bits_per_pixel with bytes).
|
// less error-prone (e.g. confusing bits_per_pixel with bytes).
|
||||||
size_t tex_img_size(const Tex* t)
|
size_t Tex::img_size() const
|
||||||
{
|
{
|
||||||
// (can't use normal CHECK_TEX due to size_t return value)
|
// (can't use normal CHECK_TEX due to size_t return value)
|
||||||
WARN_IF_ERR(tex_validate(t));
|
WARN_IF_ERR(validate());
|
||||||
|
|
||||||
const int levels_to_skip = (t->flags & TEX_MIPMAPS)? 0 : TEX_BASE_LEVEL_ONLY;
|
const int levels_to_skip = (m_Flags & TEX_MIPMAPS)? 0 : TEX_BASE_LEVEL_ONLY;
|
||||||
const size_t data_padding = (t->flags & TEX_DXT)? 4 : 1;
|
const size_t data_padding = (m_Flags & TEX_DXT)? 4 : 1;
|
||||||
size_t out_size = 0;
|
size_t out_size = 0;
|
||||||
tex_util_foreach_mipmap(t->w, t->h, t->bpp, 0, levels_to_skip, data_padding, add_level_size, &out_size);
|
tex_util_foreach_mipmap(m_Width, m_Height, m_Bpp, 0, levels_to_skip, data_padding, add_level_size, &out_size);
|
||||||
return out_size;
|
return out_size;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -714,57 +716,57 @@ size_t tex_hdr_size(const VfsPath& filename)
|
|||||||
// read/write from memory and disk
|
// read/write from memory and disk
|
||||||
//-----------------------------------------------------------------------------
|
//-----------------------------------------------------------------------------
|
||||||
|
|
||||||
Status tex_decode(const shared_ptr<u8>& data, size_t dataSize, Tex* t)
|
Status Tex::decode(const shared_ptr<u8>& Data, size_t DataSize)
|
||||||
{
|
{
|
||||||
const TexCodecVTbl* c;
|
const TexCodecVTbl* c;
|
||||||
RETURN_STATUS_IF_ERR(tex_codec_for_header(data.get(), dataSize, &c));
|
RETURN_STATUS_IF_ERR(tex_codec_for_header(Data.get(), DataSize, &c));
|
||||||
|
|
||||||
// make sure the entire header is available
|
// make sure the entire header is available
|
||||||
const size_t min_hdr_size = c->hdr_size(0);
|
const size_t min_hdr_size = c->hdr_size(0);
|
||||||
if(dataSize < min_hdr_size)
|
if(DataSize < min_hdr_size)
|
||||||
WARN_RETURN(ERR::TEX_INCOMPLETE_HEADER);
|
WARN_RETURN(ERR::TEX_INCOMPLETE_HEADER);
|
||||||
const size_t hdr_size = c->hdr_size(data.get());
|
const size_t hdr_size = c->hdr_size(Data.get());
|
||||||
if(dataSize < hdr_size)
|
if(DataSize < hdr_size)
|
||||||
WARN_RETURN(ERR::TEX_INCOMPLETE_HEADER);
|
WARN_RETURN(ERR::TEX_INCOMPLETE_HEADER);
|
||||||
|
|
||||||
t->data = data;
|
m_Data = Data;
|
||||||
t->dataSize = dataSize;
|
m_DataSize = DataSize;
|
||||||
t->ofs = hdr_size;
|
m_Ofs = hdr_size;
|
||||||
|
|
||||||
RETURN_STATUS_IF_ERR(c->decode((rpU8)data.get(), dataSize, t));
|
RETURN_STATUS_IF_ERR(c->decode((rpU8)Data.get(), DataSize, this));
|
||||||
|
|
||||||
// sanity checks
|
// sanity checks
|
||||||
if(!t->w || !t->h || t->bpp > 32)
|
if(!m_Width || !m_Height || m_Bpp > 32)
|
||||||
WARN_RETURN(ERR::TEX_FMT_INVALID);
|
WARN_RETURN(ERR::TEX_FMT_INVALID);
|
||||||
if(t->dataSize < t->ofs + tex_img_size(t))
|
if(m_DataSize < m_Ofs + img_size())
|
||||||
WARN_RETURN(ERR::TEX_INVALID_SIZE);
|
WARN_RETURN(ERR::TEX_INVALID_SIZE);
|
||||||
|
|
||||||
flip_to_global_orientation(t);
|
flip_to_global_orientation(this);
|
||||||
|
|
||||||
CHECK_TEX(t);
|
CHECK_TEX(this);
|
||||||
|
|
||||||
return INFO::OK;
|
return INFO::OK;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
Status tex_encode(Tex* t, const OsPath& extension, DynArray* da)
|
Status Tex::encode(const OsPath& extension, DynArray* da)
|
||||||
{
|
{
|
||||||
CHECK_TEX(t);
|
CHECK_TEX(this);
|
||||||
WARN_RETURN_STATUS_IF_ERR(tex_validate_plain_format(t->bpp, t->flags));
|
WARN_RETURN_STATUS_IF_ERR(tex_validate_plain_format(m_Bpp, m_Flags));
|
||||||
|
|
||||||
// we could be clever here and avoid the extra alloc if our current
|
// we could be clever here and avoid the extra alloc if our current
|
||||||
// memory block ensued from the same kind of texture file. this is
|
// memory block ensued from the same kind of texture file. this is
|
||||||
// most likely the case if in_img == tex_get_data() + c->hdr_size(0).
|
// most likely the case if in_img == tex_get_data() + c->hdr_size(0).
|
||||||
// this would make for zero-copy IO.
|
// this would make for zero-copy IO.
|
||||||
|
|
||||||
const size_t max_out_size = tex_img_size(t)*4 + 256*KiB;
|
const size_t max_out_size = img_size()*4 + 256*KiB;
|
||||||
RETURN_STATUS_IF_ERR(da_alloc(da, max_out_size));
|
RETURN_STATUS_IF_ERR(da_alloc(da, max_out_size));
|
||||||
|
|
||||||
const TexCodecVTbl* c;
|
const TexCodecVTbl* c;
|
||||||
WARN_RETURN_STATUS_IF_ERR(tex_codec_for_filename(extension, &c));
|
WARN_RETURN_STATUS_IF_ERR(tex_codec_for_filename(extension, &c));
|
||||||
|
|
||||||
// encode into <da>
|
// encode into <da>
|
||||||
Status err = c->encode(t, da);
|
Status err = c->encode(this, da);
|
||||||
if(err < 0)
|
if(err < 0)
|
||||||
{
|
{
|
||||||
(void)da_free(da);
|
(void)da_free(da);
|
||||||
|
@ -1,4 +1,4 @@
|
|||||||
/* Copyright (c) 2010 Wildfire Games
|
/* Copyright (c) 2014 Wildfire Games
|
||||||
*
|
*
|
||||||
* Permission is hereby granted, free of charge, to any person obtaining
|
* Permission is hereby granted, free of charge, to any person obtaining
|
||||||
* a copy of this software and associated documentation files (the
|
* a copy of this software and associated documentation files (the
|
||||||
@ -201,7 +201,6 @@ enum TexFlags
|
|||||||
TEX_UNDEFINED_FLAGS = ~0x1FF
|
TEX_UNDEFINED_FLAGS = ~0x1FF
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* stores all data describing an image.
|
* stores all data describing an image.
|
||||||
* we try to minimize size, since this is stored in OglTex resources
|
* we try to minimize size, since this is stored in OglTex resources
|
||||||
@ -214,9 +213,9 @@ struct Tex
|
|||||||
* (which may occur when being loaded), this may be replaced with
|
* (which may occur when being loaded), this may be replaced with
|
||||||
* a new buffer (e.g. if decompressing file contents).
|
* a new buffer (e.g. if decompressing file contents).
|
||||||
**/
|
**/
|
||||||
shared_ptr<u8> data;
|
shared_ptr<u8> m_Data;
|
||||||
|
|
||||||
size_t dataSize;
|
size_t m_DataSize;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* offset to image data in file. this is required since
|
* offset to image data in file. this is required since
|
||||||
@ -224,26 +223,141 @@ struct Tex
|
|||||||
* returns the actual file buffer. zero-copy load and
|
* returns the actual file buffer. zero-copy load and
|
||||||
* write-back to file is also made possible.
|
* write-back to file is also made possible.
|
||||||
**/
|
**/
|
||||||
size_t ofs;
|
size_t m_Ofs;
|
||||||
|
|
||||||
size_t w;
|
size_t m_Width;
|
||||||
size_t h;
|
size_t m_Height;
|
||||||
size_t bpp;
|
size_t m_Bpp;
|
||||||
|
|
||||||
/// see TexFlags and "Format Conversion" in docs.
|
/// see TexFlags and "Format Conversion" in docs.
|
||||||
size_t flags;
|
size_t m_Flags;
|
||||||
|
|
||||||
|
~Tex()
|
||||||
|
{
|
||||||
|
free();
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Is the texture object valid and self-consistent?
|
||||||
|
*
|
||||||
|
* @return Status
|
||||||
|
**/
|
||||||
|
Status validate() const;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* free all resources associated with the image and make further
|
||||||
|
* use of it impossible.
|
||||||
|
*
|
||||||
|
* @return Status
|
||||||
|
**/
|
||||||
|
void free();
|
||||||
|
|
||||||
|
/**
|
||||||
|
* decode an in-memory texture file into texture object.
|
||||||
|
*
|
||||||
|
* FYI, currently BMP, TGA, JPG, JP2, PNG, DDS are supported - but don't
|
||||||
|
* rely on this (not all codecs may be included).
|
||||||
|
*
|
||||||
|
* @param data Input data.
|
||||||
|
* @param data_size Its size [bytes].
|
||||||
|
* @return Status.
|
||||||
|
**/
|
||||||
|
Status decode(const shared_ptr<u8>& data, size_t data_size);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* encode a texture into a memory buffer in the desired file format.
|
||||||
|
*
|
||||||
|
* @param extension (including '.').
|
||||||
|
* @param da Output memory array. Allocated here; caller must free it
|
||||||
|
* when no longer needed. Invalid unless function succeeds.
|
||||||
|
* @return Status
|
||||||
|
**/
|
||||||
|
Status encode(const OsPath& extension, DynArray* da);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* store the given image data into a Tex object; this will be as if
|
||||||
|
* it had been loaded via tex_load.
|
||||||
|
*
|
||||||
|
* rationale: support for in-memory images is necessary for
|
||||||
|
* emulation of glCompressedTexImage2D and useful overall.
|
||||||
|
* however, we don't want to provide an alternate interface for each API;
|
||||||
|
* these would have to be changed whenever fields are added to Tex.
|
||||||
|
* instead, provide one entry point for specifying images.
|
||||||
|
* note: since we do not know how \<img\> was allocated, the caller must free
|
||||||
|
* it themselves (after calling tex_free, which is required regardless of
|
||||||
|
* alloc type).
|
||||||
|
*
|
||||||
|
* we need only add bookkeeping information and "wrap" it in
|
||||||
|
* our Tex struct, hence the name.
|
||||||
|
*
|
||||||
|
* @param w,h Pixel dimensions.
|
||||||
|
* @param bpp Bits per pixel.
|
||||||
|
* @param flags TexFlags.
|
||||||
|
* @param data Img texture data. note: size is calculated from other params.
|
||||||
|
* @param ofs
|
||||||
|
* @return Status
|
||||||
|
**/
|
||||||
|
Status wrap(size_t w, size_t h, size_t bpp, size_t flags, const shared_ptr<u8>& data, size_t ofs);
|
||||||
|
|
||||||
|
//
|
||||||
|
// modify image
|
||||||
|
//
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Change \<t\>'s pixel format.
|
||||||
|
*
|
||||||
|
* @param transforms TexFlags that are to be flipped.
|
||||||
|
* @return Status
|
||||||
|
**/
|
||||||
|
Status transform(size_t transforms);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Change \<t\>'s pixel format (2nd version)
|
||||||
|
* (note: this is equivalent to tex_transform(t, t-\>flags^new_flags).
|
||||||
|
*
|
||||||
|
* @param new_flags desired new value of TexFlags.
|
||||||
|
* @return Status
|
||||||
|
**/
|
||||||
|
Status transform_to(size_t new_flags);
|
||||||
|
|
||||||
|
//
|
||||||
|
// return image information
|
||||||
|
//
|
||||||
|
|
||||||
|
/**
|
||||||
|
* rationale: since Tex is a struct, its fields are accessible to callers.
|
||||||
|
* this is more for C compatibility than convenience; the following should
|
||||||
|
* be used instead of direct access to the corresponding fields because
|
||||||
|
* they take care of some dirty work.
|
||||||
|
**/
|
||||||
|
|
||||||
|
/**
|
||||||
|
* return a pointer to the image data (pixels), taking into account any
|
||||||
|
* header(s) that may come before it.
|
||||||
|
*
|
||||||
|
* @return pointer to data returned by mem_get_ptr (holds reference)!
|
||||||
|
**/
|
||||||
|
u8* get_data();
|
||||||
|
|
||||||
|
/**
|
||||||
|
* return the ARGB value of the 1x1 mipmap level of the texture.
|
||||||
|
*
|
||||||
|
* @return ARGB value (or 0 if texture does not have mipmaps)
|
||||||
|
**/
|
||||||
|
u32 get_average_colour() const;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* return total byte size of the image pixels. (including mipmaps!)
|
||||||
|
* rationale: this is preferable to calculating manually because it's
|
||||||
|
* less error-prone (e.g. confusing bits_per_pixel with bytes).
|
||||||
|
*
|
||||||
|
* @return size [bytes]
|
||||||
|
**/
|
||||||
|
size_t img_size() const;
|
||||||
|
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Is the texture object valid and self-consistent?
|
|
||||||
*
|
|
||||||
* @param t
|
|
||||||
* @return Status
|
|
||||||
**/
|
|
||||||
extern Status tex_validate(const Tex* t);
|
|
||||||
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Set the orientation to which all loaded images will
|
* Set the orientation to which all loaded images will
|
||||||
* automatically be converted (excepting file formats that don't specify
|
* automatically be converted (excepting file formats that don't specify
|
||||||
@ -269,129 +383,6 @@ extern void tex_codec_register_all();
|
|||||||
**/
|
**/
|
||||||
extern void tex_codec_unregister_all();
|
extern void tex_codec_unregister_all();
|
||||||
|
|
||||||
/**
|
|
||||||
* decode an in-memory texture file into texture object.
|
|
||||||
*
|
|
||||||
* FYI, currently BMP, TGA, JPG, JP2, PNG, DDS are supported - but don't
|
|
||||||
* rely on this (not all codecs may be included).
|
|
||||||
*
|
|
||||||
* @param data Input data.
|
|
||||||
* @param data_size Its size [bytes].
|
|
||||||
* @param t Output texture object.
|
|
||||||
* @return Status.
|
|
||||||
**/
|
|
||||||
extern Status tex_decode(const shared_ptr<u8>& data, size_t data_size, Tex* t);
|
|
||||||
|
|
||||||
/**
|
|
||||||
* encode a texture into a memory buffer in the desired file format.
|
|
||||||
*
|
|
||||||
* @param t Input texture object.
|
|
||||||
* @param extension (including '.').
|
|
||||||
* @param da Output memory array. Allocated here; caller must free it
|
|
||||||
* when no longer needed. Invalid unless function succeeds.
|
|
||||||
* @return Status
|
|
||||||
**/
|
|
||||||
extern Status tex_encode(Tex* t, const OsPath& extension, DynArray* da);
|
|
||||||
|
|
||||||
/**
|
|
||||||
* store the given image data into a Tex object; this will be as if
|
|
||||||
* it had been loaded via tex_load.
|
|
||||||
*
|
|
||||||
* rationale: support for in-memory images is necessary for
|
|
||||||
* emulation of glCompressedTexImage2D and useful overall.
|
|
||||||
* however, we don't want to provide an alternate interface for each API;
|
|
||||||
* these would have to be changed whenever fields are added to Tex.
|
|
||||||
* instead, provide one entry point for specifying images.
|
|
||||||
* note: since we do not know how \<img\> was allocated, the caller must free
|
|
||||||
* it themselves (after calling tex_free, which is required regardless of
|
|
||||||
* alloc type).
|
|
||||||
*
|
|
||||||
* we need only add bookkeeping information and "wrap" it in
|
|
||||||
* our Tex struct, hence the name.
|
|
||||||
*
|
|
||||||
* @param w,h Pixel dimensions.
|
|
||||||
* @param bpp Bits per pixel.
|
|
||||||
* @param flags TexFlags.
|
|
||||||
* @param data Img texture data. note: size is calculated from other params.
|
|
||||||
* @param ofs
|
|
||||||
* @param t output texture object.
|
|
||||||
* @return Status
|
|
||||||
**/
|
|
||||||
extern Status tex_wrap(size_t w, size_t h, size_t bpp, size_t flags, const shared_ptr<u8>& data, size_t ofs, Tex* t);
|
|
||||||
|
|
||||||
/**
|
|
||||||
* free all resources associated with the image and make further
|
|
||||||
* use of it impossible.
|
|
||||||
*
|
|
||||||
* @param t texture object (note: not zeroed afterwards; see impl)
|
|
||||||
* @return Status
|
|
||||||
**/
|
|
||||||
extern void tex_free(Tex* t);
|
|
||||||
|
|
||||||
|
|
||||||
//
|
|
||||||
// modify image
|
|
||||||
//
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Change \<t\>'s pixel format.
|
|
||||||
*
|
|
||||||
* @param t Input texture object.
|
|
||||||
* @param transforms TexFlags that are to be flipped.
|
|
||||||
* @return Status
|
|
||||||
**/
|
|
||||||
extern Status tex_transform(Tex* t, size_t transforms);
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Change \<t\>'s pixel format (2nd version)
|
|
||||||
* (note: this is equivalent to tex_transform(t, t-\>flags^new_flags).
|
|
||||||
*
|
|
||||||
* @param t Input texture object.
|
|
||||||
* @param new_flags desired new value of TexFlags.
|
|
||||||
* @return Status
|
|
||||||
**/
|
|
||||||
extern Status tex_transform_to(Tex* t, size_t new_flags);
|
|
||||||
|
|
||||||
|
|
||||||
//
|
|
||||||
// return image information
|
|
||||||
//
|
|
||||||
|
|
||||||
/**
|
|
||||||
* rationale: since Tex is a struct, its fields are accessible to callers.
|
|
||||||
* this is more for C compatibility than convenience; the following should
|
|
||||||
* be used instead of direct access to the corresponding fields because
|
|
||||||
* they take care of some dirty work.
|
|
||||||
**/
|
|
||||||
|
|
||||||
/**
|
|
||||||
* return a pointer to the image data (pixels), taking into account any
|
|
||||||
* header(s) that may come before it.
|
|
||||||
*
|
|
||||||
* @param t input texture object
|
|
||||||
* @return pointer to data returned by mem_get_ptr (holds reference)!
|
|
||||||
**/
|
|
||||||
extern u8* tex_get_data(const Tex* t);
|
|
||||||
|
|
||||||
/**
|
|
||||||
* return the ARGB value of the 1x1 mipmap level of the texture.
|
|
||||||
*
|
|
||||||
* @param t input texture object
|
|
||||||
* @return ARGB value (or 0 if texture does not have mipmaps)
|
|
||||||
**/
|
|
||||||
extern u32 tex_get_average_colour(const Tex* t);
|
|
||||||
|
|
||||||
/**
|
|
||||||
* return total byte size of the image pixels. (including mipmaps!)
|
|
||||||
* rationale: this is preferable to calculating manually because it's
|
|
||||||
* less error-prone (e.g. confusing bits_per_pixel with bytes).
|
|
||||||
*
|
|
||||||
* @param t input texture object
|
|
||||||
* @return size [bytes]
|
|
||||||
**/
|
|
||||||
extern size_t tex_img_size(const Tex* t);
|
|
||||||
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* special value for levels_to_skip: the callback will only be called
|
* special value for levels_to_skip: the callback will only be called
|
||||||
* for the base mipmap level (i.e. 100%)
|
* for the base mipmap level (i.e. 100%)
|
||||||
@ -464,13 +455,4 @@ extern bool tex_is_known_extension(const VfsPath& pathname);
|
|||||||
**/
|
**/
|
||||||
extern size_t tex_hdr_size(const VfsPath& filename);
|
extern size_t tex_hdr_size(const VfsPath& filename);
|
||||||
|
|
||||||
// RAII wrapper
|
|
||||||
struct ScopedTex : public Tex
|
|
||||||
{
|
|
||||||
~ScopedTex()
|
|
||||||
{
|
|
||||||
tex_free(this);
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
#endif // INCLUDED_TEX
|
#endif // INCLUDED_TEX
|
||||||
|
@ -116,10 +116,10 @@ static Status bmp_decode(rpU8 data, size_t UNUSED(size), Tex* RESTRICT t)
|
|||||||
if(compress != BI_RGB)
|
if(compress != BI_RGB)
|
||||||
WARN_RETURN(ERR::TEX_COMPRESSED);
|
WARN_RETURN(ERR::TEX_COMPRESSED);
|
||||||
|
|
||||||
t->w = w;
|
t->m_Width = w;
|
||||||
t->h = h;
|
t->m_Height = h;
|
||||||
t->bpp = bpp;
|
t->m_Bpp = bpp;
|
||||||
t->flags = flags;
|
t->m_Flags = flags;
|
||||||
return INFO::OK;
|
return INFO::OK;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -127,11 +127,11 @@ static Status bmp_decode(rpU8 data, size_t UNUSED(size), Tex* RESTRICT t)
|
|||||||
static Status bmp_encode(Tex* RESTRICT t, DynArray* RESTRICT da)
|
static Status bmp_encode(Tex* RESTRICT t, DynArray* RESTRICT da)
|
||||||
{
|
{
|
||||||
const size_t hdr_size = sizeof(BmpHeader); // needed for BITMAPFILEHEADER
|
const size_t hdr_size = sizeof(BmpHeader); // needed for BITMAPFILEHEADER
|
||||||
const size_t img_size = tex_img_size(t);
|
const size_t img_size = t->img_size();
|
||||||
const size_t file_size = hdr_size + img_size;
|
const size_t file_size = hdr_size + img_size;
|
||||||
const i32 h = (t->flags & TEX_TOP_DOWN)? -(i32)t->h : (i32)t->h;
|
const i32 h = (t->m_Flags & TEX_TOP_DOWN)? -(i32)t->m_Height : (i32)t->m_Height;
|
||||||
|
|
||||||
size_t transforms = t->flags;
|
size_t transforms = t->m_Flags;
|
||||||
transforms &= ~TEX_ORIENTATION; // no flip needed - we can set top-down bit.
|
transforms &= ~TEX_ORIENTATION; // no flip needed - we can set top-down bit.
|
||||||
transforms ^= TEX_BGR; // BMP is native BGR.
|
transforms ^= TEX_BGR; // BMP is native BGR.
|
||||||
|
|
||||||
@ -145,10 +145,10 @@ static Status bmp_encode(Tex* RESTRICT t, DynArray* RESTRICT da)
|
|||||||
|
|
||||||
// BITMAPINFOHEADER
|
// BITMAPINFOHEADER
|
||||||
40, // biSize = sizeof(BITMAPINFOHEADER)
|
40, // biSize = sizeof(BITMAPINFOHEADER)
|
||||||
(i32)t->w,
|
(i32)t->m_Width,
|
||||||
h,
|
h,
|
||||||
1, // biPlanes
|
1, // biPlanes
|
||||||
(u16)t->bpp,
|
(u16)t->m_Bpp,
|
||||||
BI_RGB, // biCompression
|
BI_RGB, // biCompression
|
||||||
(u32)img_size, // biSizeImage
|
(u32)img_size, // biSizeImage
|
||||||
0, 0, 0, 0 // unused (bi?PelsPerMeter, biClr*)
|
0, 0, 0, 0 // unused (bi?PelsPerMeter, biClr*)
|
||||||
|
@ -175,9 +175,9 @@ std::vector<RowPtr> tex_codec_alloc_rows(const u8* data, size_t h, size_t pitch,
|
|||||||
|
|
||||||
Status tex_codec_write(Tex* t, size_t transforms, const void* hdr, size_t hdr_size, DynArray* da)
|
Status tex_codec_write(Tex* t, size_t transforms, const void* hdr, size_t hdr_size, DynArray* da)
|
||||||
{
|
{
|
||||||
RETURN_STATUS_IF_ERR(tex_transform(t, transforms));
|
RETURN_STATUS_IF_ERR(t->transform(transforms));
|
||||||
|
|
||||||
void* img_data = tex_get_data(t); const size_t img_size = tex_img_size(t);
|
void* img_data = t->get_data(); const size_t img_size = t->img_size();
|
||||||
RETURN_STATUS_IF_ERR(da_append(da, hdr, hdr_size));
|
RETURN_STATUS_IF_ERR(da_append(da, hdr, hdr_size));
|
||||||
RETURN_STATUS_IF_ERR(da_append(da, img_data, img_size));
|
RETURN_STATUS_IF_ERR(da_append(da, img_data, img_size));
|
||||||
return INFO::OK;
|
return INFO::OK;
|
||||||
|
@ -279,22 +279,22 @@ static Status s3tc_decompress(Tex* t)
|
|||||||
// - adding or stripping alpha channels during transform is not
|
// - adding or stripping alpha channels during transform is not
|
||||||
// our job; we merely output the same pixel format as given
|
// our job; we merely output the same pixel format as given
|
||||||
// (tex.cpp's plain transform could cover it, if ever needed).
|
// (tex.cpp's plain transform could cover it, if ever needed).
|
||||||
const size_t dxt = t->flags & TEX_DXT;
|
const size_t dxt = t->m_Flags & TEX_DXT;
|
||||||
const size_t out_bpp = (dxt != 1)? 32 : 24;
|
const size_t out_bpp = (dxt != 1)? 32 : 24;
|
||||||
const size_t out_size = tex_img_size(t) * out_bpp / t->bpp;
|
const size_t out_size = t->img_size() * out_bpp / t->m_Bpp;
|
||||||
shared_ptr<u8> decompressedData;
|
shared_ptr<u8> decompressedData;
|
||||||
AllocateAligned(decompressedData, out_size, pageSize);
|
AllocateAligned(decompressedData, out_size, pageSize);
|
||||||
|
|
||||||
const size_t s3tc_block_size = (dxt == 3 || dxt == 5)? 16 : 8;
|
const size_t s3tc_block_size = (dxt == 3 || dxt == 5)? 16 : 8;
|
||||||
S3tcDecompressInfo di = { dxt, s3tc_block_size, out_bpp/8, decompressedData.get() };
|
S3tcDecompressInfo di = { dxt, s3tc_block_size, out_bpp/8, decompressedData.get() };
|
||||||
const u8* s3tc_data = tex_get_data(t);
|
const u8* s3tc_data = t->get_data();
|
||||||
const int levels_to_skip = (t->flags & TEX_MIPMAPS)? 0 : TEX_BASE_LEVEL_ONLY;
|
const int levels_to_skip = (t->m_Flags & TEX_MIPMAPS)? 0 : TEX_BASE_LEVEL_ONLY;
|
||||||
tex_util_foreach_mipmap(t->w, t->h, t->bpp, s3tc_data, levels_to_skip, 4, s3tc_decompress_level, &di);
|
tex_util_foreach_mipmap(t->m_Width, t->m_Height, t->m_Bpp, s3tc_data, levels_to_skip, 4, s3tc_decompress_level, &di);
|
||||||
t->data = decompressedData;
|
t->m_Data = decompressedData;
|
||||||
t->dataSize = out_size;
|
t->m_DataSize = out_size;
|
||||||
t->ofs = 0;
|
t->m_Ofs = 0;
|
||||||
t->bpp = out_bpp;
|
t->m_Bpp = out_bpp;
|
||||||
t->flags &= ~TEX_DXT;
|
t->m_Flags &= ~TEX_DXT;
|
||||||
return INFO::OK;
|
return INFO::OK;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -607,7 +607,7 @@ static size_t dds_hdr_size(const u8* UNUSED(file))
|
|||||||
static Status dds_decode(rpU8 data, size_t UNUSED(size), Tex* RESTRICT t)
|
static Status dds_decode(rpU8 data, size_t UNUSED(size), Tex* RESTRICT t)
|
||||||
{
|
{
|
||||||
const DDS_HEADER* sd = (const DDS_HEADER*)(data+4);
|
const DDS_HEADER* sd = (const DDS_HEADER*)(data+4);
|
||||||
RETURN_STATUS_IF_ERR(decode_sd(sd, t->w, t->h, t->bpp, t->flags));
|
RETURN_STATUS_IF_ERR(decode_sd(sd, t->m_Width, t->m_Height, t->m_Bpp, t->m_Flags));
|
||||||
return INFO::OK;
|
return INFO::OK;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -626,8 +626,8 @@ static Status dds_transform(Tex* t, size_t transforms)
|
|||||||
{
|
{
|
||||||
TIMER_ACCRUE(tc_dds_transform);
|
TIMER_ACCRUE(tc_dds_transform);
|
||||||
|
|
||||||
size_t mipmaps = t->flags & TEX_MIPMAPS;
|
size_t mipmaps = t->m_Flags & TEX_MIPMAPS;
|
||||||
size_t dxt = t->flags & TEX_DXT;
|
size_t dxt = t->m_Flags & TEX_DXT;
|
||||||
ENSURE(is_valid_dxt(dxt));
|
ENSURE(is_valid_dxt(dxt));
|
||||||
|
|
||||||
const size_t transform_mipmaps = transforms & TEX_MIPMAPS;
|
const size_t transform_mipmaps = transforms & TEX_MIPMAPS;
|
||||||
@ -637,7 +637,7 @@ static Status dds_transform(Tex* t, size_t transforms)
|
|||||||
{
|
{
|
||||||
// we don't need to actually change anything except the flag - the
|
// we don't need to actually change anything except the flag - the
|
||||||
// mipmap levels will just be treated as trailing junk
|
// mipmap levels will just be treated as trailing junk
|
||||||
t->flags &= ~TEX_MIPMAPS;
|
t->m_Flags &= ~TEX_MIPMAPS;
|
||||||
return INFO::OK;
|
return INFO::OK;
|
||||||
}
|
}
|
||||||
// requesting decompression
|
// requesting decompression
|
||||||
|
@ -503,16 +503,8 @@ static Status jpg_decode_impl(rpU8 data, size_t size, jpeg_decompress_struct* ci
|
|||||||
if(cinfo->err->num_warnings != 0)
|
if(cinfo->err->num_warnings != 0)
|
||||||
ret = WARN::TEX_INVALID_DATA;
|
ret = WARN::TEX_INVALID_DATA;
|
||||||
|
|
||||||
// store image info
|
// store image info and validate
|
||||||
t->data = img;
|
return ret | t->wrap(w,h,bpp,flags,img,0);
|
||||||
t->dataSize = imgSize;
|
|
||||||
t->ofs = 0;
|
|
||||||
t->w = w;
|
|
||||||
t->h = h;
|
|
||||||
t->bpp = bpp;
|
|
||||||
t->flags = flags;
|
|
||||||
|
|
||||||
return ret;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
@ -522,10 +514,10 @@ static Status jpg_encode_impl(Tex* t, jpeg_compress_struct* cinfo, DynArray* da)
|
|||||||
|
|
||||||
// describe image format
|
// describe image format
|
||||||
// required:
|
// required:
|
||||||
cinfo->image_width = (JDIMENSION)t->w;
|
cinfo->image_width = (JDIMENSION)t->m_Width;
|
||||||
cinfo->image_height = (JDIMENSION)t->h;
|
cinfo->image_height = (JDIMENSION)t->m_Height;
|
||||||
cinfo->input_components = (int)t->bpp / 8;
|
cinfo->input_components = (int)t->m_Bpp / 8;
|
||||||
cinfo->in_color_space = (t->bpp == 8)? JCS_GRAYSCALE : JCS_RGB;
|
cinfo->in_color_space = (t->m_Bpp == 8)? JCS_GRAYSCALE : JCS_RGB;
|
||||||
// defaults depend on cinfo->in_color_space already having been set!
|
// defaults depend on cinfo->in_color_space already having been set!
|
||||||
jpeg_set_defaults(cinfo);
|
jpeg_set_defaults(cinfo);
|
||||||
// (add optional settings, e.g. quality, here)
|
// (add optional settings, e.g. quality, here)
|
||||||
@ -535,16 +527,16 @@ static Status jpg_encode_impl(Tex* t, jpeg_compress_struct* cinfo, DynArray* da)
|
|||||||
jpeg_start_compress(cinfo, TRUE);
|
jpeg_start_compress(cinfo, TRUE);
|
||||||
|
|
||||||
// if BGR, convert to RGB.
|
// if BGR, convert to RGB.
|
||||||
WARN_IF_ERR(tex_transform_to(t, t->flags & ~TEX_BGR));
|
WARN_IF_ERR(t->transform_to(t->m_Flags & ~TEX_BGR));
|
||||||
|
|
||||||
const size_t pitch = t->w * t->bpp / 8;
|
const size_t pitch = t->m_Width * t->m_Bpp / 8;
|
||||||
u8* data = tex_get_data(t);
|
u8* data = t->get_data();
|
||||||
std::vector<RowPtr> rows = tex_codec_alloc_rows(data, t->h, pitch, t->flags, TEX_TOP_DOWN);
|
std::vector<RowPtr> rows = tex_codec_alloc_rows(data, t->m_Height, pitch, t->m_Flags, TEX_TOP_DOWN);
|
||||||
|
|
||||||
// could use cinfo->output_scanline to keep track of progress,
|
// could use cinfo->output_scanline to keep track of progress,
|
||||||
// but we need to count lines_left anyway (paranoia).
|
// but we need to count lines_left anyway (paranoia).
|
||||||
JSAMPARRAY row = (JSAMPARRAY)&rows[0];
|
JSAMPARRAY row = (JSAMPARRAY)&rows[0];
|
||||||
JDIMENSION lines_left = (JDIMENSION)t->h;
|
JDIMENSION lines_left = (JDIMENSION)t->m_Height;
|
||||||
while(lines_left != 0)
|
while(lines_left != 0)
|
||||||
{
|
{
|
||||||
JDIMENSION lines_read = jpeg_write_scanlines(cinfo, row, lines_left);
|
JDIMENSION lines_read = jpeg_write_scanlines(cinfo, row, lines_left);
|
||||||
|
@ -153,16 +153,8 @@ static Status png_decode_impl(MemoryStream* stream, png_structp png_ptr, png_inf
|
|||||||
// success; make sure all data was consumed.
|
// success; make sure all data was consumed.
|
||||||
ENSURE(stream->RemainingSize() == 0);
|
ENSURE(stream->RemainingSize() == 0);
|
||||||
|
|
||||||
// store image info
|
// store image info and validate
|
||||||
t->data = data;
|
return t->wrap(w,h,bpp,flags,data,0);
|
||||||
t->dataSize = img_size;
|
|
||||||
t->ofs = 0;
|
|
||||||
t->w = w;
|
|
||||||
t->h = h;
|
|
||||||
t->bpp = bpp;
|
|
||||||
t->flags = flags;
|
|
||||||
|
|
||||||
return INFO::OK;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
@ -170,11 +162,11 @@ static Status png_decode_impl(MemoryStream* stream, png_structp png_ptr, png_inf
|
|||||||
// "dtor / setjmp interaction" warning.
|
// "dtor / setjmp interaction" warning.
|
||||||
static Status png_encode_impl(Tex* t, png_structp png_ptr, png_infop info_ptr, DynArray* da)
|
static Status png_encode_impl(Tex* t, png_structp png_ptr, png_infop info_ptr, DynArray* da)
|
||||||
{
|
{
|
||||||
const png_uint_32 w = (png_uint_32)t->w, h = (png_uint_32)t->h;
|
const png_uint_32 w = (png_uint_32)t->m_Width, h = (png_uint_32)t->m_Height;
|
||||||
const size_t pitch = w * t->bpp / 8;
|
const size_t pitch = w * t->m_Bpp / 8;
|
||||||
|
|
||||||
int colour_type;
|
int colour_type;
|
||||||
switch(t->flags & (TEX_GREY|TEX_ALPHA))
|
switch(t->m_Flags & (TEX_GREY|TEX_ALPHA))
|
||||||
{
|
{
|
||||||
case TEX_GREY|TEX_ALPHA:
|
case TEX_GREY|TEX_ALPHA:
|
||||||
colour_type = PNG_COLOR_TYPE_GRAY_ALPHA;
|
colour_type = PNG_COLOR_TYPE_GRAY_ALPHA;
|
||||||
@ -194,11 +186,11 @@ static Status png_encode_impl(Tex* t, png_structp png_ptr, png_infop info_ptr, D
|
|||||||
png_set_IHDR(png_ptr, info_ptr, w, h, 8, colour_type,
|
png_set_IHDR(png_ptr, info_ptr, w, h, 8, colour_type,
|
||||||
PNG_INTERLACE_NONE, PNG_COMPRESSION_TYPE_DEFAULT, PNG_FILTER_TYPE_DEFAULT);
|
PNG_INTERLACE_NONE, PNG_COMPRESSION_TYPE_DEFAULT, PNG_FILTER_TYPE_DEFAULT);
|
||||||
|
|
||||||
u8* data = tex_get_data(t);
|
u8* data = t->get_data();
|
||||||
std::vector<RowPtr> rows = tex_codec_alloc_rows(data, h, pitch, t->flags, TEX_TOP_DOWN);
|
std::vector<RowPtr> rows = tex_codec_alloc_rows(data, h, pitch, t->m_Flags, TEX_TOP_DOWN);
|
||||||
|
|
||||||
// PNG is native RGB.
|
// PNG is native RGB.
|
||||||
const int png_transforms = (t->flags & TEX_BGR)? PNG_TRANSFORM_BGR : PNG_TRANSFORM_IDENTITY;
|
const int png_transforms = (t->m_Flags & TEX_BGR)? PNG_TRANSFORM_BGR : PNG_TRANSFORM_IDENTITY;
|
||||||
|
|
||||||
png_set_rows(png_ptr, info_ptr, (png_bytepp)&rows[0]);
|
png_set_rows(png_ptr, info_ptr, (png_bytepp)&rows[0]);
|
||||||
png_write_png(png_ptr, info_ptr, png_transforms, 0);
|
png_write_png(png_ptr, info_ptr, png_transforms, 0);
|
||||||
|
@ -136,10 +136,10 @@ static Status tga_decode(rpU8 data, size_t UNUSED(size), Tex* RESTRICT t)
|
|||||||
if(desc & TGA_RIGHT_TO_LEFT)
|
if(desc & TGA_RIGHT_TO_LEFT)
|
||||||
WARN_RETURN(ERR::TEX_INVALID_LAYOUT);
|
WARN_RETURN(ERR::TEX_INVALID_LAYOUT);
|
||||||
|
|
||||||
t->w = w;
|
t->m_Width = w;
|
||||||
t->h = h;
|
t->m_Height = h;
|
||||||
t->bpp = bpp;
|
t->m_Bpp = bpp;
|
||||||
t->flags = flags;
|
t->m_Flags = flags;
|
||||||
return INFO::OK;
|
return INFO::OK;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -147,13 +147,13 @@ static Status tga_decode(rpU8 data, size_t UNUSED(size), Tex* RESTRICT t)
|
|||||||
static Status tga_encode(Tex* RESTRICT t, DynArray* RESTRICT da)
|
static Status tga_encode(Tex* RESTRICT t, DynArray* RESTRICT da)
|
||||||
{
|
{
|
||||||
u8 img_desc = 0;
|
u8 img_desc = 0;
|
||||||
if(t->flags & TEX_TOP_DOWN)
|
if(t->m_Flags & TEX_TOP_DOWN)
|
||||||
img_desc |= TGA_TOP_DOWN;
|
img_desc |= TGA_TOP_DOWN;
|
||||||
if(t->bpp == 32)
|
if(t->m_Bpp == 32)
|
||||||
img_desc |= 8; // size of alpha channel
|
img_desc |= 8; // size of alpha channel
|
||||||
TgaImgType img_type = (t->flags & TEX_GREY)? TGA_GREY : TGA_TRUE_COLOUR;
|
TgaImgType img_type = (t->m_Flags & TEX_GREY)? TGA_GREY : TGA_TRUE_COLOUR;
|
||||||
|
|
||||||
size_t transforms = t->flags;
|
size_t transforms = t->m_Flags;
|
||||||
transforms &= ~TEX_ORIENTATION; // no flip needed - we can set top-down bit.
|
transforms &= ~TEX_ORIENTATION; // no flip needed - we can set top-down bit.
|
||||||
transforms ^= TEX_BGR; // TGA is native BGR.
|
transforms ^= TEX_BGR; // TGA is native BGR.
|
||||||
|
|
||||||
@ -164,9 +164,9 @@ static Status tga_encode(Tex* RESTRICT t, DynArray* RESTRICT da)
|
|||||||
(u8)img_type,
|
(u8)img_type,
|
||||||
{0,0,0,0,0}, // unused (colour map)
|
{0,0,0,0,0}, // unused (colour map)
|
||||||
0, 0, // unused (origin)
|
0, 0, // unused (origin)
|
||||||
(u16)t->w,
|
(u16)t->m_Width,
|
||||||
(u16)t->h,
|
(u16)t->m_Height,
|
||||||
(u8)t->bpp,
|
(u8)t->m_Bpp,
|
||||||
img_desc
|
img_desc
|
||||||
};
|
};
|
||||||
const size_t hdr_size = sizeof(hdr);
|
const size_t hdr_size = sizeof(hdr);
|
||||||
|
@ -173,7 +173,7 @@ const wchar_t* ErrorString(int err)
|
|||||||
Status tex_write(Tex* t, const VfsPath& filename)
|
Status tex_write(Tex* t, const VfsPath& filename)
|
||||||
{
|
{
|
||||||
DynArray da;
|
DynArray da;
|
||||||
RETURN_STATUS_IF_ERR(tex_encode(t, filename.Extension(), &da));
|
RETURN_STATUS_IF_ERR(t->encode(filename.Extension(), &da));
|
||||||
|
|
||||||
// write to disk
|
// write to disk
|
||||||
Status ret = INFO::OK;
|
Status ret = INFO::OK;
|
||||||
@ -230,7 +230,7 @@ void WriteScreenshot(const VfsPath& extension)
|
|||||||
AllocateAligned(buf, hdr_size+img_size, maxSectorSize);
|
AllocateAligned(buf, hdr_size+img_size, maxSectorSize);
|
||||||
GLvoid* img = buf.get() + hdr_size;
|
GLvoid* img = buf.get() + hdr_size;
|
||||||
Tex t;
|
Tex t;
|
||||||
if(tex_wrap(w, h, bpp, flags, buf, hdr_size, &t) < 0)
|
if(t.wrap(w, h, bpp, flags, buf, hdr_size) < 0)
|
||||||
return;
|
return;
|
||||||
glReadPixels(0, 0, (GLsizei)w, (GLsizei)h, fmt, GL_UNSIGNED_BYTE, img);
|
glReadPixels(0, 0, (GLsizei)w, (GLsizei)h, fmt, GL_UNSIGNED_BYTE, img);
|
||||||
|
|
||||||
@ -242,8 +242,6 @@ void WriteScreenshot(const VfsPath& extension)
|
|||||||
}
|
}
|
||||||
else
|
else
|
||||||
LOGERROR(L"Error writing screenshot to '%ls'", filename.string().c_str());
|
LOGERROR(L"Error writing screenshot to '%ls'", filename.string().c_str());
|
||||||
|
|
||||||
tex_free(&t);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
@ -294,7 +292,7 @@ void WriteBigScreenshot(const VfsPath& extension, int tiles)
|
|||||||
|
|
||||||
Tex t;
|
Tex t;
|
||||||
GLvoid* img = img_buf.get() + hdr_size;
|
GLvoid* img = img_buf.get() + hdr_size;
|
||||||
if(tex_wrap(img_w, img_h, bpp, flags, img_buf, hdr_size, &t) < 0)
|
if(t.wrap(img_w, img_h, bpp, flags, img_buf, hdr_size) < 0)
|
||||||
{
|
{
|
||||||
free(tile_data);
|
free(tile_data);
|
||||||
return;
|
return;
|
||||||
@ -378,6 +376,5 @@ void WriteBigScreenshot(const VfsPath& extension, int tiles)
|
|||||||
else
|
else
|
||||||
LOGERROR(L"Error writing screenshot to '%ls'", filename.string().c_str());
|
LOGERROR(L"Error writing screenshot to '%ls'", filename.string().c_str());
|
||||||
|
|
||||||
tex_free(&t);
|
|
||||||
free(tile_data);
|
free(tile_data);
|
||||||
}
|
}
|
||||||
|
@ -1929,7 +1929,7 @@ int CRenderer::LoadAlphaMaps()
|
|||||||
|
|
||||||
// upload the composite texture
|
// upload the composite texture
|
||||||
Tex t;
|
Tex t;
|
||||||
(void)tex_wrap(total_w, total_h, 8, TEX_GREY, data, 0, &t);
|
(void)t.wrap(total_w, total_h, 8, TEX_GREY, data, 0);
|
||||||
|
|
||||||
/*VfsPath filename("blendtex.png");
|
/*VfsPath filename("blendtex.png");
|
||||||
|
|
||||||
|
@ -88,7 +88,7 @@ void SkyManager::LoadSkyTextures()
|
|||||||
texture->Prefetch();
|
texture->Prefetch();
|
||||||
m_SkyTexture[i] = texture;
|
m_SkyTexture[i] = texture;
|
||||||
}*/
|
}*/
|
||||||
|
|
||||||
///////////////////////////////////////////////////////////////////////////
|
///////////////////////////////////////////////////////////////////////////
|
||||||
// HACK: THE HORRIBLENESS HERE IS OVER 9000. The following code is a HUGE hack and will be removed completely
|
// HACK: THE HORRIBLENESS HERE IS OVER 9000. The following code is a HUGE hack and will be removed completely
|
||||||
// as soon as all the hardcoded GL_TEXTURE_2D references are corrected in the TextureManager/OGL/tex libs.
|
// as soon as all the hardcoded GL_TEXTURE_2D references are corrected in the TextureManager/OGL/tex libs.
|
||||||
@ -132,37 +132,35 @@ void SkyManager::LoadSkyTextures()
|
|||||||
}
|
}
|
||||||
|
|
||||||
Tex tex;
|
Tex tex;
|
||||||
tex_decode(file, fileSize, &tex);
|
tex.decode(file, fileSize);
|
||||||
|
|
||||||
tex_transform_to(&tex, (tex.flags | TEX_BOTTOM_UP | TEX_ALPHA) & ~(TEX_DXT | TEX_MIPMAPS));
|
tex.transform_to((tex.m_Flags | TEX_BOTTOM_UP | TEX_ALPHA) & ~(TEX_DXT | TEX_MIPMAPS));
|
||||||
|
|
||||||
u8* data = tex_get_data(&tex);
|
u8* data = tex.get_data();
|
||||||
|
|
||||||
if (types[i] == GL_TEXTURE_CUBE_MAP_NEGATIVE_Y || types[i] == GL_TEXTURE_CUBE_MAP_POSITIVE_Y)
|
if (types[i] == GL_TEXTURE_CUBE_MAP_NEGATIVE_Y || types[i] == GL_TEXTURE_CUBE_MAP_POSITIVE_Y)
|
||||||
{
|
{
|
||||||
std::vector<u8> rotated(tex.dataSize);
|
std::vector<u8> rotated(tex.m_DataSize);
|
||||||
|
|
||||||
for (size_t y = 0; y < tex.h; ++y)
|
for (size_t y = 0; y < tex.m_Height; ++y)
|
||||||
{
|
{
|
||||||
for (size_t x = 0; x < tex.w; ++x)
|
for (size_t x = 0; x < tex.m_Width; ++x)
|
||||||
{
|
{
|
||||||
size_t invx = y, invy = tex.w-x-1;
|
size_t invx = y, invy = tex.m_Width-x-1;
|
||||||
|
|
||||||
rotated[(y*tex.w + x) * 4 + 0] = data[(invy*tex.w + invx) * 4 + 0];
|
rotated[(y*tex.m_Width + x) * 4 + 0] = data[(invy*tex.m_Width + invx) * 4 + 0];
|
||||||
rotated[(y*tex.w + x) * 4 + 1] = data[(invy*tex.w + invx) * 4 + 1];
|
rotated[(y*tex.m_Width + x) * 4 + 1] = data[(invy*tex.m_Width + invx) * 4 + 1];
|
||||||
rotated[(y*tex.w + x) * 4 + 2] = data[(invy*tex.w + invx) * 4 + 2];
|
rotated[(y*tex.m_Width + x) * 4 + 2] = data[(invy*tex.m_Width + invx) * 4 + 2];
|
||||||
rotated[(y*tex.w + x) * 4 + 3] = data[(invy*tex.w + invx) * 4 + 3];
|
rotated[(y*tex.m_Width + x) * 4 + 3] = data[(invy*tex.m_Width + invx) * 4 + 3];
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
glTexImage2D(types[i], 0, GL_RGB, tex.w, tex.h, 0, GL_RGBA, GL_UNSIGNED_BYTE, &rotated[0]);
|
glTexImage2D(types[i], 0, GL_RGB, tex.m_Width, tex.m_Height, 0, GL_RGBA, GL_UNSIGNED_BYTE, &rotated[0]);
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
glTexImage2D(types[i], 0, GL_RGB, tex.w, tex.h, 0, GL_RGBA, GL_UNSIGNED_BYTE, data);
|
glTexImage2D(types[i], 0, GL_RGB, tex.m_Width, tex.m_Height, 0, GL_RGBA, GL_UNSIGNED_BYTE, data);
|
||||||
}
|
}
|
||||||
|
|
||||||
tex_free(&tex);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
glTexParameteri(GL_TEXTURE_CUBE_MAP, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
|
glTexParameteri(GL_TEXTURE_CUBE_MAP, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
|
||||||
|
@ -336,7 +336,7 @@ public:
|
|||||||
shared_ptr<u8> buf;
|
shared_ptr<u8> buf;
|
||||||
AllocateAligned(buf, hdr_size+img_size, maxSectorSize);
|
AllocateAligned(buf, hdr_size+img_size, maxSectorSize);
|
||||||
Tex t;
|
Tex t;
|
||||||
if (tex_wrap(w, h, bpp, flags, buf, hdr_size, &t) < 0)
|
if (t.wrap(w, h, bpp, flags, buf, hdr_size) < 0)
|
||||||
return;
|
return;
|
||||||
|
|
||||||
u8* img = buf.get() + hdr_size;
|
u8* img = buf.get() + hdr_size;
|
||||||
@ -344,7 +344,6 @@ public:
|
|||||||
img[i] = (u8)((data[i] * 255) / max);
|
img[i] = (u8)((data[i] * 255) / max);
|
||||||
|
|
||||||
tex_write(&t, filename);
|
tex_write(&t, filename);
|
||||||
tex_free(&t);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
bool TryLoadSharedComponent(bool hasTechs)
|
bool TryLoadSharedComponent(bool hasTechs)
|
||||||
|
@ -172,22 +172,21 @@ MESSAGEHANDLER(ImportHeightmap)
|
|||||||
|
|
||||||
// decode to a raw pixel format
|
// decode to a raw pixel format
|
||||||
Tex tex;
|
Tex tex;
|
||||||
if (tex_decode(fileData, fileSize, &tex) < 0)
|
if (tex.decode(fileData, fileSize) < 0)
|
||||||
{
|
{
|
||||||
LOGERROR(L"Failed to decode heightmap.");
|
LOGERROR(L"Failed to decode heightmap.");
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
// Convert to uncompressed BGRA with no mipmaps
|
// Convert to uncompressed BGRA with no mipmaps
|
||||||
if (tex_transform_to(&tex, (tex.flags | TEX_BGR | TEX_ALPHA) & ~(TEX_DXT | TEX_MIPMAPS)) < 0)
|
if (tex.transform_to((tex.m_Flags | TEX_BGR | TEX_ALPHA) & ~(TEX_DXT | TEX_MIPMAPS)) < 0)
|
||||||
{
|
{
|
||||||
LOGERROR(L"Failed to transform heightmap.");
|
LOGERROR(L"Failed to transform heightmap.");
|
||||||
tex_free(&tex);
|
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
// pick smallest side of texture; truncate if not divisible by PATCH_SIZE
|
// pick smallest side of texture; truncate if not divisible by PATCH_SIZE
|
||||||
ssize_t terrainSize = std::min(tex.w, tex.h);
|
ssize_t terrainSize = std::min(tex.m_Width, tex.m_Height);
|
||||||
terrainSize -= terrainSize % PATCH_SIZE;
|
terrainSize -= terrainSize % PATCH_SIZE;
|
||||||
|
|
||||||
// resize terrain to heightmap size
|
// resize terrain to heightmap size
|
||||||
@ -198,9 +197,9 @@ MESSAGEHANDLER(ImportHeightmap)
|
|||||||
u16* heightmap = g_Game->GetWorld()->GetTerrain()->GetHeightMap();
|
u16* heightmap = g_Game->GetWorld()->GetTerrain()->GetHeightMap();
|
||||||
ssize_t hmSize = g_Game->GetWorld()->GetTerrain()->GetVerticesPerSide();
|
ssize_t hmSize = g_Game->GetWorld()->GetTerrain()->GetVerticesPerSide();
|
||||||
|
|
||||||
u8* mapdata = tex_get_data(&tex);
|
u8* mapdata = tex.get_data();
|
||||||
ssize_t bytesPP = tex.bpp / 8;
|
ssize_t bytesPP = tex.m_Bpp / 8;
|
||||||
ssize_t mapLineSkip = tex.w * bytesPP;
|
ssize_t mapLineSkip = tex.m_Width * bytesPP;
|
||||||
|
|
||||||
for (ssize_t y = 0; y < terrainSize; ++y)
|
for (ssize_t y = 0; y < terrainSize; ++y)
|
||||||
{
|
{
|
||||||
@ -215,8 +214,6 @@ MESSAGEHANDLER(ImportHeightmap)
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
tex_free(&tex);
|
|
||||||
|
|
||||||
// update simulation
|
// update simulation
|
||||||
CmpPtr<ICmpTerrain> cmpTerrain(*g_Game->GetSimulation2(), SYSTEM_ENTITY);
|
CmpPtr<ICmpTerrain> cmpTerrain(*g_Game->GetSimulation2(), SYSTEM_ENTITY);
|
||||||
if (cmpTerrain) cmpTerrain->ReloadTerrain();
|
if (cmpTerrain) cmpTerrain->ReloadTerrain();
|
||||||
|
Loading…
Reference in New Issue
Block a user