Merge pull request #6119 from devLotto/resizablescaling

Stretched Resizable Mode
This commit is contained in:
Adam
2018-10-31 18:34:27 -04:00
committed by GitHub
13 changed files with 300 additions and 80 deletions

View File

@@ -1103,9 +1103,9 @@ public interface Client extends GameEngine
RenderOverview getRenderOverview();
/**
* Checked whether the client is in stretched mode.
* Checks whether the client is in stretched mode.
*
* @return true if the client is in stretched, false otherwise
* @return true if the client is in stretched mode, false otherwise
*/
boolean isStretchedEnabled();
@@ -1117,16 +1117,16 @@ public interface Client extends GameEngine
void setStretchedEnabled(boolean state);
/**
* Checks whether the client is using fast rendering techniques when
* stretching the client in fixed mode.
* Checks whether the client is using fast
* rendering techniques when stretching the canvas.
*
* @return true if client is fast rendering, false otherwise
* @return true if stretching is fast rendering, false otherwise
*/
boolean isStretchedFast();
/**
* Sets whether to use fast rendering techniques when in stretch
* fixed mode.
* Sets whether to use fast rendering techniques
* when stretching the canvas.
*
* @param state new fast rendering state
*/
@@ -1134,19 +1134,36 @@ public interface Client extends GameEngine
/**
* Sets whether to force integer scale factor by rounding scale
* factors towards {@code zero} when stretching fixed mode.
* factors towards {@code zero} when stretching.
*
* @param state new integer scaling state
*/
void setStretchedIntegerScaling(boolean state);
/**
* Sets whether to keep aspect ratio when stretching fixed mode.
* Sets whether to keep aspect ratio when stretching.
*
* @param state new keep aspect ratio state
*/
void setStretchedKeepAspectRatio(boolean state);
/**
* Sets the scaling factor when scaling resizable mode.
*
* @param factor new scaling factor
*/
void setScalingFactor(int factor);
/**
* Invalidates cached dimensions that are
* used for stretching and scaling.
*
* @param resize true to tell the game to
* resize the canvas on the next frame,
* false otherwise.
*/
void invalidateStretching(boolean resize);
/**
* Gets the current stretched dimensions of the client.
*

View File

@@ -0,0 +1,32 @@
/*
* Copyright (c) 2018, Lotto <https://github.com/devLotto>
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions are met:
*
* 1. Redistributions of source code must retain the above copyright notice, this
* list of conditions and the following disclaimer.
* 2. Redistributions in binary form must reproduce the above copyright notice,
* this list of conditions and the following disclaimer in the documentation
* and/or other materials provided with the distribution.
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
* ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
* WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
* DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR
* ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
* (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
* LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
* ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
* SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/
package net.runelite.api.events;
/**
* An event posted when the canvas size might have changed.
*/
public class CanvasSizeChanged
{
}

View File

@@ -29,13 +29,13 @@ package net.runelite.api.events;
import lombok.Data;
/**
* An event where the client window has been resized.
* An event where the game has changed from fixed to resizable mode or vice versa.
*/
@Data
public class ResizeableChanged
{
/**
* Whether the window is resized.
* Whether the game is in resizable mode.
*/
private boolean isResized;
}

View File

