mirror of
https://github.com/Card-Forge/forge.git
synced 2025-11-18 03:38:01 +00:00
Optimize card rendering behind other cards
Fix issue with achievement tooltip not appearing at times
This commit is contained in:
@@ -16,6 +16,7 @@ import forge.assets.FSkinImage;
|
||||
import forge.assets.FSkinTexture;
|
||||
import forge.assets.TextRenderer;
|
||||
import forge.card.CardDetailUtil.DetailColors;
|
||||
import forge.card.CardRenderer.CardStackPosition;
|
||||
import forge.card.mana.ManaCost;
|
||||
import forge.screens.FScreen;
|
||||
import forge.view.CardView;
|
||||
@@ -56,7 +57,7 @@ public class CardImageRenderer {
|
||||
prevImageHeight = h;
|
||||
}
|
||||
|
||||
public static void drawCardImage(Graphics g, CardView card, float x, float y, float w, float h) {
|
||||
public static void drawCardImage(Graphics g, CardView card, float x, float y, float w, float h, CardStackPosition pos) {
|
||||
updateStaticFields(w, h);
|
||||
final CardStateView state = card.getOriginal();
|
||||
|
||||
@@ -94,6 +95,10 @@ public class CardImageRenderer {
|
||||
Color headerColor1 = FSkinColor.tintColor(Color.WHITE, color1, CardRenderer.NAME_BOX_TINT);
|
||||
Color headerColor2 = color2 == null ? null : FSkinColor.tintColor(Color.WHITE, color2, CardRenderer.NAME_BOX_TINT);
|
||||
drawHeader(g, card, headerColor1, headerColor2, x, y, w, headerHeight);
|
||||
|
||||
if (pos == CardStackPosition.BehindVert) { return; } //remaining rendering not needed if card is behind another card in a vertical stack
|
||||
boolean onTop = (pos == CardStackPosition.Top);
|
||||
|
||||
y += headerHeight;
|
||||
|
||||
float artWidth = w - 2 * artInset;
|
||||
@@ -138,7 +143,8 @@ public class CardImageRenderer {
|
||||
y += textBoxHeight;
|
||||
|
||||
//draw P/T box
|
||||
if (ptBoxHeight > 0) {
|
||||
if (onTop && ptBoxHeight > 0) {
|
||||
//only needed if on top since otherwise P/T will be hidden
|
||||
Color ptColor1 = FSkinColor.tintColor(Color.WHITE, color1, CardRenderer.PT_BOX_TINT);
|
||||
Color ptColor2 = color2 == null ? null : FSkinColor.tintColor(Color.WHITE, color2, CardRenderer.PT_BOX_TINT);
|
||||
drawPtBox(g, card, ptColor1, ptColor2, x, y - 2 * artInset, w, ptBoxHeight);
|
||||
|
||||
@@ -40,6 +40,12 @@ import forge.view.CardView.CardStateView;
|
||||
import forge.view.ViewUtil;
|
||||
|
||||
public class CardRenderer {
|
||||
public enum CardStackPosition {
|
||||
Top,
|
||||
BehindHorz,
|
||||
BehindVert
|
||||
}
|
||||
|
||||
private static final FSkinFont NAME_FONT = FSkinFont.get(16);
|
||||
private static final FSkinFont TYPE_FONT = FSkinFont.get(14);
|
||||
private static final FSkinFont SET_FONT = TYPE_FONT;
|
||||
@@ -94,7 +100,7 @@ public class CardRenderer {
|
||||
w = h / FCardPanel.ASPECT_RATIO;
|
||||
x += (oldWidth - w) / 2;
|
||||
}
|
||||
CardImageRenderer.drawCardImage(g, card, x, y, w, h);
|
||||
CardImageRenderer.drawCardImage(g, card, x, y, w, h, CardStackPosition.Top);
|
||||
drawFoilEffect(g, card, x, y, w, h);
|
||||
return true;
|
||||
}
|
||||
@@ -495,11 +501,11 @@ public class CardRenderer {
|
||||
g.drawText(ptText, PT_FONT, Color.BLACK, x, y, w, h, false, HAlignment.CENTER, true);
|
||||
}
|
||||
|
||||
public static void drawCard(Graphics g, IPaperCard pc, float x, float y, float w, float h) {
|
||||
public static void drawCard(Graphics g, IPaperCard pc, float x, float y, float w, float h, CardStackPosition pos) {
|
||||
Texture image = ImageCache.getImage(pc);
|
||||
if (image != null) {
|
||||
if (image == ImageCache.defaultImage) {
|
||||
CardImageRenderer.drawCardImage(g, ViewUtil.getCardForUi(pc), x, y, w, h);
|
||||
CardImageRenderer.drawCardImage(g, ViewUtil.getCardForUi(pc), x, y, w, h, pos);
|
||||
}
|
||||
else {
|
||||
g.drawImage(image, x, y, w, h);
|
||||
@@ -516,11 +522,11 @@ public class CardRenderer {
|
||||
g.fillRect(Color.BLACK, x, y, w, h);
|
||||
}
|
||||
}
|
||||
public static void drawCard(Graphics g, CardView card, float x, float y, float w, float h) {
|
||||
public static void drawCard(Graphics g, CardView card, float x, float y, float w, float h, CardStackPosition pos) {
|
||||
Texture image = ImageCache.getImage(card);
|
||||
if (image != null) {
|
||||
if (image == ImageCache.defaultImage) {
|
||||
CardImageRenderer.drawCardImage(g, card, x, y, w, h);
|
||||
CardImageRenderer.drawCardImage(g, card, x, y, w, h, pos);
|
||||
}
|
||||
else {
|
||||
g.drawImage(image, x, y, w, h);
|
||||
@@ -532,8 +538,8 @@ public class CardRenderer {
|
||||
}
|
||||
}
|
||||
|
||||
public static void drawCardWithOverlays(Graphics g, CardView card, float x, float y, float w, float h) {
|
||||
drawCard(g, card, x, y, w, h);
|
||||
public static void drawCardWithOverlays(Graphics g, CardView card, float x, float y, float w, float h, CardStackPosition pos) {
|
||||
drawCard(g, card, x, y, w, h, pos);
|
||||
|
||||
float padding = w * 0.021f; //adjust for card border
|
||||
x += padding;
|
||||
@@ -564,6 +570,9 @@ public class CardRenderer {
|
||||
}
|
||||
}
|
||||
|
||||
if (pos == CardStackPosition.BehindVert) { return; } //remaining rendering not needed if card is behind another card in a vertical stack
|
||||
boolean onTop = (pos == CardStackPosition.Top);
|
||||
|
||||
if (showCardIdOverlay(card)) {
|
||||
FSkinFont idFont = FSkinFont.forHeight(h * 0.12f);
|
||||
float idHeight = idFont.getCapHeight();
|
||||
@@ -612,7 +621,8 @@ public class CardRenderer {
|
||||
}
|
||||
}
|
||||
|
||||
if (details.isCreature() && card.isSick() && card.getZone() == ZoneType.Battlefield) {
|
||||
if (onTop && details.isCreature() && card.isSick() && card.getZone() == ZoneType.Battlefield) {
|
||||
//only needed if on top since otherwise symbol will be hidden
|
||||
CardFaceSymbols.drawSymbol("summonsick", g, stateXSymbols, ySymbols, otherSymbolsSize, otherSymbolsSize);
|
||||
}
|
||||
|
||||
@@ -625,7 +635,8 @@ public class CardRenderer {
|
||||
CardFaceSymbols.drawSymbol("sacrifice", g, (x + (w / 2)) - sacSymbolSize / 2, (y + (h / 2)) - sacSymbolSize / 2, otherSymbolsSize, otherSymbolsSize);
|
||||
}
|
||||
|
||||
if (showCardPowerOverlay(card)) { //make sure card p/t box appears on top
|
||||
if (onTop && showCardPowerOverlay(card)) { //make sure card p/t box appears on top
|
||||
//only needed if on top since otherwise P/T will be hidden
|
||||
drawPtBox(g, card, details, color, x, y, w, h);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -26,6 +26,7 @@ import forge.assets.FSkinFont;
|
||||
import forge.assets.FSkinImage;
|
||||
import forge.card.CardEdition;
|
||||
import forge.card.CardRenderer;
|
||||
import forge.card.CardRenderer.CardStackPosition;
|
||||
import forge.card.CardRules;
|
||||
import forge.card.CardZoom;
|
||||
import forge.card.mana.ManaCostShard;
|
||||
@@ -401,7 +402,7 @@ public class AddBasicLandsDialog extends FDialog {
|
||||
@Override
|
||||
public void draw(Graphics g) {
|
||||
if (card == null) { return; }
|
||||
CardRenderer.drawCard(g, card, 0, 0, getWidth(), getHeight());
|
||||
CardRenderer.drawCard(g, card, 0, 0, getWidth(), getHeight(), CardStackPosition.Top);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -9,6 +9,7 @@ import forge.assets.FSkinColor.Colors;
|
||||
import forge.assets.FSkinFont;
|
||||
import forge.assets.ImageCache;
|
||||
import forge.card.CardRenderer;
|
||||
import forge.card.CardRenderer.CardStackPosition;
|
||||
import forge.card.CardZoom;
|
||||
import forge.deck.DeckProxy;
|
||||
import forge.item.IPaperCard;
|
||||
@@ -474,6 +475,8 @@ public class ImageView<T extends InventoryItem> extends ItemView<T> {
|
||||
x = 0;
|
||||
|
||||
for (ItemInfo itemInfo : group.items) {
|
||||
itemInfo.pos = CardStackPosition.Top;
|
||||
|
||||
if (pile.items.size() == columnCount) {
|
||||
pile = new Pile();
|
||||
x = 0;
|
||||
@@ -500,9 +503,11 @@ public class ImageView<T extends InventoryItem> extends ItemView<T> {
|
||||
Pile pile = group.piles.get(j);
|
||||
y = pileY;
|
||||
for (ItemInfo itemInfo : pile.items) {
|
||||
itemInfo.pos = CardStackPosition.BehindVert;
|
||||
itemInfo.setBounds(x, y, itemWidth, itemHeight);
|
||||
y += dy;
|
||||
}
|
||||
pile.items.get(pile.items.size() - 1).pos = CardStackPosition.Top;
|
||||
pileHeight = y + itemHeight - dy - pileY;
|
||||
if (pileHeight > maxPileHeight) {
|
||||
maxPileHeight = pileHeight;
|
||||
@@ -906,7 +911,10 @@ public class ImageView<T extends InventoryItem> extends ItemView<T> {
|
||||
}
|
||||
}
|
||||
if (skippedItem != null) {
|
||||
CardStackPosition backupPos = skippedItem.pos;
|
||||
skippedItem.pos = CardStackPosition.Top; //ensure skipped item rendered as if it was on top
|
||||
skippedItem.draw(g);
|
||||
skippedItem.pos = backupPos;
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -914,6 +922,7 @@ public class ImageView<T extends InventoryItem> extends ItemView<T> {
|
||||
private final T item;
|
||||
private final Group group;
|
||||
private int index;
|
||||
private CardStackPosition pos;
|
||||
private boolean selected;
|
||||
|
||||
private ItemInfo(T item0, Group group0) {
|
||||
@@ -954,7 +963,7 @@ public class ImageView<T extends InventoryItem> extends ItemView<T> {
|
||||
}
|
||||
|
||||
if (item instanceof PaperCard) {
|
||||
CardRenderer.drawCard(g, (PaperCard)item, x, y, w, h);
|
||||
CardRenderer.drawCard(g, (PaperCard)item, x, y, w, h, pos);
|
||||
}
|
||||
else {
|
||||
Texture img = ImageCache.getImage(item);
|
||||
|
||||
@@ -12,6 +12,7 @@ import forge.FThreads;
|
||||
import forge.Graphics;
|
||||
import forge.GuiBase;
|
||||
import forge.card.CardZoom;
|
||||
import forge.card.CardRenderer.CardStackPosition;
|
||||
import forge.match.MatchUtil;
|
||||
import forge.toolbox.FCardPanel;
|
||||
import forge.view.CardView;
|
||||
@@ -213,6 +214,14 @@ public abstract class VCardDisplayArea extends VDisplayArea {
|
||||
prevPanelInStack = prevPanelInStack0;
|
||||
}
|
||||
|
||||
@Override
|
||||
protected CardStackPosition getStackPosition() {
|
||||
if (nextPanelInStack == null && attachedToPanel == null) {
|
||||
return CardStackPosition.Top;
|
||||
}
|
||||
return CardStackPosition.BehindHorz;
|
||||
}
|
||||
|
||||
//clear and reset all pointers from this panel
|
||||
public void reset() {
|
||||
if (!attachedPanels.isEmpty()) {
|
||||
@@ -230,16 +239,22 @@ public abstract class VCardDisplayArea extends VDisplayArea {
|
||||
@Override
|
||||
public boolean tap(float x, float y, int count) {
|
||||
if (renderedCardContains(x, y)) {
|
||||
forge.FTrace.get("tap").start();
|
||||
forge.FTrace.get("tap2").start();
|
||||
FThreads.invokeInBackgroundThread(new Runnable() { //must invoke in game thread in case a dialog needs to be shown
|
||||
@Override
|
||||
public void run() {
|
||||
forge.FTrace.get("selectCard").start();
|
||||
if (!selectCard()) {
|
||||
//if no cards in stack can be selected, just show zoom/details for card
|
||||
CardZoom.show(getCard());
|
||||
}
|
||||
forge.FTrace.get("selectCard").end();
|
||||
Gdx.graphics.requestRendering();
|
||||
forge.FTrace.get("tap2").end();
|
||||
}
|
||||
});
|
||||
forge.FTrace.get("tap").end();
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
|
||||
@@ -18,6 +18,7 @@ import forge.card.CardDetailUtil;
|
||||
import forge.card.CardRenderer;
|
||||
import forge.card.CardZoom;
|
||||
import forge.card.CardDetailUtil.DetailColors;
|
||||
import forge.card.CardRenderer.CardStackPosition;
|
||||
import forge.game.player.Player;
|
||||
import forge.game.zone.ZoneType;
|
||||
import forge.match.MatchUtil;
|
||||
@@ -329,7 +330,7 @@ public class VStack extends FDropDown {
|
||||
|
||||
x += PADDING;
|
||||
y += PADDING;
|
||||
CardRenderer.drawCardWithOverlays(g, stackInstance.getSource(), x, y, CARD_WIDTH, CARD_HEIGHT);
|
||||
CardRenderer.drawCardWithOverlays(g, stackInstance.getSource(), x, y, CARD_WIDTH, CARD_HEIGHT, CardStackPosition.Top);
|
||||
|
||||
x += CARD_WIDTH + PADDING;
|
||||
w -= x + PADDING - BORDER_THICKNESS;
|
||||
|
||||
@@ -146,7 +146,8 @@ public class AchievementsPage extends TabPage<SettingsScreen> {
|
||||
|
||||
@Override
|
||||
public boolean longPress(float x, float y) {
|
||||
return showCard(getAchievementAt(x, y));
|
||||
selectedAchievement = getAchievementAt(x, y);
|
||||
return showCard(selectedAchievement);
|
||||
}
|
||||
|
||||
private boolean showCard(Achievement achievement) {
|
||||
@@ -245,7 +246,7 @@ public class AchievementsPage extends TabPage<SettingsScreen> {
|
||||
x = startX;
|
||||
|
||||
if (y >= getHeight()) {
|
||||
return;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -2,6 +2,7 @@ package forge.toolbox;
|
||||
|
||||
import forge.Graphics;
|
||||
import forge.card.CardRenderer;
|
||||
import forge.card.CardRenderer.CardStackPosition;
|
||||
import forge.util.Utils;
|
||||
import forge.view.CardView;
|
||||
|
||||
@@ -75,6 +76,11 @@ public class FCardPanel extends FDisplayObject {
|
||||
return PADDING;
|
||||
}
|
||||
|
||||
//allow overriding stack position
|
||||
protected CardStackPosition getStackPosition() {
|
||||
return CardStackPosition.Top;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void draw(Graphics g) {
|
||||
if (card == null) { return; }
|
||||
@@ -93,7 +99,7 @@ public class FCardPanel extends FDisplayObject {
|
||||
g.startRotateTransform(x + edgeOffset, y + h - edgeOffset, tappedAngle);
|
||||
}
|
||||
|
||||
CardRenderer.drawCardWithOverlays(g, card, x, y, w, h);
|
||||
CardRenderer.drawCardWithOverlays(g, card, x, y, w, h, getStackPosition());
|
||||
|
||||
if (tapped) {
|
||||
g.endTransform();
|
||||
|
||||
@@ -14,6 +14,7 @@ import forge.assets.TextRenderer;
|
||||
import forge.assets.FSkinColor.Colors;
|
||||
import forge.card.CardRenderer;
|
||||
import forge.card.CardZoom;
|
||||
import forge.card.CardRenderer.CardStackPosition;
|
||||
import forge.item.PaperCard;
|
||||
import forge.screens.match.MatchController;
|
||||
import forge.screens.match.views.VAvatar;
|
||||
@@ -393,7 +394,7 @@ public class FChoiceList<T> extends FList<T> {
|
||||
@Override
|
||||
public void drawValue(Graphics g, T value, FSkinFont font, FSkinColor foreColor, boolean pressed, float x, float y, float w, float h) {
|
||||
SpellAbilityView spellAbility = (SpellAbilityView)value;
|
||||
CardRenderer.drawCardWithOverlays(g, spellAbility.getHostCard(), x, y, VStack.CARD_WIDTH, VStack.CARD_HEIGHT);
|
||||
CardRenderer.drawCardWithOverlays(g, spellAbility.getHostCard(), x, y, VStack.CARD_WIDTH, VStack.CARD_HEIGHT, CardStackPosition.Top);
|
||||
|
||||
float dx = VStack.CARD_WIDTH + FList.PADDING;
|
||||
x += dx;
|
||||
|
||||
@@ -11,6 +11,7 @@ import forge.assets.FImage;
|
||||
import forge.assets.FSkinImage;
|
||||
import forge.card.CardRenderer;
|
||||
import forge.card.CardZoom;
|
||||
import forge.card.CardRenderer.CardStackPosition;
|
||||
import forge.screens.match.views.VPrompt;
|
||||
import forge.toolbox.FEvent.*;
|
||||
import forge.util.Callback;
|
||||
@@ -110,7 +111,7 @@ public class FOptionPane extends FDialog {
|
||||
float x = (getWidth() - w) / 2;
|
||||
float y = 0;
|
||||
|
||||
CardRenderer.drawCard(g, card, x, y, w, h);
|
||||
CardRenderer.drawCard(g, card, x, y, w, h, CardStackPosition.Top);
|
||||
}
|
||||
};
|
||||
cardDisplay.setHeight(Utils.SCREEN_HEIGHT / 2);
|
||||
|
||||
@@ -169,17 +169,21 @@ public class InputAttack extends InputSyncronizedBase {
|
||||
/** {@inheritDoc} */
|
||||
@Override
|
||||
protected final boolean onCardSelected(final Card card, final ITriggerEvent triggerEvent) {
|
||||
forge.FTrace.get("onCardSelected").start();
|
||||
final List<Card> att = combat.getAttackers();
|
||||
if (triggerEvent != null && triggerEvent.getButton() == 3 && att.contains(card)) {
|
||||
if (undeclareAttacker(card)) {
|
||||
updateMessage();
|
||||
forge.FTrace.get("onCardSelected").end();
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
forge.FTrace.get("isAttackingDefender").start();
|
||||
if (combat.isAttacking(card, currentDefender)) {
|
||||
boolean validAction = true;
|
||||
if (isBandingPossible()) {
|
||||
forge.FTrace.get("activateBand").start();
|
||||
// Activate band by selecting/deselecting a band member
|
||||
if (activeBand == null) {
|
||||
activateBand(combat.getBandOfAttacker(card));
|
||||
@@ -197,41 +201,61 @@ public class InputAttack extends InputSyncronizedBase {
|
||||
validAction = false;
|
||||
}
|
||||
}
|
||||
forge.FTrace.get("activateBand").end();
|
||||
}
|
||||
else {
|
||||
//if banding not possible, just undeclare attacker
|
||||
forge.FTrace.get("undeclareAttacker").start();
|
||||
undeclareAttacker(card);
|
||||
forge.FTrace.get("undeclareAttacker").end();
|
||||
}
|
||||
|
||||
updateMessage();
|
||||
forge.FTrace.get("isAttackingDefender").end();
|
||||
forge.FTrace.get("onCardSelected").end();
|
||||
return validAction;
|
||||
}
|
||||
forge.FTrace.get("isAttackingDefender").end();
|
||||
|
||||
forge.FTrace.get("isOpponentOf").start();
|
||||
if (card.getController().isOpponentOf(playerAttacks)) {
|
||||
if (defenders.contains(card)) { // planeswalker?
|
||||
setCurrentDefender(card);
|
||||
forge.FTrace.get("isOpponentOf").end();
|
||||
forge.FTrace.get("onCardSelected").end();
|
||||
return true;
|
||||
}
|
||||
}
|
||||
forge.FTrace.get("isOpponentOf").end();
|
||||
|
||||
forge.FTrace.get("canAttack").start();
|
||||
if (playerAttacks.getZone(ZoneType.Battlefield).contains(card) && CombatUtil.canAttack(card, currentDefender, combat)) {
|
||||
if (activeBand != null && !activeBand.canJoinBand(card)) {
|
||||
activateBand(null);
|
||||
updateMessage();
|
||||
flashIncorrectAction();
|
||||
forge.FTrace.get("onCardSelected").end();
|
||||
return false;
|
||||
}
|
||||
|
||||
forge.FTrace.get("isAttacking").start();
|
||||
if (combat.isAttacking(card)) {
|
||||
combat.removeFromCombat(card);
|
||||
}
|
||||
forge.FTrace.get("isAttacking").end();
|
||||
|
||||
forge.FTrace.get("declareAttacker").start();
|
||||
declareAttacker(card);
|
||||
forge.FTrace.get("declareAttacker").end();
|
||||
updateMessage();
|
||||
forge.FTrace.get("canAttack").end();
|
||||
forge.FTrace.get("onCardSelected").end();
|
||||
return true;
|
||||
}
|
||||
forge.FTrace.get("canAttack").end();
|
||||
|
||||
flashIncorrectAction();
|
||||
forge.FTrace.get("onCardSelected").end();
|
||||
return false;
|
||||
}
|
||||
|
||||
|
||||
Reference in New Issue
Block a user