Skip to content

Commit

Permalink
It works!
Browse files Browse the repository at this point in the history
  • Loading branch information
hrydgard committed Jun 5, 2017
1 parent 0bf92a4 commit 0d3d642
Show file tree
Hide file tree
Showing 9 changed files with 83 additions and 70 deletions.
2 changes: 1 addition & 1 deletion UI/GameSettingsScreen.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -676,7 +676,7 @@ void GameSettingsScreen::CreateViews() {

systemSettings->Add(new ItemHeader(sy->T("General")));

#ifdef __ANDROID__
#if PPSSPP_PLATFORM(ANDROID)
if (System_GetPropertyInt(SYSPROP_DEVICE_TYPE) == DEVICE_TYPE_MOBILE) {
static const char *screenRotation[] = {"Auto", "Landscape", "Portrait", "Landscape Reversed", "Portrait Reversed"};
PopupMultiChoice *rot = systemSettings->Add(new PopupMultiChoice(&g_Config.iScreenRotation, co->T("Screen Rotation"), screenRotation, 0, ARRAY_SIZE(screenRotation), co->GetName(), screenManager()));
Expand Down
6 changes: 3 additions & 3 deletions UI/MiscScreens.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -345,16 +345,16 @@ NewLanguageScreen::NewLanguageScreen(const std::string &title) : ListPopupScreen
continue;
}

#ifndef _WIN32
// ar_AE only works on Windows.
#if !(defined(USING_QT_UI) || PPSSPP_PLATFORM(WINDOWS) || PPSSPP_PLATFORM(ANDROID))
if (tempLangs[i].name.find("ar_AE") != std::string::npos) {
continue;
}
// Farsi also only works on Windows.

if (tempLangs[i].name.find("fa_IR") != std::string::npos) {
continue;
}
#endif

FileInfo lang = tempLangs[i];
langs_.push_back(lang);

Expand Down
4 changes: 2 additions & 2 deletions android/jni/app-android.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -659,7 +659,7 @@ extern "C" void Java_org_ppsspp_ppsspp_NativeApp_shutdown(JNIEnv *, jclass) {
// JavaEGL
extern "C" void Java_org_ppsspp_ppsspp_NativeRenderer_displayInit(JNIEnv * env, jobject obj) {
// Need to get the local JNI env for the graphics thread. Used later in draw_text_android.
int res = javaVM->GetEnv((void **)&jniEnvGraphics, JNI_VERSION_1_4);
int res = javaVM->GetEnv((void **)&jniEnvGraphics, JNI_VERSION_1_6);
if (res != JNI_OK) {
ELOG("GetEnv failed: %d", res);
}
Expand Down Expand Up @@ -1031,7 +1031,7 @@ extern "C" bool JNICALL Java_org_ppsspp_ppsspp_NativeActivity_runEGLRenderLoop(J
ANativeWindow *wnd = ANativeWindow_fromSurface(env, _surf);

// Need to get the local JNI env for the graphics thread. Used later in draw_text_android.
int res = javaVM->GetEnv((void **)&jniEnvGraphics, JNI_VERSION_1_4);
int res = javaVM->GetEnv((void **)&jniEnvGraphics, JNI_VERSION_1_6);
if (res != JNI_OK) {
ELOG("GetEnv failed: %d", res);
}
Expand Down
3 changes: 2 additions & 1 deletion android/jni/app-android.h
Original file line number Diff line number Diff line change
Expand Up @@ -8,5 +8,6 @@

extern JNIEnv *jniEnvMain;
extern JNIEnv *jniEnvGraphics;
extern JavaVM *javaVM;

#endif
#endif
61 changes: 32 additions & 29 deletions android/src/org/ppsspp/ppsspp/TextRenderer.java
Original file line number Diff line number Diff line change
Expand Up @@ -4,43 +4,46 @@
import java.nio.ByteBuffer;

public class TextRenderer {
public static int measureText(String string, float textSize) {
Paint p;
p = new Paint(Paint.ANTI_ALIAS_FLAG);
private static Paint p;
private static Paint bg;
static {
p = new Paint(Paint.SUBPIXEL_TEXT_FLAG | Paint.ANTI_ALIAS_FLAG);
p.setColor(Color.WHITE);
bg = new Paint();
bg.setColor(Color.BLACK);
}
public static int measureText(String string, double textSize) {
Rect bound = new Rect();
p.setTextSize(textSize);
p.setTextSize((float)textSize);
p.getTextBounds(string, 0, string.length(), bound);
return (bound.width() << 16) | bound.height();
int w = bound.width();
int h = bound.height();
// Round width up to even already here to avoid annoyances from odd-width 16-bit textures which
// OpenGL does not like - each line must be 4-byte aligned
w = (w + 3) & ~1;
h += 2;
return (w << 16) | h;
}
public static short[] renderText(String string, float textSize) {
Paint p;
p = new Paint(Paint.ANTI_ALIAS_FLAG);
public static int[] renderText(String string, double textSize) {
Rect bound = new Rect();
p.setTextSize(textSize);
p.setTextSize((float)textSize);
p.getTextBounds(string, 0, string.length(), bound);
int w = bound.width();
int h = bound.height();
// Round width up to even already here to avoid annoyances from odd-width 16-bit textures which
// OpenGL does not like - each line must be 4-byte aligned
w = (w + 3) & ~1;
h += 2;

float baseline = -p.ascent();
Bitmap bmp = Bitmap.createBitmap(bound.width(), bound.height(), Bitmap.Config.ARGB_4444);
Bitmap bmp = Bitmap.createBitmap(w, h, Bitmap.Config.ARGB_8888);
Canvas canvas = new Canvas(bmp);
canvas.drawRect(0.0f, 0.0f, w, h, bg);
p.setColor(Color.WHITE);
canvas.drawText(string, 0, baseline, p);

int bufSize = bmp.getRowBytes() * bmp.getHeight() * 2; // 2 = sizeof(ARGB_4444)
ByteBuffer buf = ByteBuffer.allocate(bufSize);
bmp.copyPixelsFromBuffer(buf);
byte[] bytes = buf.array();

// Output array size must match return value of measureText
short[] output = new short[bound.width() * bound.height()];
canvas.drawText(string, 1, -bound.top + 1, p);

// 16-bit pixels but stored as bytes.
for (int y = 0; y < bound.height(); y++) {
int srcOffset = y * bmp.getRowBytes();
int dstOffset = y * bound.width();
for (int x = 0; x < bound.width(); x++) {
int val = bytes[srcOffset + x * 2];
output[dstOffset + x] = (short)val;
}
}
return output;
int [] pixels = new int[w * h];
bmp.getPixels(pixels, 0, w, 0, 0, w, h);
return pixels;
}
}
4 changes: 3 additions & 1 deletion ext/native/gfx_es2/draw_text.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -35,9 +35,11 @@ void TextDrawer::SetFontScale(float xscale, float yscale) {

float TextDrawer::CalculateDPIScale() {
float scale = g_dpi_scale;
#if !PPSSPP_PLATFORM(ANDROID)
if (scale >= 1.0f) {
scale = 1.0f;
}
#endif
return scale;
}

Expand All @@ -55,4 +57,4 @@ TextDrawer *TextDrawer::Create(Draw::DrawContext *draw) {
drawer = nullptr;
}
return drawer;
}
}
67 changes: 37 additions & 30 deletions ext/native/gfx_es2/draw_text_android.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,7 @@
#include "gfx_es2/draw_text_android.h"

#include "android/jni/app-android.h"
#include <assert.h>

#if PPSSPP_PLATFORM(ANDROID)

Expand All @@ -17,20 +18,25 @@
TextDrawerAndroid::TextDrawerAndroid(Draw::DrawContext *draw) : TextDrawer(draw) {
env_ = jniEnvGraphics;
const char *textRendererClassName = "org/ppsspp/ppsspp/TextRenderer";
cls_textRenderer = env_->FindClass(textRendererClassName);
jclass localClass = env_->FindClass(textRendererClassName);
cls_textRenderer = reinterpret_cast<jclass>(env_->NewGlobalRef(localClass));
ILOG("cls_textRender: %p", cls_textRenderer);
if (cls_textRenderer) {
method_measureText = env_->GetStaticMethodID(cls_textRenderer, "measureText", "(Ljava/lang/String;F)I");
method_measureText = env_->GetStaticMethodID(cls_textRenderer, "measureText", "(Ljava/lang/String;D)I");
ILOG("method_measureText: %p", method_measureText);
method_renderText = env_->GetStaticMethodID(cls_textRenderer, "renderText", "(Ljava/lang/String;F)[S");
method_renderText = env_->GetStaticMethodID(cls_textRenderer, "renderText", "(Ljava/lang/String;D)[I");
ILOG("method_renderText: %p", method_renderText);
} else {
ELOG("Failed to find class: %s", textRendererClassName);
ELOG("Failed to find class: '%s'", textRendererClassName);
}
curSize_ = 12;
dpiScale_ = 1.0f;
}

TextDrawerAndroid::~TextDrawerAndroid() {
// Not sure why we can't do this but it crashes.
// At worst we leak one ref...
// env_->DeleteGlobalRef(cls_textRenderer);
ClearCache();
}

Expand All @@ -50,9 +56,10 @@ uint32_t TextDrawerAndroid::SetFont(const char *fontName, int size, int flags) {
return fontHash;
}

curSize_ = size;
curSize_ = (float)((6 + size) / dpiScale_) * 96.0f / 72.f;
AndroidFontEntry entry;
entry.size = curSize_;

fontMap_[fontHash] = entry;
fontHash_ = fontHash;
return fontHash;
Expand All @@ -62,7 +69,7 @@ void TextDrawerAndroid::SetFont(uint32_t fontHandle) {
uint32_t fontHash = fontHandle;
auto iter = fontMap_.find(fontHash);
if (iter != fontMap_.end()) {
curSize_ = iter->second.size;
curSize_ = iter->second.size / dpiScale_;
}
}

Expand All @@ -74,9 +81,9 @@ void TextDrawerAndroid::MeasureString(const char *str, size_t len, float *w, flo
std::string stdstring(str, len);
jstring jstr = env_->NewStringUTF(stdstring.c_str());
uint32_t size = env_->CallStaticIntMethod(cls_textRenderer, method_measureText, jstr, curSize_);
*w = (size >> 16) * fontScaleX_;
*h = (size & 0xFFFF) * fontScaleY_;
env_->DeleteLocalRef(jstr);
*w = (size >> 16) * fontScaleX_ * dpiScale_;
*h = (size & 0xFFFF) * fontScaleY_ * dpiScale_;
}

void TextDrawerAndroid::MeasureStringRect(const char *str, size_t len, const Bounds &bounds, float *w, float *h, int align) {
Expand All @@ -88,15 +95,18 @@ void TextDrawerAndroid::MeasureStringRect(const char *str, size_t len, const Bou

jstring jstr = env_->NewStringUTF(toMeasure.c_str());
uint32_t size = env_->CallStaticIntMethod(cls_textRenderer, method_measureText, jstr, curSize_);
*w = (size >> 16) * fontScaleX_;
*h = (size & 0xFFFF) * fontScaleY_;
env_->DeleteLocalRef(jstr);
*w = (size >> 16) * fontScaleX_ * dpiScale_;
*h = (size & 0xFFFF) * fontScaleY_ * dpiScale_;
}

void TextDrawerAndroid::DrawString(DrawBuffer &target, const char *str, float x, float y, uint32_t color, int align) {
using namespace Draw;
if (!strlen(str))
return;
JNIEnv *env;
int result = javaVM->GetEnv((void **)&env, JNI_VERSION_1_6);
assert(env == env_);

uint32_t stringHash = hash::Fletcher((const uint8_t *)str, strlen(str));
uint32_t entryHash = stringHash ^ fontHash_ ^ (align << 24);
Expand All @@ -112,10 +122,12 @@ void TextDrawerAndroid::DrawString(DrawBuffer &target, const char *str, float x,
draw_->BindTexture(0, entry->texture);
} else {
jstring jstr = env_->NewStringUTF(str);
int len = (int)env_->GetStringUTFLength(jstr);
ILOG("UTF len: %d", len);
uint32_t size = env_->CallStaticIntMethod(cls_textRenderer, method_measureText, jstr, curSize_);
int imageWidth = (size >> 16) * fontScaleX_;
int imageHeight = (size & 0xFFFF) * fontScaleY_;
jshortArray imageData = (jshortArray)env_->CallStaticObjectMethod(cls_textRenderer, method_renderText, jstr, curSize_);
int imageWidth = (size >> 16);
int imageHeight = (size & 0xFFFF);
jintArray imageData = (jintArray)env_->CallStaticObjectMethod(cls_textRenderer, method_renderText, jstr, curSize_);
env_->DeleteLocalRef(jstr);

entry = new TextStringEntry();
Expand All @@ -132,23 +144,25 @@ void TextDrawerAndroid::DrawString(DrawBuffer &target, const char *str, float x,
desc.mipLevels = 1;

uint16_t *bitmapData = new uint16_t[entry->bmWidth * entry->bmHeight];
jshort* jimage = env_->GetShortArrayElements(imageData, nullptr);
jint* jimage = env_->GetIntArrayElements(imageData, nullptr);
int arraySize = env_->GetArrayLength(imageData);
assert(arraySize == imageWidth * imageHeight);
for (int x = 0; x < entry->bmWidth; x++) {
for (int y = 0; y < entry->bmHeight; y++) {
int v = jimage[imageWidth * y + x];
v = (v << 4) | v;
v = (v << 8) | v;
bitmapData[entry->bmWidth * y + x] = v;
uint32_t v = jimage[imageWidth * y + x];
v = 0xFFF0 | ((v >> 12) & 0xF); // Just grab some bits from the green channel.
bitmapData[entry->bmWidth * y + x] = (uint16_t)v;
}
}
env_->ReleaseShortArrayElements(imageData, jimage, 0);
env_->ReleaseIntArrayElements(imageData, jimage, 0);
desc.initData.push_back((uint8_t *)bitmapData);
entry->texture = draw_->CreateTexture(desc);
delete[] bitmapData;
cache_[entryHash] = std::unique_ptr<TextStringEntry>(entry);
draw_->BindTexture(0, entry->texture);
}
float w = entry->bmWidth * fontScaleX_;
float h = entry->bmHeight * fontScaleY_;
float w = entry->bmWidth * fontScaleX_ * dpiScale_;
float h = entry->bmHeight * fontScaleY_ * dpiScale_;
DrawBuffer::DoAlign(align, &x, &y, &w, &h);
target.DrawTexRect(x, y, x + w, y + h, 0.0f, 0.0f, 1.0f, 1.0f, color);
target.Flush(true);
Expand All @@ -160,7 +174,7 @@ void TextDrawerAndroid::ClearCache() {
iter.second->texture->Release();
}
cache_.clear();
sizeCache_.clear();
fontMap_.clear();
}

void TextDrawerAndroid::DrawStringRect(DrawBuffer &target, const char *str, const Bounds &bounds, uint32_t color, int align) {
Expand Down Expand Up @@ -191,6 +205,7 @@ void TextDrawerAndroid::OncePerFrame() {
// If DPI changed (small-mode, future proper monitor DPI support), drop everything.
float newDpiScale = CalculateDPIScale();
if (newDpiScale != dpiScale_) {
ILOG("Scale changed - recreating fonts");
dpiScale_ = newDpiScale;
ClearCache();
RecreateFonts();
Expand All @@ -207,14 +222,6 @@ void TextDrawerAndroid::OncePerFrame() {
iter++;
}
}

for (auto iter = sizeCache_.begin(); iter != sizeCache_.end(); ) {
if (frameCount_ - iter->second->lastUsedFrame > 100) {
sizeCache_.erase(iter++);
} else {
iter++;
}
}
}
}

Expand Down
5 changes: 2 additions & 3 deletions ext/native/gfx_es2/draw_text_android.h
Original file line number Diff line number Diff line change
Expand Up @@ -37,15 +37,14 @@ class TextDrawerAndroid : public TextDrawer {
jclass cls_textRenderer;
jmethodID method_measureText;
jmethodID method_renderText;
float curSize_;
double curSize_;

uint32_t fontHash_;

std::map<uint32_t, AndroidFontEntry> fontMap_;

// The key is the CityHash of the string xor the fontHash_.
std::map<uint32_t, std::unique_ptr<TextStringEntry>> cache_;
std::map<uint32_t, std::unique_ptr<TextMeasureEntry>> sizeCache_;
};

#endif
#endif
1 change: 1 addition & 0 deletions ext/native/thin3d/thin3d_gl.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -675,6 +675,7 @@ OpenGLTexture::OpenGLTexture(const TextureDesc &desc) {
type_ = desc.type;
target_ = TypeToTarget(desc.type);
canWrap_ = isPowerOf2(width_) && isPowerOf2(height_);
mipLevels_ = desc.mipLevels;
if (!desc.initData.size())
return;

Expand Down

0 comments on commit 0d3d642

Please sign in to comment.