@@ -297,7 +297,7 @@ public class Hooks implements Callbacks
notifier.processFlash(graphics2d);
// Stretch the game image if the user has that enabled
if (!client.isResized() && client.isStretchedEnabled())
if (client.isStretchedEnabled())
{
GraphicsConfiguration gc = clientUi.getGraphicsConfiguration();
Dimension stretchedDimensions = client.getStretchedDimensions();

View File

@@ -23,19 +23,19 @@
* OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
* OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/
package net.runelite.client.plugins.stretchedfixedmode;
package net.runelite.client.plugins.stretchedmode;
import net.runelite.client.config.Config;
import net.runelite.client.config.ConfigGroup;
import net.runelite.client.config.ConfigItem;
@ConfigGroup("stretchedfixedmode")
public interface StretchedFixedModeConfig extends Config
@ConfigGroup("stretchedmode")
public interface StretchedModeConfig extends Config
{
@ConfigItem(
keyName = "keepAspectRatio",
name = "Keep aspect ratio",
description = "Keeps the aspect ratio when stretching"
description = "Keeps the aspect ratio when stretching."
)
default boolean keepAspectRatio()
{
@@ -45,7 +45,7 @@ public interface StretchedFixedModeConfig extends Config
@ConfigItem(
keyName = "increasedPerformance",
name = "Increased performance mode",
description = "Uses a fast algorithm when stretching, lowering quality but increasing performance"
description = "Uses a fast algorithm when stretching, lowering quality but increasing performance."
)
default boolean increasedPerformance()
{
@@ -55,10 +55,20 @@ public interface StretchedFixedModeConfig extends Config
@ConfigItem(
keyName = "integerScaling",
name = "Integer Scaling",
description = "Forces use of a whole number scale factor"
description = "Forces use of a whole number scale factor when stretching."
)
default boolean integerScaling()
{
return false;
}
@ConfigItem(
keyName = "scalingFactor",
name = "Resizable Scaling (%)",
description = "In resizable mode, the game is reduced in size this much before it's stretched."
)
default int scalingFactor()
{
return 50;
}
}

View File

@@ -23,31 +23,33 @@
* OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
* OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/
package net.runelite.client.plugins.stretchedfixedmode;
package net.runelite.client.plugins.stretchedmode;
import com.google.common.eventbus.Subscribe;
import com.google.inject.Provides;
import javax.inject.Inject;
import net.runelite.api.Client;
import net.runelite.api.events.CanvasSizeChanged;
import net.runelite.api.events.ConfigChanged;
import net.runelite.api.events.ResizeableChanged;
import net.runelite.client.config.ConfigManager;
import net.runelite.client.input.MouseManager;
import net.runelite.client.plugins.Plugin;
import net.runelite.client.plugins.PluginDescriptor;
@PluginDescriptor(
name = "Stretched Fixed Mode",
description = "Resize the game while in fixed mode",
tags = {"resize"},
name = "Stretched Mode",
description = "Stretches the game in fixed and resizable modes.",
tags = {"resize", "ui", "interface", "stretch", "scaling", "fixed"},
enabledByDefault = false
)
public class StretchedFixedModePlugin extends Plugin
public class StretchedModePlugin extends Plugin
{
@Inject
private Client client;
@Inject
private StretchedFixedModeConfig config;
private StretchedModeConfig config;
@Inject
private MouseManager mouseManager;
@@ -59,9 +61,9 @@ public class StretchedFixedModePlugin extends Plugin
private TranslateMouseWheelListener mouseWheelListener;
@Provides
StretchedFixedModeConfig provideConfig(ConfigManager configManager)
StretchedModeConfig provideConfig(ConfigManager configManager)
{
return configManager.getConfig(StretchedFixedModeConfig.class);
return configManager.getConfig(StretchedModeConfig.class);
}
@Override
@@ -83,10 +85,22 @@ public class StretchedFixedModePlugin extends Plugin
mouseManager.unregisterMouseWheelListener(mouseWheelListener);
}
@Subscribe
public void onResizableChanged(ResizeableChanged event)
{
client.invalidateStretching(true);
}
@Subscribe
public void onCanvasSizeChanged(CanvasSizeChanged event)
{
client.invalidateStretching(false);
}
@Subscribe
public void onConfigChanged(ConfigChanged event)
{
if (!event.getGroup().equals("stretchedfixedmode"))
if (!event.getGroup().equals("stretchedmode"))
{
return;
}
@@ -99,5 +113,8 @@ public class StretchedFixedModePlugin extends Plugin
client.setStretchedIntegerScaling(config.integerScaling());
client.setStretchedKeepAspectRatio(config.keepAspectRatio());
client.setStretchedFast(config.increasedPerformance());
client.setScalingFactor(config.scalingFactor());
client.invalidateStretching(true);
}
}

View File

@@ -23,14 +23,13 @@
* OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
* OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/
package net.runelite.client.plugins.stretchedfixedmode;
package net.runelite.client.plugins.stretchedmode;
import java.awt.Component;
import java.awt.Dimension;
import java.awt.event.MouseEvent;
import javax.inject.Inject;
import net.runelite.api.Client;
import net.runelite.api.Constants;
import net.runelite.client.input.MouseListener;
public class TranslateMouseListener implements MouseListener
@@ -87,17 +86,13 @@ public class TranslateMouseListener implements MouseListener
private MouseEvent translateEvent(MouseEvent e)
{
if (!client.isResized())
{
Dimension stretchedDimensions = client.getStretchedDimensions();
Dimension stretchedDimensions = client.getStretchedDimensions();
Dimension realDimensions = client.getRealDimensions();
int newX = (int) (e.getX() / (stretchedDimensions.width / (double) Constants.GAME_FIXED_WIDTH));
int newY = (int) (e.getY() / (stretchedDimensions.height / (double) Constants.GAME_FIXED_HEIGHT));
int newX = (int) (e.getX() / (stretchedDimensions.width / realDimensions.getWidth()));
int newY = (int) (e.getY() / (stretchedDimensions.height / realDimensions.getHeight()));
return new MouseEvent((Component) e.getSource(), e.getID(), e.getWhen(), e.getModifiersEx(),
newX, newY, e.getClickCount(), e.isPopupTrigger(), e.getButton());
}
return e;
return new MouseEvent((Component) e.getSource(), e.getID(), e.getWhen(), e.getModifiersEx(),
newX, newY, e.getClickCount(), e.isPopupTrigger(), e.getButton());
}
}

View File

@@ -23,14 +23,13 @@
* OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
* OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/
package net.runelite.client.plugins.stretchedfixedmode;
package net.runelite.client.plugins.stretchedmode;
import java.awt.Component;
import java.awt.Dimension;
import java.awt.event.MouseWheelEvent;
import javax.inject.Inject;
import net.runelite.api.Client;
import net.runelite.api.Constants;
import net.runelite.client.input.MouseWheelListener;
public class TranslateMouseWheelListener implements MouseWheelListener
@@ -51,17 +50,13 @@ public class TranslateMouseWheelListener implements MouseWheelListener
private MouseWheelEvent translateEvent(MouseWheelEvent e)
{
if (!client.isResized())
{
Dimension stretchedDimensions = client.getStretchedDimensions();
Dimension stretchedDimensions = client.getStretchedDimensions();
Dimension realDimensions = client.getRealDimensions();
int newX = (int) (e.getX() / (stretchedDimensions.width / (double) Constants.GAME_FIXED_WIDTH));
int newY = (int) (e.getY() / (stretchedDimensions.height / (double) Constants.GAME_FIXED_HEIGHT));
int newX = (int) (e.getX() / (stretchedDimensions.width / realDimensions.getWidth()));
int newY = (int) (e.getY() / (stretchedDimensions.height / realDimensions.getHeight()));
return new MouseWheelEvent((Component) e.getSource(), e.getID(), e.getWhen(), e.getModifiers(), newX, newY,
e.getClickCount(), e.isPopupTrigger(), e.getScrollType(), e.getScrollAmount(), e.getWheelRotation());
}
return e;
return new MouseWheelEvent((Component) e.getSource(), e.getID(), e.getWhen(), e.getModifiers(), newX, newY,
e.getClickCount(), e.isPopupTrigger(), e.getScrollType(), e.getScrollAmount(), e.getWheelRotation());
}
}

