Skip to content

Remove the default pixel format, fix rendering of grayscale PNGs #2573

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Open
wants to merge 4 commits into
base: wip-v3
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion core/2d/AnchoredSprite.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -71,7 +71,7 @@ AnchoredSprite* AnchoredSprite::createWithTexture(Texture2D* texture, const Rect

AnchoredSprite* AnchoredSprite::create(std::string_view filename)
{
return AnchoredSprite::create(filename, Texture2D::getDefaultAlphaPixelFormat());
return AnchoredSprite::create(filename, PixelFormat::NONE);
}

AnchoredSprite* AnchoredSprite::create(std::string_view filename, PixelFormat format)
Expand Down
24 changes: 21 additions & 3 deletions core/2d/Sprite.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -75,7 +75,7 @@ Sprite* Sprite::createWithTexture(Texture2D* texture, const Rect& rect, bool rot

Sprite* Sprite::create(std::string_view filename)
{
return Sprite::create(filename, Texture2D::getDefaultAlphaPixelFormat());
return Sprite::create(filename, PixelFormat::NONE);
}

Sprite* Sprite::create(std::string_view filename, PixelFormat format)
Expand Down Expand Up @@ -187,7 +187,7 @@ bool Sprite::initWithTexture(Texture2D* texture, const Rect& rect)

bool Sprite::initWithFile(std::string_view filename)
{
return initWithFile(filename, Texture2D::getDefaultAlphaPixelFormat());
return initWithFile(filename, PixelFormat::NONE);
}

bool Sprite::initWithFile(std::string_view filename, PixelFormat format)
Expand Down Expand Up @@ -434,7 +434,25 @@ void Sprite::setTexture(Texture2D* texture)
}

if (needsUpdatePS)
setProgramState(backend::ProgramType::POSITION_TEXTURE_COLOR);
{
const PixelFormat pixelFormat = _texture->getPixelFormat();

switch(pixelFormat)
{
case PixelFormat::R8:
setProgramState(backend::ProgramType::POSITION_TEXTURE_GRAY);
break;
case PixelFormat::RG8:
setProgramState(backend::ProgramType::POSITION_TEXTURE_GRAY_ALPHA);
break;
case PixelFormat::RGBA8:
setProgramState(backend::ProgramType::POSITION_TEXTURE_COLOR);
break;
default:
AXLOGW("Warning: Sprite::setTexture() unhandled pixel format {}", (int)pixelFormat);
setProgramState(backend::ProgramType::POSITION_TEXTURE_COLOR);
}
}
else
updateProgramStateTexture(_texture);
}
Expand Down
11 changes: 1 addition & 10 deletions core/base/Director.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -229,15 +229,6 @@ void Director::setDefaultValues()
else
AXASSERT(false, "Invalid projection value");

// Default pixel format for PNG images with alpha
std::string pixel_format = conf->getValue("axmol.texture.pixel_format_for_png", Value("rgba8888")).asString();
if (pixel_format == "rgba8888")
Texture2D::setDefaultAlphaPixelFormat(backend::PixelFormat::RGBA8);
else if (pixel_format == "rgba4444")
Texture2D::setDefaultAlphaPixelFormat(backend::PixelFormat::RGBA4);
else if (pixel_format == "rgba5551")
Texture2D::setDefaultAlphaPixelFormat(backend::PixelFormat::RGB5A1);

