Compare commits

...

18 Commits

Author SHA1 Message Date
Renovate ad0ebe3fe4 Merge pull request 'Update dependency tools.jackson.dataformat:jackson-dataformat-toml to v3.2.0' (#16) from renovate/all-minor-patch into master
Build and Test / build (push) Successful in 48s
2026-06-09 10:01:05 +02:00
Renovate 22670c2468 Update dependency tools.jackson.dataformat:jackson-dataformat-toml to v3.2.0
Build and Test / build (pull_request) Successful in 47s
2026-06-09 08:00:10 +00:00
Renovate a9abe3c640 Merge pull request 'Update all minor and patch updates to v1.14.2' (#15) from renovate/all-minor-patch into master
Build and Test / build (push) Successful in 45s
2026-06-05 18:01:02 +02:00
Renovate 6416a55904 Update all minor and patch updates to v1.14.2
Build and Test / build (pull_request) Successful in 47s
2026-06-05 16:00:10 +00:00
Renovate 65cfff172d Merge pull request 'Update all minor and patch updates to v12.6-javax' (#14) from renovate/all-minor-patch into master
Build and Test / build (push) Successful in 47s
2026-06-05 10:01:06 +02:00
Renovate 16e171a55e Update all minor and patch updates to v12.6-javax
Build and Test / build (pull_request) Successful in 49s
2026-06-05 08:00:10 +00:00
Renovate eada8b87c3 Merge pull request 'Update actions/checkout digest to df4cb1c' (#13) from renovate/all-minor-patch into master
Build and Test / build (push) Successful in 57s
2026-06-03 18:01:29 +02:00
Renovate 2b6787143a Update actions/checkout digest to df4cb1c
Build and Test / build (pull_request) Successful in 1m15s
2026-06-03 16:00:10 +00:00
Renovate d9794cce22 Merge pull request 'Update dependency tools.jackson.dataformat:jackson-dataformat-toml to v3.1.4' (#12) from renovate/all-minor-patch into master
Build and Test / build (push) Successful in 43s
2026-05-30 02:01:04 +02:00
Renovate 3b8df5824f Update dependency tools.jackson.dataformat:jackson-dataformat-toml to v3.1.4
Build and Test / build (pull_request) Successful in 49s
2026-05-30 00:00:10 +00:00
Renovate 0e6a327c08 Merge pull request 'Update dependency org.junit:junit-bom to v6.1.0' (#11) from renovate/all-minor-patch into master
Build and Test / build (push) Successful in 37s
2026-05-20 02:01:00 +02:00
Renovate 933ff6006f Update dependency org.junit:junit-bom to v6.1.0
Build and Test / build (pull_request) Successful in 44s
2026-05-20 00:00:10 +00:00
Renovate fbcfad2346 Merge pull request 'Update all minor and patch updates to v1.14.1' (#10) from renovate/all-minor-patch into master
Build and Test / build (push) Successful in 36s
2026-05-19 10:14:19 +02:00
Renovate bc24b5dc09 Update all minor and patch updates to v1.14.1
Build and Test / build (pull_request) Successful in 1m39s
2026-05-19 00:00:11 +00:00
seeseemelk 8f9aeb2608 Enhance GraphicsContext: add RGB color setting method, adjust clipping logic, and update Menu to return Window
Build and Test / build (push) Has been cancelled
2026-05-15 21:44:23 +02:00
seeseemelk 95bf1695ef Refactor GraphicsContext: implement translation handling and update drawing methods to use translation values
Build and Test / build (push) Has been cancelled
2026-05-14 23:16:17 +02:00
seeseemelk 280f294b57 Add Bootloader configuration and enhance clipping functionality in GraphicsContext 2026-05-14 22:03:17 +02:00
seeseemelk 412e3adf2a Working on menus 2026-05-14 13:01:57 +02:00
13 changed files with 294 additions and 48 deletions
+1 -1
View File
@@ -11,7 +11,7 @@ jobs:
runs-on: ubuntu-latest runs-on: ubuntu-latest
steps: steps:
- name: Checkout - name: Checkout
uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6 uses: actions/checkout@df4cb1c069e1874edd31b4311f1884172cec0e10 # v6
- name: Set up JDK - name: Set up JDK
uses: actions/setup-java@be666c2fcd27ec809703dec50e508c2fdc7f6654 # v5 uses: actions/setup-java@be666c2fcd27ec809703dec50e508c2fdc7f6654 # v5
+15
View File
@@ -0,0 +1,15 @@
<component name="ProjectRunConfigurationManager">
<configuration default="false" name="Bootloader" type="Application" factoryName="Application" nameIsGenerated="true">
<option name="MAIN_CLASS_NAME" value="be.seeseemelk.diceos.Bootloader" />
<module name="diceos.main" />
<extension name="coverage">
<pattern>
<option name="PATTERN" value="be.seeseemelk.diceos.*" />
<option name="ENABLED" value="true" />
</pattern>
</extension>
<method v="2">
<option name="Make" enabled="true" />
</method>
</configuration>
</component>
+8 -4
View File
@@ -7,10 +7,14 @@ plugins {
group = "be.seeseemelk" group = "be.seeseemelk"
version = "1.0-SNAPSHOT" version = "1.0-SNAPSHOT"
val gdxVersion = "1.14.0" val gdxVersion = "1.14.2"
val slf4j = "2.0.18" val slf4j = "2.0.18"
val lombokVersion = "1.18.46" val lombokVersion = "1.18.46"
val avajeInjectVersion = "12.5" val avajeInjectVersion = "12.6-javax"
application {
mainClass = "be.seeseemelk.diceos.Bootloader"
}
repositories { repositories {
mavenCentral() mavenCentral()
@@ -35,14 +39,14 @@ dependencies {
testAnnotationProcessor("io.avaje:avaje-inject-generator:${avajeInjectVersion}") testAnnotationProcessor("io.avaje:avaje-inject-generator:${avajeInjectVersion}")
// Parsing TOML files // Parsing TOML files
implementation("tools.jackson.dataformat:jackson-dataformat-toml:3.1.3") implementation("tools.jackson.dataformat:jackson-dataformat-toml:3.2.0")
// LibGDX // LibGDX
api("com.badlogicgames.gdx:gdx:$gdxVersion") api("com.badlogicgames.gdx:gdx:$gdxVersion")
api("com.badlogicgames.gdx:gdx-backend-lwjgl3:$gdxVersion") api("com.badlogicgames.gdx:gdx-backend-lwjgl3:$gdxVersion")
api("com.badlogicgames.gdx:gdx-platform:$gdxVersion:natives-desktop") api("com.badlogicgames.gdx:gdx-platform:$gdxVersion:natives-desktop")
testImplementation(platform("org.junit:junit-bom:6.0.3")) testImplementation(platform("org.junit:junit-bom:6.1.0"))
testImplementation("org.junit.jupiter:junit-jupiter") testImplementation("org.junit.jupiter:junit-jupiter")
testRuntimeOnly("org.junit.platform:junit-platform-launcher") testRuntimeOnly("org.junit.platform:junit-platform-launcher")
} }
@@ -10,6 +10,7 @@ public class DiceOS {
private static DiceOS INSTANCE; private static DiceOS INSTANCE;
private final ResourceLoader resourceLoader; private final ResourceLoader resourceLoader;
private final WindowService windowService; private final WindowService windowService;
private final InputService inputService;
@PostConstruct @PostConstruct
void register() { void register() {
@@ -33,4 +34,8 @@ public class DiceOS {
public static WindowService getWindowService() { public static WindowService getWindowService() {
return INSTANCE.windowService; return INSTANCE.windowService;
} }
public static InputService getInputService() {
return INSTANCE.inputService;
}
} }
@@ -5,7 +5,6 @@ import com.badlogic.gdx.ApplicationAdapter;
import com.badlogic.gdx.Gdx; import com.badlogic.gdx.Gdx;
import com.badlogic.gdx.graphics.Color; import com.badlogic.gdx.graphics.Color;
import com.badlogic.gdx.graphics.Texture; import com.badlogic.gdx.graphics.Texture;
import com.badlogic.gdx.graphics.g2d.BitmapFont;
import com.badlogic.gdx.graphics.g2d.TextureRegion; import com.badlogic.gdx.graphics.g2d.TextureRegion;
import com.badlogic.gdx.utils.ScreenUtils; import com.badlogic.gdx.utils.ScreenUtils;
import com.badlogic.gdx.utils.viewport.ScreenViewport; import com.badlogic.gdx.utils.viewport.ScreenViewport;
@@ -24,6 +23,7 @@ public class DiceOSAdapter extends ApplicationAdapter {
private final DisplayService display; private final DisplayService display;
private final CursorService cursorService; private final CursorService cursorService;
private final WindowService windowService; private final WindowService windowService;
private final InputService inputService;
private final List<OnStartup> startupTasks; private final List<OnStartup> startupTasks;
private Texture clouds; private Texture clouds;
private Texture border; private Texture border;
@@ -62,6 +62,8 @@ public class DiceOSAdapter extends ApplicationAdapter {
offsetY = (height - (displayHeight * scaling)) / 2; offsetY = (height - (displayHeight * scaling)) / 2;
cursorService.setScale(scaling); cursorService.setScale(scaling);
inputService.setScale(scaling);
inputService.setOffset(offsetX, offsetY);
gc = new GraphicsContext(screenViewport.getCamera(), display.getBatch(), displayHeight, displayWidth, gc = new GraphicsContext(screenViewport.getCamera(), display.getBatch(), displayHeight, displayWidth,
DiceOS.getResourceLoader().getDefaultFont().getBitmapFont()); DiceOS.getResourceLoader().getDefaultFont().getBitmapFont());
@@ -8,13 +8,14 @@ import io.avaje.inject.Component;
import lombok.RequiredArgsConstructor; import lombok.RequiredArgsConstructor;
import lombok.extern.slf4j.Slf4j; import lombok.extern.slf4j.Slf4j;
import java.awt.event.KeyEvent;
@Slf4j @Slf4j
@Component @Component
@RequiredArgsConstructor @RequiredArgsConstructor
public class InputService implements OnStartup { public class InputService implements OnStartup {
private final DisplayService displayService; private final DisplayService displayService;
private int scale = 1;
private int offsetX = 0;
private int offsetY = 0;
@Override @Override
public void onStartup() { public void onStartup() {
@@ -49,4 +50,36 @@ public class InputService implements OnStartup {
return Gdx.input.isKeyPressed(com.badlogic.gdx.Input.Keys.ALT_LEFT) || return Gdx.input.isKeyPressed(com.badlogic.gdx.Input.Keys.ALT_LEFT) ||
Gdx.input.isKeyPressed(com.badlogic.gdx.Input.Keys.ALT_RIGHT); Gdx.input.isKeyPressed(com.badlogic.gdx.Input.Keys.ALT_RIGHT);
} }
public int getMouseX() {
return (Gdx.input.getX() - offsetX) / scale;
}
public int getMouseY() {
return (Gdx.input.getY() - offsetY) / scale;
}
void setScale(int scale) {
this.scale = scale;
}
void setOffset(int x, int y) {
this.offsetX = x;
this.offsetY = y;
}
/**
* Checks if the mouse is currently within the specified rectangle.
* @param x The x-coordinate of the rectangle.
* @param y The y-coordinate of the rectangle.
* @param width The width of the rectangle.
* @param height The height of the rectangle.
* @return True if the mouse is within the rectangle, false otherwise.
*/
public boolean mouseInBounds(int x, int y, int width, int height) {
int mx = getMouseX();
int my = getMouseY();
return mx >= x && mx < x + width &&
my >= y && my < y + height;
}
} }
@@ -69,10 +69,13 @@ public class WindowService implements OnStartup {
// Render menubar items // Render menubar items
gc.save(); gc.save();
gc.translate(10, 0); gc.translate(8, 0);
for (var submenu : menu.getItems()) { for (var submenu : menu.getItems()) {
gc.save();
gc.clip(0, 0, submenu.getWidth(), submenu.getHeight());
submenu.paint(gc); submenu.paint(gc);
gc.translate(submenu.getWidth() + 4, 0); gc.restore();
gc.translate(submenu.getWidth(), 0);
} }
gc.restore(); gc.restore();
} }
@@ -11,6 +11,8 @@ import com.badlogic.gdx.scenes.scene2d.utils.ScissorStack;
import lombok.Getter; import lombok.Getter;
import lombok.RequiredArgsConstructor; import lombok.RequiredArgsConstructor;
import java.util.Stack;
/** /**
* Graphics context and rendering utilities. * Graphics context and rendering utilities.
*/ */
@@ -23,15 +25,20 @@ public class GraphicsContext {
private final int width; private final int width;
private final BitmapFont font; private final BitmapFont font;
private final java.util.Stack<GraphicsState> stateStack = new java.util.Stack<>(); private final Stack<GraphicsState> stateStack = new java.util.Stack<>();
private int translateX = 0;
private int translateY = 0;
private static class GraphicsState { private static class GraphicsState {
private final com.badlogic.gdx.math.Matrix4 transform; private final int translateX;
private final boolean scissorEnabled; private final int translateY;
private int scissorCount;
public GraphicsState(com.badlogic.gdx.math.Matrix4 transform, boolean scissorEnabled) { public GraphicsState(int translateX, int translateY, int scissorCount) {
this.transform = transform.cpy(); this.translateX = translateX;
this.scissorEnabled = scissorEnabled; this.translateY = translateY;
this.scissorCount = scissorCount;
} }
} }
@@ -44,7 +51,7 @@ public class GraphicsContext {
* @param height The height. * @param height The height.
*/ */
public void draw(NinePatch image, int x, int y, int width, int height) { public void draw(NinePatch image, int x, int y, int width, int height) {
image.draw(batch, x, getHeight() - height - y, width, height); image.draw(batch, x + translateX, getHeight() - height - (y + translateY), width, height);
} }
/** /**
@@ -54,7 +61,7 @@ public class GraphicsContext {
* @param y The y-coordinate. * @param y The y-coordinate.
*/ */
public void draw(Texture texture, int x, int y) { public void draw(Texture texture, int x, int y) {
draw(texture, x, y, Parameters.DEFAULT); draw(texture, x + translateX, y + translateY, Parameters.DEFAULT);
} }
/** /**
@@ -66,7 +73,7 @@ public class GraphicsContext {
*/ */
public void draw(Texture texture, int x, int y, Parameters params) { public void draw(Texture texture, int x, int y, Parameters params) {
batch.draw(texture, batch.draw(texture,
x, getHeight() - y - texture.getHeight(), texture.getWidth(), texture.getHeight(), x + translateX, getHeight() - (y + translateY) - texture.getHeight(), texture.getWidth(), texture.getHeight(),
0, 0, texture.getWidth(), texture.getHeight(), 0, 0, texture.getWidth(), texture.getHeight(),
params.flipX, params.flipY); params.flipX, params.flipY);
} }
@@ -78,7 +85,7 @@ public class GraphicsContext {
* @param y The y coordinate to draw at. * @param y The y coordinate to draw at.
*/ */
public void draw(String text, int x, int y) { public void draw(String text, int x, int y) {
font.draw(batch, text, x, getHeight() - (y + font.getLineHeight())); font.draw(batch, text, x + translateX, getHeight() - (y + translateY + font.getLineHeight()));
} }
/** /**
@@ -90,7 +97,7 @@ public class GraphicsContext {
*/ */
public void fillRect(int x, int y, int width, int height) { public void fillRect(int x, int y, int width, int height) {
var texture = DiceOS.getResourceLoader().loadTexture("system/white.png"); var texture = DiceOS.getResourceLoader().loadTexture("system/white.png");
batch.draw(texture, x, getHeight() - height - y, width, height); // This is not ideal. batch.draw(texture, x + translateX, getHeight() - height - (y + translateY), width, height);
} }
/** /**
@@ -103,6 +110,14 @@ public class GraphicsContext {
batch.setColor(r / 255f, g / 255f, b / 255f, 1f); batch.setColor(r / 255f, g / 255f, b / 255f, 1f);
} }
/**
* Sets the color for subsequent drawing operations using an RGB integer.
* @param rgb The RGB color integer.
*/
public void setColour(int rgb) {
setColour((rgb >> 16) & 0xFF, (rgb >> 8) & 0xFF, rgb & 0xFF);
}
/** /**
* Shifts the context to the right and down by some amount. * Shifts the context to the right and down by some amount.
* Negative values move towards the opposite direction. * Negative values move towards the opposite direction.
@@ -111,7 +126,21 @@ public class GraphicsContext {
* @param y The number of pixels to move down by. * @param y The number of pixels to move down by.
*/ */
public void translate(int x, int y) { public void translate(int x, int y) {
batch.setTransformMatrix(batch.getTransformMatrix().trn(x, -y, 0)); translateX += x;
translateY += y;
}
/**
* Gets the total amount of X-translation applied by this graphics context.
* In other words, a draw command with `x=0` would actually write to this screen coordinate.
* @return The total amount of X-translation.
*/
public int getXTranslation() {
return translateX;
}
public int getYTranslation() {
return translateY;
} }
/** /**
@@ -121,10 +150,32 @@ public class GraphicsContext {
* @param height The height of the clipping area. * @param height The height of the clipping area.
*/ */
public void clip(int width, int height) { public void clip(int width, int height) {
var scissors = new Rectangle(0, 0, width, height); clip(0, 0, width, height);
}
/**
* Sets a clipping rectangle for subsequent draw operations.
*
* @param x The x-coordinate of the clipping area.
* @param y The y-coordinate of the clipping area.
* @param width The width of the clipping area.
* @param height The height of the clipping area.
*/
public void clip(int x, int y, int width, int height) {
var scissors = new Rectangle(x + getXTranslation(), getHeight() - (y + getYTranslation()) - height, width, height);
ScissorStack.calculateScissors(camera, batch.getTransformMatrix(), scissors, scissors); ScissorStack.calculateScissors(camera, batch.getTransformMatrix(), scissors, scissors);
batch.flush(); batch.flush();
ScissorStack.pushScissors(scissors); if (ScissorStack.pushScissors(scissors)) {
getCurrentState().scissorCount++;
}
}
/**
* Returns the current graphics state from the top of the stack.
* @return The current state.
*/
private GraphicsState getCurrentState() {
return stateStack.peek();
} }
/** /**
@@ -132,7 +183,7 @@ public class GraphicsContext {
* The state can later be restored using {@link #restore()}. * The state can later be restored using {@link #restore()}.
*/ */
public void save() { public void save() {
stateStack.push(new GraphicsState(batch.getTransformMatrix(), false)); stateStack.push(new GraphicsState(translateX, translateY, 0));
} }
/** /**
@@ -145,7 +196,11 @@ public class GraphicsContext {
} }
batch.flush(); batch.flush();
GraphicsState state = stateStack.pop(); GraphicsState state = stateStack.pop();
batch.setTransformMatrix(state.transform); translateX = state.translateX;
translateY = state.translateY;
for (int i = 0; i < state.scissorCount; i++) {
ScissorStack.popScissors();
}
} }
/** /**
@@ -3,15 +3,20 @@ package be.seeseemelk.diceos.system.toolkit.menu;
import be.seeseemelk.diceos.system.DiceOS; import be.seeseemelk.diceos.system.DiceOS;
import be.seeseemelk.diceos.system.font.Font; import be.seeseemelk.diceos.system.font.Font;
import be.seeseemelk.diceos.system.gfx.GraphicsContext; import be.seeseemelk.diceos.system.gfx.GraphicsContext;
import be.seeseemelk.diceos.system.toolkit.Window;
import lombok.Getter; import lombok.Getter;
import lombok.RequiredArgsConstructor; import lombok.RequiredArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import java.util.ArrayList; import java.util.ArrayList;
import java.util.List; import java.util.List;
@RequiredArgsConstructor @RequiredArgsConstructor
@Getter @Getter
@Slf4j
public class Menu implements MenuItem { public class Menu implements MenuItem {
private final static int HORIZONTAL_PADDING = 2;
private final String title; private final String title;
private final List<MenuItem> items = new ArrayList<>(); private final List<MenuItem> items = new ArrayList<>();
private final Font font = DiceOS.getResourceLoader().getDefaultFont(); private final Font font = DiceOS.getResourceLoader().getDefaultFont();
@@ -28,12 +33,12 @@ public class Menu implements MenuItem {
@Override @Override
public int getWidth() { public int getWidth() {
return font.getTextWidth(title); return font.getTextWidth(title) + HORIZONTAL_PADDING * 2;
} }
@Override @Override
public int getHeight() { public int getHeight() {
return items.stream().mapToInt(MenuItem::getHeight).sum(); return 13;
} }
/** /**
@@ -41,15 +46,23 @@ public class Menu implements MenuItem {
* *
* @param x The x-coordinate. * @param x The x-coordinate.
* @param y The y-coordinate. * @param y The y-coordinate.
* @return The created MenuPopup. * @return The created Window for the menu.
*/ */
public MenuPopup show(int x, int y) { public Window show(int x, int y) {
return new MenuPopup(this, x, y); return new Window(x, y, getWidth(), getHeight(), Window.Style.NONE);
} }
@Override @Override
public void paint(GraphicsContext gc) { public void paint(GraphicsContext gc) {
if (DiceOS.getInputService().mouseInBounds(gc.getXTranslation(), gc.getYTranslation(), getWidth(), getHeight())) {
log.info("Mouse in bounds");
gc.setColour(0x9f7445);
gc.fillRect(-100, -100, 500, 500);
}
gc.setColour(255, 255, 255);
// Renders the menu as a simple menu button // Renders the menu as a simple menu button
gc.draw(title, 0, 5); gc.draw(title, HORIZONTAL_PADDING, 5);
} }
} }
@@ -1,16 +0,0 @@
package be.seeseemelk.diceos.system.toolkit.menu;
import be.seeseemelk.diceos.system.toolkit.Window;
/**
* A visisble menu popup.
*/
public class MenuPopup {
private final Menu menu;
private final Window window;
public MenuPopup(Menu menu, int x, int y) {
this.menu = menu;
this.window = new Window(x, y, menu.getWidth(), menu.getHeight(), Window.Style.NONE);
}
}
@@ -12,4 +12,18 @@ public class Utils {
public static boolean isPowerOfTwo(int value) { public static boolean isPowerOfTwo(int value) {
return (value & (value - 1)) == 0 && value != 0; return (value & (value - 1)) == 0 && value != 0;
} }
/**
* Determines if the point at (x, y) is inside the bounds of (x1, y1, width, height).
* @param x The x-coordinate of the point.
* @param y The y-coordinate of the point.
* @param x1 The x-coordinate of the bounds.
* @param y1 The y-coordinate of the bounds.
* @param width The width of the bounds.
* @param height The height of the bounds.
* @return True if the point is inside the bounds, false otherwise.
*/
public static boolean isInBounds(int x, int y, int x1, int y1, int width, int height) {
return x >= x1 && x < x1 + width && y >= y1 && y < y1 + height;
}
} }
@@ -0,0 +1,39 @@
package be.seeseemelk.diceos.system;
import com.badlogic.gdx.Gdx;
import com.badlogic.gdx.Input;
import org.junit.jupiter.api.BeforeEach;
import org.junit.jupiter.api.Test;
import org.mockito.Mockito;
import static org.junit.jupiter.api.Assertions.*;
class InputServiceTest {
private DisplayService displayService;
private InputService inputService;
@BeforeEach
void setUp() {
displayService = Mockito.mock(DisplayService.class);
inputService = new InputService(displayService);
Gdx.input = Mockito.mock(Input.class);
}
@Test
void testMouseMethods() {
Mockito.when(Gdx.input.getX()).thenReturn(100);
Mockito.when(Gdx.input.getY()).thenReturn(200);
assertEquals(100, inputService.getMouseX());
assertEquals(200, inputService.getMouseY());
}
@Test
void testMouseInBounds() {
Mockito.when(Gdx.input.getX()).thenReturn(100);
Mockito.when(Gdx.input.getY()).thenReturn(200);
assertTrue(inputService.mouseInBounds(90, 190, 20, 20));
assertFalse(inputService.mouseInBounds(0, 0, 50, 50));
}
}
@@ -0,0 +1,79 @@
package be.seeseemelk.diceos.system.gfx;
import com.badlogic.gdx.graphics.Camera;
import com.badlogic.gdx.graphics.Texture;
import com.badlogic.gdx.graphics.g2d.Batch;
import com.badlogic.gdx.graphics.g2d.BitmapFont;
import com.badlogic.gdx.graphics.g2d.NinePatch;
import com.badlogic.gdx.math.Matrix4;
import org.junit.jupiter.api.BeforeEach;
import org.junit.jupiter.api.Test;
import static org.junit.jupiter.api.Assertions.assertDoesNotThrow;
import static org.junit.jupiter.api.Assertions.assertEquals;
import static org.junit.jupiter.api.Assertions.assertThrows;
import static org.mockito.Mockito.*;
class GraphicsContextTest {
private Camera camera;
private Batch batch;
private BitmapFont font;
private GraphicsContext gc;
@BeforeEach
void setUp() {
camera = mock(Camera.class);
batch = mock(Batch.class);
font = mock(BitmapFont.class);
gc = new GraphicsContext(camera, batch, 600, 800, font);
when(batch.getTransformMatrix()).thenReturn(new Matrix4());
}
@Test
void testDrawNinePatch() {
NinePatch np = mock(NinePatch.class);
gc.draw(np, 10, 20, 100, 200);
verify(np).draw(eq(batch), eq(10f), eq(380f), eq(100f), eq(200f));
}
@Test
void testDrawTexture() {
Texture tex = mock(Texture.class);
when(tex.getHeight()).thenReturn(50);
when(tex.getWidth()).thenReturn(50);
gc.draw(tex, 10, 20);
verify(batch).draw(eq(tex), eq(10f), anyFloat(), anyFloat(), anyFloat(), anyInt(), anyInt(), anyInt(), anyInt(), anyBoolean(), anyBoolean());
}
@Test
void testDrawText() {
gc.draw("test", 10, 20);
verify(font).draw(batch, "test", 10f, 600f - (20f + font.getLineHeight()));
}
@Test
void testSetColour() {
gc.setColour(255, 0, 0);
verify(batch).setColor(1f, 0f, 0f, 1f);
}
@Test
void testSetColourRGB() {
gc.setColour(0xFF00FF);
verify(batch).setColor(1f, 0f, 1f, 1f);
}
@Test
void testTranslate() {
gc.translate(10, 20);
assertEquals(10, gc.getXTranslation());
assertEquals(20, gc.getYTranslation());
}
@Test
void testSaveRestore() {
gc.save();
assertDoesNotThrow(() -> gc.restore());
assertThrows(IllegalStateException.class, () -> gc.restore());
}
}