View File

@@ -68,6 +68,7 @@ import net.runelite.api.WorldType;
import net.runelite.api.coords.LocalPoint;
import net.runelite.api.coords.WorldPoint;
import net.runelite.api.events.BoostedLevelChanged;
import net.runelite.api.events.CanvasSizeChanged;
import net.runelite.api.events.ChatMessage;
import net.runelite.api.events.ClanChanged;
import net.runelite.api.events.DraggingWidgetChanged;
@@ -155,6 +156,9 @@ public abstract class RSClientMixin implements RSClient
@Inject
private static RSItem lastItemDespawn;
@Inject
private static boolean oldIsResized;
@Inject
@Override
public Callbacks getCallbacks()
@@ -968,9 +972,16 @@ public abstract class RSClientMixin implements RSClient
public static void resizeChanged(int idx)
{
//maybe couple with varbitChanged. resizeable may not be a varbit but it would fit with the other client settings.
ResizeableChanged resizeableChanged = new ResizeableChanged();
resizeableChanged.setResized(client.isResized());
client.getCallbacks().post(resizeableChanged);
boolean isResized = client.isResized();
if (oldIsResized != isResized)
{
ResizeableChanged resizeableChanged = new ResizeableChanged();
resizeableChanged.setResized(isResized);
client.getCallbacks().post(resizeableChanged);
oldIsResized = isResized;
}
}
@FieldHook("clanMemberManager")
@@ -980,6 +991,20 @@ public abstract class RSClientMixin implements RSClient
client.getCallbacks().post(new ClanChanged(client.getClanMemberManager() != null));
}
@FieldHook("canvasWidth")
@Inject
public static void canvasWidthChanged(int idx)
{
client.getCallbacks().post(new CanvasSizeChanged());
}
@FieldHook("canvasHeight")
@Inject
public static void canvasHeightChanged(int idx)
{
client.getCallbacks().post(new CanvasSizeChanged());
}
@Inject
@Override
public boolean hasHintArrow()