/* !!!Notes
** All compressed image should do PMA at texture convert tools(such as astcenc-2.2+ with -pp-premultiply)
** or GPU fragment shader
Expand Down Expand Up @@ -1324,7 +1315,7 @@ void Director::createStatsLabel()
return;
}

texture = _textureCache->addImage(image, "/ax_fps_images", PixelFormat::RGBA4);
texture = _textureCache->addImage(image, "/ax_fps_images");
AX_SAFE_RELEASE(image);

/*
Expand Down
5 changes: 3 additions & 2 deletions core/platform/Image.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -1314,7 +1314,8 @@ bool Image::initWithPngData(uint8_t* data, ssize_t dataLen)
png_read_end(png_ptr, nullptr);

// premultiplied alpha for RGBA8888
if ((color_type == PNG_COLOR_TYPE_RGB_ALPHA) || (color_type == PNG_COLOR_TYPE_GRAY_ALPHA))
if ((color_type == PNG_COLOR_TYPE_RGB_ALPHA)
|| (color_type == PNG_COLOR_TYPE_GRAY_ALPHA))
{
if (PNG_PREMULTIPLIED_ALPHA_ENABLED)
{
Expand Down Expand Up @@ -2635,7 +2636,7 @@ void Image::premultiplyAlpha()
for (int i = 0; i < _width * _height; i++)
{
uint8_t* p = _data + i * 2;
twoBytes[i] = ((p[0] * p[1] + 1) >> 8) | (p[1] << 8);
twoBytes[i] = ((p[0] * (p[1] + 1)) >> 8) | (p[1] << 8);
}
}

Expand Down
2 changes: 2 additions & 0 deletions core/renderer/Shaders.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -39,6 +39,8 @@ AX_DLL const std::string_view positionTexture_frag = "positionTe
AX_DLL const std::string_view positionTextureColor_vert = "positionTextureColor_vs"sv;
AX_DLL const std::string_view positionTextureColor_frag = "positionTextureColor_fs"sv;
AX_DLL const std::string_view positionTextureColorAlphaTest_frag = "positionTextureColorAlphaTest_fs"sv;
AX_DLL const std::string_view positionTextureGray_frag = "positionTextureGray_fs"sv;
AX_DLL const std::string_view positionTextureGrayAlpha_frag = "positionTextureGrayAlpha_fs"sv;
AX_DLL const std::string_view label_normal_frag = "label_normal_fs"sv;
AX_DLL const std::string_view label_outline_frag = "label_outline_fs"sv;
AX_DLL const std::string_view label_distanceNormal_frag = "label_distanceNormal_fs"sv;
Expand Down
2 changes: 2 additions & 0 deletions core/renderer/Shaders.h
Original file line number Diff line number Diff line change
Expand Up @@ -47,6 +47,8 @@ extern AX_DLL const std::string_view positionTexture_frag;
extern AX_DLL const std::string_view positionTextureColor_vert;
extern AX_DLL const std::string_view positionTextureColor_frag;
extern AX_DLL const std::string_view positionTextureColorAlphaTest_frag;
extern AX_DLL const std::string_view positionTextureGray_frag;
extern AX_DLL const std::string_view positionTextureGrayAlpha_frag;
extern AX_DLL const std::string_view label_normal_frag;
extern AX_DLL const std::string_view label_outline_frag;
extern AX_DLL const std::string_view label_distanceNormal_frag;
Expand Down
64 changes: 17 additions & 47 deletions core/renderer/Texture2D.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -56,12 +56,6 @@ THE SOFTWARE.
namespace ax
{

// CLASS IMPLEMENTATIONS:

// If the image has alpha, you can create RGBA8 (32-bit) or RGBA4 (16-bit) or RGB5A1 (16-bit)
// Default is: RGBA8888 (32-bit textures)
static backend::PixelFormat g_defaultAlphaPixelFormat = backend::PixelFormat::RGBA8;

Texture2D::Texture2D()
: _pixelFormat(backend::PixelFormat::NONE)
, _pixelsWide(0)
Expand Down Expand Up @@ -188,6 +182,11 @@ bool Texture2D::initWithMipmaps(MipmapInfo* mipmaps,
return true;
}

bool Texture2D::updateWithImage(Image* image, int index)
{
return updateWithImage(image, image->getPixelFormat(), index);
}

bool Texture2D::updateWithImage(Image* image, backend::PixelFormat format, int index)
{
if (image == nullptr)
Expand Down Expand Up @@ -237,34 +236,24 @@ bool Texture2D::updateWithImage(Image* image, backend::PixelFormat format, int i
default:
break;
}
#elif !AX_GLES_PROFILE
// Non-GLES doesn't support follow render formats, needs convert PixelFormat::RGBA8
// Note: axmol-1.1 deprecated A8, L8, LA8 as renderFormat, preferred R8, RG8
switch (renderFormat)
{
case PixelFormat::R8:
case PixelFormat::RG8:
// Note: conversion to RGBA8 will happends
renderFormat = PixelFormat::RGBA8;
}
#endif

if (image->getNumberOfMipmaps() > 1)
{
if (renderFormat != image->getPixelFormat())
if (renderFormat != imagePixelFormat)
{
AXLOGW("WARNING: This image has more than 1 mipmaps and we will not convert the data format");
}

// pixel format of data is not converted, renderFormat can be different from pixelFormat
// it will be done later
updateWithMipmaps(image->getMipmaps(), image->getNumberOfMipmaps(), image->getPixelFormat(), renderFormat, imageHeight, imageWidth, image->hasPremultipliedAlpha(), index);
updateWithMipmaps(image->getMipmaps(), image->getNumberOfMipmaps(), imagePixelFormat, renderFormat, imageHeight, imageWidth, image->hasPremultipliedAlpha(), index);
}
else if (image->isCompressed())
{ // !Only hardware support texture will be compression PixelFormat, otherwise, will convert to RGBA8 duraing image
// load
renderFormat = imagePixelFormat;
updateWithData(tempData, tempDataLen, image->getPixelFormat(), image->getPixelFormat(), imageWidth, imageHeight, image->hasPremultipliedAlpha(), index);
updateWithData(tempData, tempDataLen, imagePixelFormat, image->getPixelFormat(), imageWidth, imageHeight, image->hasPremultipliedAlpha(), index);
}
else
{
Expand Down Expand Up @@ -448,7 +437,13 @@ bool Texture2D::updateWithSubData(void* data, int offsetX, int offsetY, int widt
// implementation Texture2D (Image)
bool Texture2D::initWithImage(Image* image)
{
return initWithImage(image, g_defaultAlphaPixelFormat);
if (image == nullptr)
{
AXLOGW("Texture2D. Can't create Texture. UIImage is nil");
return false;
}

return initWithImage(image, image->getPixelFormat());
}

bool Texture2D::initWithImage(Image* image, backend::PixelFormat format)
Expand Down Expand Up @@ -532,10 +527,6 @@ bool Texture2D::initWithString(std::string_view text, const FontDefinition& text
AXASSERT(textDefinition._stroke._strokeEnabled == false, "Currently stroke only supported on iOS and Android!");
#endif

PixelFormat pixelFormat = g_defaultAlphaPixelFormat;
unsigned char* outTempData = nullptr;
size_t outTempDataLen = 0;

int imageWidth;
int imageHeight;
auto textDef = textDefinition;
Expand All @@ -560,16 +551,10 @@ bool Texture2D::initWithString(std::string_view text, const FontDefinition& text
}

Vec2 imageSize = Vec2((float)imageWidth, (float)imageHeight);
pixelFormat =
backend::PixelFormatUtils::convertDataToFormat(outData.getBytes(), imageWidth * imageHeight * 4,
PixelFormat::RGBA8, pixelFormat, &outTempData, &outTempDataLen);
const PixelFormat pixelFormat = PixelFormat::RGBA8;

ret = initWithData(outTempData, outTempDataLen, pixelFormat, imageWidth, imageHeight);
ret = initWithData(outData.getBytes(), imageWidth * imageHeight * 4, pixelFormat, imageWidth, imageHeight);

if (outTempData != nullptr && outTempData != outData.getBytes())
{
free(outTempData);
}
setPremultipliedAlpha(hasPremultipliedAlpha);

return ret;
Expand Down Expand Up @@ -647,21 +632,6 @@ const char* Texture2D::getStringForFormat() const
return backend::PixelFormatUtils::getFormatDescriptor(_pixelFormat).name;
}

//
// Texture options for images that contains alpha
//
// implementation Texture2D (PixelFormat)

void Texture2D::setDefaultAlphaPixelFormat(backend::PixelFormat format)
{
g_defaultAlphaPixelFormat = format;
}

backend::PixelFormat Texture2D::getDefaultAlphaPixelFormat()
{
return g_defaultAlphaPixelFormat;
}

unsigned int Texture2D::getBitsPerPixelForFormat(backend::PixelFormat format) const
{
return backend::PixelFormatUtils::getFormatDescriptor(format).bpp;
Expand Down
45 changes: 7 additions & 38 deletions core/renderer/Texture2D.h
Original file line number Diff line number Diff line change
Expand Up @@ -91,36 +91,6 @@ class AX_DLL Texture2D : public Object
*/
using TexParams = backend::SamplerDescriptor;

