From 87e9c93264504f55b75d4d7fd61b4f1a0560a630 Mon Sep 17 00:00:00 2001
From: Anthony Calosa
Date: Mon, 7 Oct 2019 12:59:52 +0800
Subject: [PATCH] New Faster Cache for Mobile - Cache2k, Add Border Masking
Option
---
.../game/ability/effects/BlockEffect.java | 3 +-
forge-gui-android/pom.xml | 18 +++
forge-gui-android/proguard.cfg | 14 +++
forge-gui-ios/pom.xml | 18 +++
forge-gui-mobile-dev/pom.xml | 18 +++
forge-gui-mobile/pom.xml | 18 +++
.../src/forge/CachedCardImage.java | 6 +-
.../src/forge/assets/ImageCache.java | 43 ++++---
.../src/forge/assets/ImageLoader.java | 113 +++++++++++++++---
.../src/forge/card/CardImage.java | 11 +-
.../src/forge/card/CardImageRenderer.java | 7 +-
.../src/forge/card/CardRenderer.java | 20 +++-
.../forge/screens/settings/SettingsPage.java | 4 +
.../forge/properties/ForgePreferences.java | 1 +
14 files changed, 248 insertions(+), 46 deletions(-)
diff --git a/forge-game/src/main/java/forge/game/ability/effects/BlockEffect.java b/forge-game/src/main/java/forge/game/ability/effects/BlockEffect.java
index 5737a68e3e2..9d96e0cff20 100644
--- a/forge-game/src/main/java/forge/game/ability/effects/BlockEffect.java
+++ b/forge-game/src/main/java/forge/game/ability/effects/BlockEffect.java
@@ -11,6 +11,7 @@ import forge.game.Game;
import forge.game.spellability.SpellAbility;
import forge.game.trigger.TriggerType;
import forge.game.zone.ZoneType;
+import org.apache.commons.lang3.StringUtils;
import java.util.*;
@@ -106,7 +107,7 @@ public class BlockEffect extends SpellAbilityEffect {
}
}
- sb.append(String.join(", ", blockers)).append(" block ").append(String.join(", ", attackers));
+ sb.append(StringUtils.join(blockers.toArray(), ", ")).append(" block ").append(StringUtils.join(attackers.toArray(), ", "));
return sb.toString();
}
diff --git a/forge-gui-android/pom.xml b/forge-gui-android/pom.xml
index 7708708406e..ebc8f35f90f 100644
--- a/forge-gui-android/pom.xml
+++ b/forge-gui-android/pom.xml
@@ -104,6 +104,24 @@
gdx-backend-android
1.9.10
+
+ org.cache2k
+ cache2k-base-bom
+ 1.2.4.Final
+ pom
+
+
+ org.cache2k
+ cache2k-core
+ 1.2.4.Final
+ compile
+
+
+ org.cache2k
+ cache2k-api
+ 1.2.4.Final
+ compile
+
diff --git a/forge-gui-android/proguard.cfg b/forge-gui-android/proguard.cfg
index e6a1ef032c5..159c6a4348c 100644
--- a/forge-gui-android/proguard.cfg
+++ b/forge-gui-android/proguard.cfg
@@ -28,6 +28,20 @@
-dontwarn org.slf4j.**
-dontwarn javax.**
+# mandatory proguard rules for cache2k to keep the core implementation
+-dontwarn org.cache2k.impl.xmlConfiguration.**
+-dontwarn org.cache2k.impl.serverSide.**
+-keep interface org.cache2k.spi.Cache2kCoreProvider
+-keep public class * extends org.cache2k.spi.Cache2kCoreProvider
+# optional proguard rules for cache2k, to keep XML configuration code
+# if only programmatic configuration is used, these rules may be ommitted
+-keep interface org.cache2k.core.spi.CacheConfigurationProvider
+-keep public class * extends org.cache2k.core.spi.CacheConfigurationProvider
+-keepclassmembers public class * extends org.cache2k.configuration.ConfigurationBean {
+ public void set*(...);
+ public ** get*();
+}
+
-keep class forge.** { *; }
-keep class com.thoughtworks.xstream.** { *; }
-keep class org.apache.commons.lang3.** { *; }
diff --git a/forge-gui-ios/pom.xml b/forge-gui-ios/pom.xml
index 21539d4c17e..a48dfcb7641 100644
--- a/forge-gui-ios/pom.xml
+++ b/forge-gui-ios/pom.xml
@@ -75,5 +75,23 @@
gdx-backend-robovm
1.9.10
+
+ org.cache2k
+ cache2k-base-bom
+ 1.2.4.Final
+ pom
+
+
+ org.cache2k
+ cache2k-core
+ 1.2.4.Final
+ compile
+
+
+ org.cache2k
+ cache2k-api
+ 1.2.4.Final
+ compile
+
diff --git a/forge-gui-mobile-dev/pom.xml b/forge-gui-mobile-dev/pom.xml
index c515dd9a240..4591747ecb1 100644
--- a/forge-gui-mobile-dev/pom.xml
+++ b/forge-gui-mobile-dev/pom.xml
@@ -80,5 +80,23 @@
commons-cli
1.4
+
+ org.cache2k
+ cache2k-base-bom
+ 1.2.4.Final
+ pom
+
+
+ org.cache2k
+ cache2k-core
+ 1.2.4.Final
+ compile
+
+
+ org.cache2k
+ cache2k-api
+ 1.2.4.Final
+ compile
+
diff --git a/forge-gui-mobile/pom.xml b/forge-gui-mobile/pom.xml
index a3e0183dd9c..f21a549db0e 100644
--- a/forge-gui-mobile/pom.xml
+++ b/forge-gui-mobile/pom.xml
@@ -70,6 +70,24 @@
gdx-freetype
1.9.10
+
+ org.cache2k
+ cache2k-base-bom
+ 1.2.4.Final
+ pom
+
+
+ org.cache2k
+ cache2k-core
+ 1.2.4.Final
+ compile
+
+
+ org.cache2k
+ cache2k-api
+ 1.2.4.Final
+ compile
+
diff --git a/forge-gui-mobile/src/forge/CachedCardImage.java b/forge-gui-mobile/src/forge/CachedCardImage.java
index a58ffff4a27..91fad648edd 100644
--- a/forge-gui-mobile/src/forge/CachedCardImage.java
+++ b/forge-gui-mobile/src/forge/CachedCardImage.java
@@ -34,7 +34,11 @@ public abstract class CachedCardImage implements ImageFetcher.Callback {
}
public Texture getImage() {
- return ImageCache.getImage(key, true);
+ return ImageCache.getImage(key, true, false);
+ }
+
+ public Texture getImage(boolean mask) {
+ return ImageCache.getImage(key, true, mask);
}
public abstract void onImageFetched();
diff --git a/forge-gui-mobile/src/forge/assets/ImageCache.java b/forge-gui-mobile/src/forge/assets/ImageCache.java
index 6245e4ef2a4..a26cbc204d6 100644
--- a/forge-gui-mobile/src/forge/assets/ImageCache.java
+++ b/forge-gui-mobile/src/forge/assets/ImageCache.java
@@ -20,18 +20,17 @@ package forge.assets;
import com.badlogic.gdx.Gdx;
import com.badlogic.gdx.graphics.Pixmap.Format;
import com.badlogic.gdx.graphics.Texture;
-import com.google.common.cache.CacheBuilder;
-import com.google.common.cache.LoadingCache;
import forge.ImageKeys;
import forge.game.player.IHasIcon;
import forge.item.InventoryItem;
import forge.properties.ForgeConstants;
import forge.util.ImageUtil;
import org.apache.commons.lang3.StringUtils;
+import org.cache2k.Cache;
+import org.cache2k.Cache2kBuilder;
import java.util.HashSet;
import java.util.Set;
-import java.util.concurrent.ExecutionException;
import java.util.concurrent.TimeUnit;
/**
@@ -52,10 +51,14 @@ public class ImageCache {
// short prefixes to save memory
private static final Set missingIconKeys = new HashSet<>();
- private static final LoadingCache cache = CacheBuilder.newBuilder()
- .maximumSize(400)
- .expireAfterAccess(15,TimeUnit.MINUTES)
- .build(new ImageLoader());
+ private static final Cache cache = new Cache2kBuilder() {}
+ .name("cache")
+ .entryCapacity(500)
+ .expireAfterWrite(15, TimeUnit.MINUTES)
+ .refreshAhead(true)
+ .permitNullValues(true)
+ .loader(new ImageLoader())
+ .build();
public static final Texture defaultImage;
private static boolean imageLoaded, delayLoadRequested;
@@ -76,12 +79,16 @@ public class ImageCache {
}
public static void clear() {
- cache.invalidateAll();
+ cache.clear();
missingIconKeys.clear();
}
public static Texture getImage(InventoryItem ii) {
- return getImage(ii.getImageKey(false), true);
+ return getImage(ii.getImageKey(false), true, false);
+ }
+
+ public static Texture getImage(InventoryItem ii, Boolean mask) {
+ return getImage(ii.getImageKey(false), true, mask);
}
/**
@@ -107,6 +114,9 @@ public class ImageCache {
*
*/
public static Texture getImage(String imageKey, boolean useDefaultIfNotFound) {
+ return getImage(imageKey, useDefaultIfNotFound, false);
+ }
+ public static Texture getImage(String imageKey, boolean useDefaultIfNotFound, boolean maskCard) {
if (StringUtils.isEmpty(imageKey)) {
return null;
}
@@ -125,7 +135,10 @@ public class ImageCache {
Texture image;
if (useDefaultIfNotFound) {
// Load from file and add to cache if not found in cache initially.
- image = cache.getIfPresent(imageKey);
+ if (maskCard)//if we add pixmap modification here, it will slow performance so we do this on the image loader lol :)...
+ imageKey += "#drawroundcorner#";
+ image = cache.get(imageKey);
+
if (image != null) { return image; }
if (imageLoaded) { //prevent loading more than one image each render for performance
@@ -139,15 +152,7 @@ public class ImageCache {
imageLoaded = true;
}
- try {
- image = cache.get(imageKey);
- }
- catch (final ExecutionException ex) {
- if (!(ex.getCause() instanceof NullPointerException)) {
- ex.printStackTrace();
- }
- image = null;
- }
+ try { image = cache.get(imageKey); }
catch (final Exception ex) {
image = null;
}
diff --git a/forge-gui-mobile/src/forge/assets/ImageLoader.java b/forge-gui-mobile/src/forge/assets/ImageLoader.java
index e8668c6862f..968a6f8b0c1 100644
--- a/forge-gui-mobile/src/forge/assets/ImageLoader.java
+++ b/forge-gui-mobile/src/forge/assets/ImageLoader.java
@@ -3,8 +3,12 @@ package forge.assets;
import java.io.File;
import com.badlogic.gdx.files.FileHandle;
+import com.badlogic.gdx.graphics.Color;
+import com.badlogic.gdx.graphics.Pixmap;
import com.badlogic.gdx.graphics.Texture;
-import com.google.common.cache.CacheLoader;
+import com.badlogic.gdx.graphics.TextureData;
+import com.badlogic.gdx.graphics.glutils.PixmapTextureData;
+import org.cache2k.integration.CacheLoader;
import forge.Forge;
import forge.ImageKeys;
@@ -12,27 +16,49 @@ import forge.ImageKeys;
final class ImageLoader extends CacheLoader {
@Override
public Texture load(String key) {
- File file = ImageKeys.getImageFile(key);
+ boolean mask = key.contains("#drawroundcorner#");
+ boolean alphaCard = false;
+ boolean textureFilter = Forge.isTextureFilteringEnabled();
+ if (key.length() > 4){
+ if ((key.substring(0,4).contains("LEA/")) || (key.substring(0,2).contains("A/")))
+ alphaCard = true;
+ //TODO dont add border on some sets???
+ }
+ File file = ImageKeys.getImageFile(key.replaceAll("#drawroundcorner#",""));
if (file != null) {
FileHandle fh = new FileHandle(file);
try {
- if (Forge.isTextureFilteringEnabled()) {
- Texture t = new Texture(fh, true);
- t.setFilter(Texture.TextureFilter.MipMapLinearLinear, Texture.TextureFilter.Linear);
-
- /* // Optional experimental feature: Anisotropic filtering
- GL20 gl = Gdx.gl20;
- if (gl != null && Gdx.graphics.supportsExtension("GL_EXT_texture_filter_anisotropic")) {
- FloatBuffer buffer = BufferUtils.newFloatBuffer(16);
- gl.glGetFloatv(GL20.GL_MAX_TEXTURE_MAX_ANISOTROPY_EXT, buffer);
- float maxAniso = buffer.get(0);
-
- t.bind();
- gl.glTexParameterf(GL20.GL_TEXTURE_2D, GL20.GL_TEXTURE_MAX_ANISOTROPY_EXT, maxAniso);
- } */
+ Texture t;
+ if (mask) {
+ Pixmap pImage = new Pixmap(fh);
+ int w = pImage.getWidth();
+ int h = pImage.getHeight();
+ int radius = alphaCard ? (h - w) / 6 : (h - w) / 8;
+ Pixmap pMask = createRoundedRectangle(w, h, radius, Color.RED);
+ drawPixelstoMask(pImage, pMask);
+ TextureData textureData = new PixmapTextureData(
+ pMask, //pixmap to use
+ Pixmap.Format.RGBA8888,
+ textureFilter, //use mipmaps
+ false, true);
+ if (textureFilter)
+ {
+ t = new Texture(textureData);
+ t.setFilter(Texture.TextureFilter.MipMapLinearLinear, Texture.TextureFilter.Linear);
+ } else {
+ t = new Texture(textureData);
+ }
+ pImage.dispose();
+ pMask.dispose();
return t;
} else {
- return new Texture(fh);
+ if (textureFilter) {
+ t = new Texture(fh, true);
+ t.setFilter(Texture.TextureFilter.MipMapLinearLinear, Texture.TextureFilter.Linear);
+ return t;
+ }
+ else
+ return new Texture(fh);
}
}
catch (Exception ex) {
@@ -41,4 +67,57 @@ final class ImageLoader extends CacheLoader {
}
return null;
}
+ public Pixmap createRoundedRectangle(int width, int height, int cornerRadius, Color color) {
+ Pixmap pixmap = new Pixmap(width, height, Pixmap.Format.RGBA8888);
+ Pixmap ret = new Pixmap(width, height, Pixmap.Format.RGBA8888);
+ pixmap.setColor(color);
+ //round corners
+ pixmap.fillCircle(cornerRadius, cornerRadius, cornerRadius);
+ pixmap.fillCircle(width - cornerRadius - 1, cornerRadius, cornerRadius);
+ pixmap.fillCircle(cornerRadius, height - cornerRadius - 1, cornerRadius);
+ pixmap.fillCircle(width - cornerRadius - 1, height - cornerRadius - 1, cornerRadius);
+ //two rectangle parts
+ pixmap.fillRectangle(cornerRadius, 0, width - cornerRadius * 2, height);
+ pixmap.fillRectangle(0, cornerRadius, width, height - cornerRadius * 2);
+ //draw rounded rectangle
+ ret.setColor(color);
+ for (int x = 0; x < width; x++) {
+ for (int y = 0; y < height; y++) {
+ if (pixmap.getPixel(x, y) != 0) ret.drawPixel(x, y);
+ }
+ }
+ pixmap.dispose();
+ return ret;
+ }
+ public void drawPixelstoMask(Pixmap pixmap, Pixmap mask){
+ int pixmapWidth = mask.getWidth();
+ int pixmapHeight = mask.getHeight();
+ Color pixelColor = new Color();
+ for (int x=0; x {
localizer.getMessage("lblDisableCardEffect"),
localizer.getMessage("nlDisableCardEffect")),
4);
+ lstSettings.addItem(new BooleanSetting(FPref.UI_ENABLE_BORDER_MASKING,
+ "Enable Round Border Mask",
+ "When enabled, the card corners are rounded (Longer Caching)."),
+ 4);
lstSettings.addItem(new CustomSelectSetting(FPref.UI_CARD_COUNTER_DISPLAY_TYPE,
localizer.getMessage("cbpCounterDisplayType"),
diff --git a/forge-gui/src/main/java/forge/properties/ForgePreferences.java b/forge-gui/src/main/java/forge/properties/ForgePreferences.java
index b6dcf1be167..a43681bbcd1 100644
--- a/forge-gui/src/main/java/forge/properties/ForgePreferences.java
+++ b/forge-gui/src/main/java/forge/properties/ForgePreferences.java
@@ -134,6 +134,7 @@ public class ForgePreferences extends PreferencesStore {
UI_ROTATE_SPLIT_CARDS("true"),
UI_DYNAMIC_PLANECHASE_BG("false"),
UI_DISABLE_IMAGES_EFFECT_CARDS("false"),
+ UI_ENABLE_BORDER_MASKING("false"),
UI_ALLOW_ORDER_GRAVEYARD_WHEN_NEEDED ("Never"),
UI_DEFAULT_FONT_SIZE("12"),
UI_SELECT_FROM_CARD_DISPLAYS("true"),