View File

@@ -67,7 +67,7 @@ public abstract class RSGameCanvasMixin extends Canvas implements RSGameCanvas
@Override
public void setSize(int width, int height)
{
if (!client.isResized() && client.isStretchedEnabled())
if (client.isStretchedEnabled())
{
super.setSize(client.getStretchedDimensions().width, client.getStretchedDimensions().height);
}
@@ -81,7 +81,7 @@ public abstract class RSGameCanvasMixin extends Canvas implements RSGameCanvas
@Override
public void setLocation(int x, int y)
{
if (!client.isResized() && client.isStretchedEnabled())
if (client.isStretchedEnabled())
{
super.setLocation((getParent().getWidth() - client.getStretchedDimensions().width) / 2, 0);
}

View File

@@ -0,0 +1,58 @@
/*
* Copyright (c) 2018, Lotto <https://github.com/devLotto>
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions are met:
*
* 1. Redistributions of source code must retain the above copyright notice, this
* list of conditions and the following disclaimer.
* 2. Redistributions in binary form must reproduce the above copyright notice,
* this list of conditions and the following disclaimer in the documentation
* and/or other materials provided with the distribution.
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
* ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
* WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
* DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR
* ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
* (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
* LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
* ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
* SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/
package net.runelite.mixins;
import java.awt.Dimension;
import net.runelite.api.mixins.Copy;
import net.runelite.api.mixins.Mixin;
import net.runelite.api.mixins.Replace;
import net.runelite.api.mixins.Shadow;
import net.runelite.rs.api.RSClient;
import net.runelite.rs.api.RSGameEngine;
@Mixin(RSGameEngine.class)
public abstract class StretchedModeMaxSizeMixin implements RSGameEngine
{
@Shadow("clientInstance")
private static RSClient client;
@Copy("setMaxCanvasSize")
abstract void rs$setMaxCanvasSize(int width, int height);
@Replace("setMaxCanvasSize")
public void setMaxCanvasSize(int width, int height)
{
if (client.isStretchedEnabled() && client.isResized())
{
Dimension realDimensions = client.getRealDimensions();
rs$setMaxCanvasSize(realDimensions.width, realDimensions.height);
}
else
{
rs$setMaxCanvasSize(width, height);
}
}
}

View File

@@ -24,7 +24,8 @@
*/
package net.runelite.mixins;
import java.awt.Canvas;
import com.google.common.primitives.Ints;
import java.awt.Container;
import java.awt.Dimension;
import net.runelite.api.Constants;
import net.runelite.api.mixins.Inject;
@@ -32,7 +33,7 @@ import net.runelite.api.mixins.Mixin;
import net.runelite.rs.api.RSClient;
@Mixin(RSClient.class)
public abstract class StretchedFixedModeMixin implements RSClient
public abstract class StretchedModeMixin implements RSClient
{
@Inject
private static boolean stretchedEnabled;
@@ -46,11 +47,14 @@ public abstract class StretchedFixedModeMixin implements RSClient
@Inject
private static boolean stretchedKeepAspectRatio;
@Inject
private static double scalingFactor;
@Inject
private static Dimension cachedStretchedDimensions;
@Inject
private static Dimension lastCanvasDimensions;
private static Dimension cachedRealDimensions;
@Inject
@Override
@@ -85,7 +89,6 @@ public abstract class StretchedFixedModeMixin implements RSClient
public void setStretchedIntegerScaling(boolean state)
{
stretchedIntegerScaling = state;
cachedStretchedDimensions = null;
}
@Inject
@@ -93,62 +96,127 @@ public abstract class StretchedFixedModeMixin implements RSClient
public void setStretchedKeepAspectRatio(boolean state)
{
stretchedKeepAspectRatio = state;
cachedStretchedDimensions = null;
}
@Inject
@Override
public void setScalingFactor(int factor)
{
factor = Ints.constrainToRange(factor, 0, 100);
scalingFactor = (100 - factor) / 100D;
}
@Inject
@Override
public Dimension getRealDimensions()
{
if (isStretchedEnabled() && !isResized())
if (!isStretchedEnabled())
{
return Constants.GAME_FIXED_SIZE;
return getCanvas().getSize();
}
return getCanvas().getSize();
if (cachedRealDimensions == null)
{
if (isResized())
{
Container canvasParent = getCanvas().getParent();
int parentWidth = canvasParent.getWidth();
int parentHeight = canvasParent.getHeight();
int widthOffset = parentWidth - Constants.GAME_FIXED_WIDTH;
int heightOffset = parentHeight - Constants.GAME_FIXED_HEIGHT;
int newWidth = Constants.GAME_FIXED_WIDTH + (int) (widthOffset * scalingFactor);
int newHeight = Constants.GAME_FIXED_HEIGHT + (int) (heightOffset * scalingFactor);
cachedRealDimensions = new Dimension(newWidth, newHeight);
}
else
{
cachedRealDimensions = Constants.GAME_FIXED_SIZE;
}
}
return cachedRealDimensions;
}
@Inject
@Override
public Dimension getStretchedDimensions()
{
Canvas canvas = getCanvas();
int width = canvas.getParent().getWidth();
int height = canvas.getParent().getHeight();
if (cachedStretchedDimensions == null || width != lastCanvasDimensions.width || height != lastCanvasDimensions.height)
if (cachedStretchedDimensions == null)
{
Container canvasParent = getCanvas().getParent();
int parentWidth = canvasParent.getWidth();
int parentHeight = canvasParent.getHeight();
Dimension realDimensions = getRealDimensions();
if (stretchedKeepAspectRatio)
{
int tempNewWidth = (int) (height * Constants.GAME_FIXED_ASPECT_RATIO);
double aspectRatio = realDimensions.getWidth() / realDimensions.getHeight();
if (tempNewWidth > canvas.getWidth())
int tempNewWidth = (int) (parentHeight * aspectRatio);
if (tempNewWidth > parentWidth)
{
height = (int) (width / Constants.GAME_FIXED_ASPECT_RATIO);
parentHeight = (int) (parentWidth / aspectRatio);
}
else
{
width = tempNewWidth;
parentWidth = tempNewWidth;
}
}
if (stretchedIntegerScaling)
{
if (width > Constants.GAME_FIXED_WIDTH)
if (parentWidth > realDimensions.width)
{
width = width - (width % Constants.GAME_FIXED_WIDTH);
parentWidth = parentWidth - (parentWidth % realDimensions.width);
}
if (height > Constants.GAME_FIXED_HEIGHT)
if (parentHeight > realDimensions.height)
{
height = height - (height % Constants.GAME_FIXED_HEIGHT);
parentHeight = parentHeight - (parentHeight % realDimensions.height);
}
}
cachedStretchedDimensions = new Dimension(width, height);
lastCanvasDimensions = new Dimension(width, height);
cachedStretchedDimensions = new Dimension(parentWidth, parentHeight);
}
return cachedStretchedDimensions;
}
@Inject
@Override
public void invalidateStretching(boolean resize)
{
cachedStretchedDimensions = null;
cachedRealDimensions = null;
if (resize && isResized())
{
/*
Tells the game to run resizeCanvas the next frame.
resizeCanvas in turn calls the method that
determines the maximum size of the canvas,
AFTER setting the size of the canvas.
The frame after that, the game sees that
the maximum size of the canvas isn't
the current size, so it runs resizeCanvas again.
This time it uses our new maximum size
as the bounds for the canvas size.
This is useful when resizeCanvas wouldn't usually run,
for example when we've only changed the scaling factor
and we still want the game's canvas to resize
with regards to the new maximum bounds.
*/
setResizeCanvasNextFrame(true);
}
}
}

View File

@@ -32,4 +32,7 @@ public interface RSGameEngine extends GameEngine
{
@Import("canvas")
Canvas getCanvas();
@Import("resizeCanvasNextFrame")
void setResizeCanvasNextFrame(boolean state);
}