public:
/** sets the default pixel format for UIImagescontains alpha channel.

@param format
If the UIImage contains alpha channel, then the options are:
- generate 32-bit textures: backend::PixelFormat::RGBA8 (default one)
- generate 24-bit textures: backend::PixelFormat::RGB8
- generate 16-bit textures: backend::PixelFormat::RGBA4
- generate 16-bit textures: backend::PixelFormat::RGB5A1
- generate 16-bit textures: backend::PixelFormat::RGB565
- generate 8-bit textures: backend::PixelFormat::R8 (only use it if you use just 1 color)
- generate 16-bit textures: backend::PixelFormat::RG8 (only use it if you use just 2 color)

How does it work ?
- If the image is an RGBA (with Alpha) then the default pixel format will be used (it can be a 8-bit, 16-bit or
32-bit texture)
- If the image is an RGB (without Alpha) then: If the default pixel format is RGBA8888 then a RGBA8888 (32-bit)
will be used. Otherwise a RGB565 (16-bit texture) will be used.

This parameter is not valid for PVR / PVR.CCZ images.

@since v0.8
*/
static void setDefaultAlphaPixelFormat(backend::PixelFormat format);

/** Returns the alpha pixel format.
@since v0.8
*/
static backend::PixelFormat getDefaultAlphaPixelFormat();

