mirror of
https://github.com/hrydgard/ppsspp.git
synced 2024-11-27 07:20:49 +00:00
Merge pull request #17854 from hrydgard/color-emoji-android
Implement color emoji support for Android
This commit is contained in:
commit
83dbc60d86
@ -426,6 +426,17 @@ int u8_is_locale_utf8(const char *locale)
|
||||
return 0;
|
||||
}
|
||||
|
||||
bool AnyEmojiInString(const char *s, size_t byteCount) {
|
||||
int i = 0;
|
||||
while (i < byteCount) {
|
||||
uint32_t c = u8_nextchar(s, &i);
|
||||
if (CodepointIsProbablyEmoji(c)) {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
int UTF8StringNonASCIICount(const char *utf8string) {
|
||||
UTF8 utf(utf8string);
|
||||
int count = 0;
|
||||
@ -558,6 +569,12 @@ std::u16string ConvertUTF8ToUCS2(const std::string &source) {
|
||||
return dst;
|
||||
}
|
||||
|
||||
std::string CodepointToUTF8(uint32_t codePoint) {
|
||||
char temp[16]{};
|
||||
UTF8::encode(temp, codePoint);
|
||||
return std::string(temp);
|
||||
}
|
||||
|
||||
#ifndef _WIN32
|
||||
|
||||
// Replacements for the Win32 wstring functions. Not to be used from emulation code!
|
||||
|
@ -26,6 +26,14 @@ int u8_strlen(const char *s);
|
||||
void u8_inc(const char *s, int *i);
|
||||
void u8_dec(const char *s, int *i);
|
||||
|
||||
// ranges grabbed from https://stackoverflow.com/a/62898106, ignoring the two bogus ranges.
|
||||
// there's probably more. Doesn't need to be perfect.
|
||||
inline bool CodepointIsProbablyEmoji(uint32_t c) {
|
||||
return (c >= 127744 && c <= 129782) || (c >= 126980 && c <= 127569);
|
||||
}
|
||||
|
||||
bool AnyEmojiInString(const char *s, size_t byteCount);
|
||||
|
||||
class UTF8 {
|
||||
public:
|
||||
static const uint32_t INVALID = (uint32_t)-1;
|
||||
@ -89,6 +97,8 @@ bool UTF8StringHasNonASCII(const char *utf8string);
|
||||
// Removes overlong encodings and similar.
|
||||
std::string SanitizeUTF8(const std::string &utf8string);
|
||||
|
||||
std::string CodepointToUTF8(uint32_t codePoint);
|
||||
|
||||
|
||||
// UTF8 to Win32 UTF-16
|
||||
// Should be used when calling Win32 api calls
|
||||
|
@ -897,6 +897,7 @@ VKContext::VKContext(VulkanContext *vulkan, bool useRenderThread)
|
||||
caps_.logicOpSupported = vulkan->GetDeviceFeatures().enabled.standard.logicOp != 0;
|
||||
caps_.multiViewSupported = vulkan->GetDeviceFeatures().enabled.multiview.multiview != 0;
|
||||
caps_.sampleRateShadingSupported = vulkan->GetDeviceFeatures().enabled.standard.sampleRateShading != 0;
|
||||
caps_.textureSwizzleSupported = true;
|
||||
|
||||
const auto &limits = vulkan->GetPhysicalDeviceProperties().properties.limits;
|
||||
|
||||
|
@ -604,6 +604,7 @@ struct DeviceCaps {
|
||||
bool isTilingGPU; // This means that it benefits from correct store-ops, msaa without backing memory, etc.
|
||||
bool sampleRateShadingSupported;
|
||||
bool setMaxFrameLatencySupported;
|
||||
bool textureSwizzleSupported;
|
||||
|
||||
bool verySlowShaderCompiler;
|
||||
|
||||
|
@ -29,8 +29,10 @@ TextDrawerAndroid::TextDrawerAndroid(Draw::DrawContext *draw) : TextDrawer(draw)
|
||||
}
|
||||
dpiScale_ = CalculateDPIScale();
|
||||
|
||||
// Pick between the two supported formats, of which at least one is supported on each platform. Prefer R8 (but only if swizzle is supported)
|
||||
use4444Format_ = (draw->GetDataFormatSupport(Draw::DataFormat::R4G4B4A4_UNORM_PACK16) & Draw::FMT_TEXTURE) != 0;
|
||||
|
||||
if ((draw->GetDataFormatSupport(Draw::DataFormat::R8_UNORM) & Draw::FMT_TEXTURE) != 0 && draw->GetDeviceCaps().textureSwizzleSupported)
|
||||
use4444Format_ = false;
|
||||
INFO_LOG(G3D, "Initializing TextDrawerAndroid with DPI scale %f, use4444=%d", dpiScale_, (int)use4444Format_);
|
||||
}
|
||||
|
||||
@ -206,20 +208,30 @@ void TextDrawerAndroid::DrawStringBitmap(std::vector<uint8_t> &bitmapData, TextS
|
||||
if (texFormat == Draw::DataFormat::B4G4R4A4_UNORM_PACK16 || texFormat == Draw::DataFormat::R4G4B4A4_UNORM_PACK16) {
|
||||
bitmapData.resize(entry.bmWidth * entry.bmHeight * sizeof(uint16_t));
|
||||
uint16_t *bitmapData16 = (uint16_t *)&bitmapData[0];
|
||||
for (int x = 0; x < entry.bmWidth; x++) {
|
||||
for (int y = 0; y < entry.bmHeight; y++) {
|
||||
for (int y = 0; y < entry.bmHeight; y++) {
|
||||
for (int x = 0; x < entry.bmWidth; x++) {
|
||||
uint32_t v = jimage[imageWidth * y + x];
|
||||
v = 0xFFF0 | ((v >> 12) & 0xF); // Just grab some bits from the green channel.
|
||||
v = 0xFFF0 | ((v >> 28) & 0xF); // Grab the upper bits from the alpha channel, and put directly in the 16-bit alpha channel.
|
||||
bitmapData16[entry.bmWidth * y + x] = (uint16_t)v;
|
||||
}
|
||||
}
|
||||
} else if (texFormat == Draw::DataFormat::R8_UNORM) {
|
||||
bitmapData.resize(entry.bmWidth * entry.bmHeight);
|
||||
for (int x = 0; x < entry.bmWidth; x++) {
|
||||
for (int y = 0; y < entry.bmHeight; y++) {
|
||||
for (int y = 0; y < entry.bmHeight; y++) {
|
||||
for (int x = 0; x < entry.bmWidth; x++) {
|
||||
uint32_t v = jimage[imageWidth * y + x];
|
||||
v = (v >> 12) & 0xF; // Just grab some bits from the green channel.
|
||||
bitmapData[entry.bmWidth * y + x] = (uint8_t)(v | (v << 4));
|
||||
bitmapData[entry.bmWidth * y + x] = (uint8_t)(v >> 24);
|
||||
}
|
||||
}
|
||||
} else if (texFormat == Draw::DataFormat::R8G8B8A8_UNORM) {
|
||||
bitmapData.resize(entry.bmWidth * entry.bmHeight * sizeof(uint32_t));
|
||||
uint32_t *bitmapData32 = (uint32_t *)&bitmapData[0];
|
||||
for (int y = 0; y < entry.bmHeight; y++) {
|
||||
for (int x = 0; x < entry.bmWidth; x++) {
|
||||
uint32_t v = jimage[imageWidth * y + x];
|
||||
// Swap R and B, for some reason.
|
||||
v = (v & 0xFF00FF00) | ((v >> 16) & 0xFF) | ((v << 16) & 0xFF0000);
|
||||
bitmapData32[entry.bmWidth * y + x] = v;
|
||||
}
|
||||
}
|
||||
} else {
|
||||
@ -238,6 +250,8 @@ void TextDrawerAndroid::DrawString(DrawBuffer &target, const char *str, float x,
|
||||
if (text.empty())
|
||||
return;
|
||||
|
||||
bool emoji = AnyEmojiInString(text.c_str(), text.size());
|
||||
|
||||
CacheKey key{ std::string(str), fontHash_ };
|
||||
target.Flush(true);
|
||||
|
||||
@ -248,8 +262,10 @@ void TextDrawerAndroid::DrawString(DrawBuffer &target, const char *str, float x,
|
||||
entry = iter->second.get();
|
||||
entry->lastUsedFrame = frameCount_;
|
||||
} else {
|
||||
// Actually, I don't know why we don't always use R8_UNORM..
|
||||
DataFormat texFormat = use4444Format_ ? Draw::DataFormat::R4G4B4A4_UNORM_PACK16 : Draw::DataFormat::R8_UNORM;
|
||||
if (emoji) {
|
||||
texFormat = Draw::DataFormat::R8G8B8A8_UNORM;
|
||||
}
|
||||
|
||||
entry = new TextStringEntry();
|
||||
|
||||
@ -265,7 +281,7 @@ void TextDrawerAndroid::DrawString(DrawBuffer &target, const char *str, float x,
|
||||
desc.depth = 1;
|
||||
desc.mipLevels = 1;
|
||||
desc.generateMips = false;
|
||||
desc.swizzle = use4444Format_ ? Draw::TextureSwizzle::DEFAULT : Draw::TextureSwizzle::R8_AS_ALPHA,
|
||||
desc.swizzle = texFormat == Draw::DataFormat::R8_UNORM ? Draw::TextureSwizzle::R8_AS_ALPHA : Draw::TextureSwizzle::DEFAULT,
|
||||
desc.tag = "TextDrawer";
|
||||
entry->texture = draw_->CreateTexture(desc);
|
||||
cache_[key] = std::unique_ptr<TextStringEntry>(entry);
|
||||
|
@ -137,7 +137,6 @@ TextDrawerUWP::TextDrawerUWP(Draw::DrawContext *draw) : TextDrawer(draw), ctx_(n
|
||||
);
|
||||
|
||||
m_d2dContext->CreateSolidColorBrush(D2D1::ColorF(D2D1::ColorF::White, 1.0f), &m_d2dWhiteBrush);
|
||||
|
||||
}
|
||||
|
||||
TextDrawerUWP::~TextDrawerUWP() {
|
||||
|
@ -39,6 +39,7 @@
|
||||
#endif
|
||||
#include "Common/File/AndroidStorage.h"
|
||||
#include "Common/Data/Text/I18n.h"
|
||||
#include "Common/Data/Encoding/Utf8.h"
|
||||
#include "Common/Net/HTTPClient.h"
|
||||
#include "Common/UI/Context.h"
|
||||
#include "Common/UI/View.h"
|
||||
@ -834,7 +835,8 @@ void SystemInfoScreen::CreateTabs() {
|
||||
|
||||
internals->Add(new ItemHeader(si->T("Notification tests")));
|
||||
internals->Add(new Choice(si->T("Error")))->OnClick.Add([&](UI::EventParams &) {
|
||||
g_OSD.Show(OSDType::MESSAGE_ERROR, "Error");
|
||||
std::string str = "Error " + CodepointToUTF8(0x1F41B) + CodepointToUTF8(0x1F41C) + CodepointToUTF8(0x1F914);
|
||||
g_OSD.Show(OSDType::MESSAGE_ERROR, str);
|
||||
return UI::EVENT_DONE;
|
||||
});
|
||||
internals->Add(new Choice(si->T("Warning")))->OnClick.Add([&](UI::EventParams &) {
|
||||
|
@ -34,6 +34,7 @@
|
||||
#include "Common/File/VFS/VFS.h"
|
||||
|
||||
#include "Common/Data/Color/RGBAUtil.h"
|
||||
#include "Common/Data/Encoding/Utf8.h"
|
||||
#include "Common/Data/Text/I18n.h"
|
||||
#include "Common/Data/Random/Rng.h"
|
||||
#include "Common/TimeUtil.h"
|
||||
@ -798,7 +799,9 @@ void LogoScreen::render() {
|
||||
// Draw the graphics API, except on UWP where it's always D3D11
|
||||
std::string apiName = screenManager()->getDrawContext()->GetInfoString(InfoField::APINAME);
|
||||
#ifdef _DEBUG
|
||||
apiName += ", debug build";
|
||||
apiName += ", debug build ";
|
||||
// Add some emoji for testing.
|
||||
apiName += CodepointToUTF8(0x1F41B) + CodepointToUTF8(0x1F41C) + CodepointToUTF8(0x1F914);
|
||||
#endif
|
||||
dc.DrawText(gr->T(apiName), bounds.centerX(), ppsspp_org_y + 50, textColor, ALIGN_CENTER);
|
||||
#endif
|
||||
|
@ -14,7 +14,7 @@ public class TextRenderer {
|
||||
p = new Paint(Paint.SUBPIXEL_TEXT_FLAG | Paint.ANTI_ALIAS_FLAG);
|
||||
p.setColor(Color.WHITE);
|
||||
bg = new Paint();
|
||||
bg.setColor(Color.BLACK);
|
||||
bg.setColor(0);
|
||||
}
|
||||
|
||||
public static void init(Context ctx) {
|
||||
|
Loading…
Reference in New Issue
Block a user