public:
/**
*/
Expand Down Expand Up @@ -197,6 +167,7 @@ class AX_DLL Texture2D : public Object
@param width Specifies the width of the texture subimage.
@param height Specifies the height of the texture subimage.
*/
bool updateWithImage(Image* image, int index = 0);
bool updateWithImage(Image* image, backend::PixelFormat format, int index = 0);
bool updateWithData(const void* data,
ssize_t dataLen,
Expand Down Expand Up @@ -240,21 +211,19 @@ class AX_DLL Texture2D : public Object
/**
Initializes a texture from a UIImage object.

We will use the format you specified with setDefaultAlphaPixelFormat to convert the image for texture.
We will use the pixel format of the image.
NOTE: It will not convert the pvr image file.
@param image An UIImage object.
*/
bool initWithImage(Image* image);

/**
Initializes a texture from a UIImage object.
Initializes a texture from an Image object and convert it to the given
format if necessary.

We will use the format you passed to the function to convert the image format to the texture format.
If you pass PixelFormat::NONE, we will auto detect the image render type and use that type for texture to render.
@param image An UIImage object.
@param format Texture pixel formats.
**/
bool initWithImage(Image* image, backend::PixelFormat format);
NOTE: It will not convert the pvr image file.
*/
bool initWithImage(Image* image, PixelFormat format);

/** Initializes a texture from a string with dimensions, alignment, font name and font size.

Expand Down
6 changes: 3 additions & 3 deletions core/renderer/TextureCache.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -87,7 +87,7 @@ struct TextureCache::AsyncStruct
: filename(fn)
, callback(f)
, callbackKey(key)
, pixelFormat(Texture2D::getDefaultAlphaPixelFormat())
, pixelFormat(PixelFormat::NONE)
, loadSuccess(false)
{}

Expand Down Expand Up @@ -433,7 +433,7 @@ Texture2D* TextureCache::getDummyTexture()

Texture2D* TextureCache::addImage(std::string_view path)
{
return addImage(path, Texture2D::getDefaultAlphaPixelFormat());
return addImage(path, PixelFormat::NONE);
}

Texture2D* TextureCache::addImage(std::string_view path, PixelFormat format)
Expand Down Expand Up @@ -516,7 +516,7 @@ void TextureCache::parseNinePatchImage(ax::Image* image, ax::Texture2D* texture,

Texture2D* TextureCache::addImage(Image* image, std::string_view key)
{
return addImage(image, key, Texture2D::getDefaultAlphaPixelFormat());
return addImage(image, key, PixelFormat::NONE);
}

Texture2D* TextureCache::addImage(Image* image, std::string_view key, PixelFormat format)
Expand Down
2 changes: 0 additions & 2 deletions core/renderer/TextureCache.h
Original file line number Diff line number Diff line change
Expand Up @@ -112,8 +112,6 @@ class AX_DLL TextureCache : public Object
@param filepath The file path.
@param callback A callback function would be invoked after the image is loaded.
@since v0.8

@remark Please don't invoke Texture2D::setDefaultAlphaPixelFormat in main GL thread before invoke this API.
*/
virtual void addImageAsync(std::string_view filepath, const std::function<void(Texture2D*)>& callback);

Expand Down
2 changes: 2 additions & 0 deletions core/renderer/backend/Enums.h
Original file line number Diff line number Diff line change
Expand Up @@ -343,6 +343,8 @@ struct ProgramType
POSITION_TEXTURE, // positionTexture_vert, positionTexture_frag
POSITION_TEXTURE_COLOR, // positionTextureColor_vert, positionTextureColor_frag
POSITION_TEXTURE_COLOR_ALPHA_TEST, // positionTextureColor_vert, positionTextureColorAlphaTest_frag
POSITION_TEXTURE_GRAY_ALPHA, // positionTextureColor_vert, positionTextureGrayAlpha_frag
POSITION_TEXTURE_GRAY, // positionTextureColor_vert, positionTextureGray_frag
LABEL_NORMAL, // positionTextureColor_vert, label_normal_frag
LABLE_OUTLINE, // positionTextureColor_vert, labelOutline_frag
LABEL_DISTANCE_NORMAL, // positionTextureColor_vert, label_distanceNormal_frag
Expand Down
4 changes: 4 additions & 0 deletions core/renderer/backend/ProgramManager.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -115,6 +115,10 @@ bool ProgramManager::init()
VertexLayoutType::Texture);
registerProgram(ProgramType::POSITION_TEXTURE_COLOR_ALPHA_TEST, positionTextureColor_vert,
positionTextureColorAlphaTest_frag, VertexLayoutType::Sprite);
registerProgram(ProgramType::POSITION_TEXTURE_GRAY_ALPHA, positionTextureColor_vert,
positionTextureGrayAlpha_frag, VertexLayoutType::Sprite);
registerProgram(ProgramType::POSITION_TEXTURE_GRAY, positionTextureColor_vert,
positionTextureGray_frag, VertexLayoutType::Sprite);
registerProgram(ProgramType::POSITION_UCOLOR, positionUColor_vert, positionColor_frag, VertexLayoutType::Pos);
registerProgram(ProgramType::DUAL_SAMPLER_GRAY, positionTextureColor_vert, dualSampler_gray_frag,
VertexLayoutType::Sprite);
Expand Down
16 changes: 16 additions & 0 deletions core/renderer/shaders/positionTextureGray.frag
Original file line number Diff line number Diff line change
@@ -0,0 +1,16 @@
#version 310 es
precision highp float;
precision highp int;

layout(location = COLOR0) in vec4 v_color;
layout(location = TEXCOORD0) in vec2 v_texCoord;

layout(binding = 0) uniform sampler2D u_tex0;

layout(location = SV_Target0) out vec4 FragColor;

void main()
{
vec4 c = texture(u_tex0, v_texCoord);
FragColor = v_color * vec4(c.r, c.r, c.r, 1);
}
Loading