Compare commits
1 Commits
c80805fc66
...
failed
| Author | SHA1 | Date | |
|---|---|---|---|
| 3ac7b4ad65 |
4
.gitattributes
vendored
4
.gitattributes
vendored
@@ -3,7 +3,7 @@
|
|||||||
#
|
#
|
||||||
# Linux start script should use lf
|
# Linux start script should use lf
|
||||||
/gradlew text eol=lf
|
/gradlew text eol=lf
|
||||||
|
|
||||||
# These are Windows script files and should use crlf
|
# These are Windows script files and should use crlf
|
||||||
*.bat text eol=crlf
|
*.bat text eol=crlf
|
||||||
*.glb filter=lfs diff=lfs merge=lfs -text
|
|
||||||
*.fbx filter=lfs diff=lfs merge=lfs -text
|
|
||||||
|
|||||||
5
.gitignore
vendored
5
.gitignore
vendored
@@ -6,7 +6,4 @@ build
|
|||||||
|
|
||||||
app/bin
|
app/bin
|
||||||
|
|
||||||
.vscode
|
.vscode
|
||||||
|
|
||||||
*.wav
|
|
||||||
imgui.ini
|
|
||||||
@@ -16,10 +16,8 @@ repositories {
|
|||||||
mavenCentral()
|
mavenCentral()
|
||||||
}
|
}
|
||||||
|
|
||||||
def os = "linux";
|
|
||||||
def lwjgl_version = "3.3.6"
|
def lwjgl_version = "3.3.6"
|
||||||
def lwjgl_natives = "natives-$os"
|
def lwjgl_natives = "natives-linux"
|
||||||
def imgui_version = "1.87.0"
|
|
||||||
|
|
||||||
dependencies {
|
dependencies {
|
||||||
// Use JUnit Jupiter for testing.
|
// Use JUnit Jupiter for testing.
|
||||||
@@ -28,17 +26,11 @@ dependencies {
|
|||||||
implementation "org.lwjgl:lwjgl:$lwjgl_version"
|
implementation "org.lwjgl:lwjgl:$lwjgl_version"
|
||||||
implementation "org.lwjgl:lwjgl-opengl:$lwjgl_version"
|
implementation "org.lwjgl:lwjgl-opengl:$lwjgl_version"
|
||||||
implementation "org.lwjgl:lwjgl-glfw:$lwjgl_version"
|
implementation "org.lwjgl:lwjgl-glfw:$lwjgl_version"
|
||||||
implementation "org.lwjgl:lwjgl-assimp:$lwjgl_version"
|
|
||||||
implementation "org.joml:joml:1.10.8"
|
implementation "org.joml:joml:1.10.8"
|
||||||
|
|
||||||
implementation "org.lwjgl:lwjgl::$lwjgl_natives"
|
implementation "org.lwjgl:lwjgl::$lwjgl_natives"
|
||||||
implementation "org.lwjgl:lwjgl-opengl::$lwjgl_natives"
|
implementation "org.lwjgl:lwjgl-opengl::$lwjgl_natives"
|
||||||
implementation "org.lwjgl:lwjgl-glfw::$lwjgl_natives"
|
implementation "org.lwjgl:lwjgl-glfw::$lwjgl_natives"
|
||||||
implementation "org.lwjgl:lwjgl-assimp::$lwjgl_natives"
|
|
||||||
|
|
||||||
implementation "io.github.spair:imgui-java-binding:$imgui_version"
|
|
||||||
implementation "io.github.spair:imgui-java-natives-$os:$imgui_version"
|
|
||||||
implementation "io.github.spair:imgui-java-app:$imgui_version"
|
|
||||||
}
|
}
|
||||||
|
|
||||||
application {
|
application {
|
||||||
@@ -53,10 +45,6 @@ jar {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
run {
|
|
||||||
standardInput = System.in
|
|
||||||
}
|
|
||||||
|
|
||||||
tasks.named('test') {
|
tasks.named('test') {
|
||||||
// Use JUnit Platform for unit tests.
|
// Use JUnit Platform for unit tests.
|
||||||
useJUnitPlatform()
|
useJUnitPlatform()
|
||||||
|
|||||||
@@ -1,17 +1,16 @@
|
|||||||
package chess;
|
package chess;
|
||||||
|
|
||||||
import java.util.Scanner;
|
|
||||||
|
|
||||||
import chess.view.consolerender.Colors;
|
import chess.view.consolerender.Colors;
|
||||||
|
|
||||||
|
import java.util.Scanner;
|
||||||
|
|
||||||
public class App {
|
public class App {
|
||||||
public static void main(String[] args) {
|
public static void main(String[] args) {
|
||||||
System.out.println(Colors.RED + "Credits: Grenier Lilas, Pribylski Simon." + Colors.RESET);
|
System.out.println(Colors.RED + "Credits: Grenier Lilas, Pribylski Simon." + Colors.RESET);
|
||||||
System.out.println("""
|
System.out.println("""
|
||||||
Pick the version to use:
|
Pick the version to use:
|
||||||
1 - Console
|
1 - Console
|
||||||
2 - Window
|
2 - Window.""");
|
||||||
3 - 3D.""");
|
|
||||||
switch (new Scanner(System.in).nextLine()) {
|
switch (new Scanner(System.in).nextLine()) {
|
||||||
case "1", "Console", "console":
|
case "1", "Console", "console":
|
||||||
ConsoleMain.main(args);
|
ConsoleMain.main(args);
|
||||||
@@ -19,9 +18,6 @@ public class App {
|
|||||||
case "2", "Window", "window":
|
case "2", "Window", "window":
|
||||||
SwingMain.main(args);
|
SwingMain.main(args);
|
||||||
break;
|
break;
|
||||||
case "3", "3D", "3d":
|
|
||||||
OpenGLMain.main(args);
|
|
||||||
break;
|
|
||||||
default:
|
default:
|
||||||
System.out.println("Invalid input");
|
System.out.println("Invalid input");
|
||||||
break;
|
break;
|
||||||
|
|||||||
@@ -5,17 +5,26 @@ package chess;
|
|||||||
|
|
||||||
import chess.controller.CommandExecutor;
|
import chess.controller.CommandExecutor;
|
||||||
import chess.controller.commands.NewGameCommand;
|
import chess.controller.commands.NewGameCommand;
|
||||||
|
import chess.model.ChessBoard;
|
||||||
import chess.model.Game;
|
import chess.model.Game;
|
||||||
|
import chess.simulator.PromoteTest;
|
||||||
import chess.view.consolerender.Console;
|
import chess.view.consolerender.Console;
|
||||||
|
|
||||||
public class ConsoleMain {
|
public class ConsoleMain {
|
||||||
public static void main(String[] args) {
|
public static void main(String[] args) {
|
||||||
Game game = new Game();
|
Game game = new Game(new ChessBoard());
|
||||||
CommandExecutor commandExecutor = new CommandExecutor(game);
|
CommandExecutor commandExecutor = new CommandExecutor(game);
|
||||||
|
|
||||||
|
PromoteTest promoteTest = new PromoteTest(commandExecutor);
|
||||||
|
commandExecutor.addListener(promoteTest);
|
||||||
|
|
||||||
Console console = new Console(commandExecutor);
|
Console console = new Console(commandExecutor);
|
||||||
commandExecutor.addListener(console);
|
commandExecutor.addListener(console);
|
||||||
|
|
||||||
|
promoteTest.onComplete.connect(() -> {
|
||||||
|
console.setCaptureInput(true);
|
||||||
|
});
|
||||||
|
|
||||||
commandExecutor.executeCommand(new NewGameCommand());
|
commandExecutor.executeCommand(new NewGameCommand());
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,21 +1,33 @@
|
|||||||
package chess;
|
package chess;
|
||||||
|
|
||||||
|
import chess.ai.DumbAI;
|
||||||
import chess.controller.CommandExecutor;
|
import chess.controller.CommandExecutor;
|
||||||
import chess.controller.commands.NewGameCommand;
|
import chess.controller.commands.NewGameCommand;
|
||||||
|
import chess.controller.event.GameAdaptator;
|
||||||
|
import chess.model.ChessBoard;
|
||||||
|
import chess.model.Color;
|
||||||
import chess.model.Game;
|
import chess.model.Game;
|
||||||
import chess.view.DDDrender.DDDView;
|
import chess.pgn.PgnExport;
|
||||||
|
import chess.view.render.Window;
|
||||||
|
|
||||||
public class OpenGLMain {
|
public class OpenGLMain {
|
||||||
public static void main(String[] args) {
|
|
||||||
Game game = new Game();
|
public static void main(String[] args) {
|
||||||
|
Game game = new Game(new ChessBoard());
|
||||||
CommandExecutor commandExecutor = new CommandExecutor(game);
|
CommandExecutor commandExecutor = new CommandExecutor(game);
|
||||||
|
|
||||||
DDDView ddd = new DDDView(commandExecutor);
|
Window window = new Window(commandExecutor);
|
||||||
commandExecutor.addListener(ddd);
|
commandExecutor.addListener(window);
|
||||||
|
|
||||||
|
// DumbAI ai = new DumbAI(commandExecutor, Color.Black);
|
||||||
|
// commandExecutor.addListener(ai);
|
||||||
|
|
||||||
|
// DumbAI ai2 = new DumbAI(commandExecutor, Color.White);
|
||||||
|
// commandExecutor.addListener(ai2);
|
||||||
|
|
||||||
commandExecutor.executeCommand(new NewGameCommand());
|
commandExecutor.executeCommand(new NewGameCommand());
|
||||||
|
|
||||||
ddd.run();
|
window.run();
|
||||||
commandExecutor.close();
|
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,10 +1,10 @@
|
|||||||
package chess;
|
package chess;
|
||||||
|
|
||||||
import chess.ai.DumbAI;
|
import chess.ai.DumbAI;
|
||||||
import chess.ai.HungryAI;
|
|
||||||
import chess.controller.CommandExecutor;
|
import chess.controller.CommandExecutor;
|
||||||
import chess.controller.commands.NewGameCommand;
|
import chess.controller.commands.NewGameCommand;
|
||||||
import chess.controller.event.GameAdaptator;
|
import chess.controller.event.GameAdaptator;
|
||||||
|
import chess.model.ChessBoard;
|
||||||
import chess.model.Color;
|
import chess.model.Color;
|
||||||
import chess.model.Game;
|
import chess.model.Game;
|
||||||
import chess.pgn.PgnExport;
|
import chess.pgn.PgnExport;
|
||||||
@@ -12,7 +12,7 @@ import chess.view.simplerender.Window;
|
|||||||
|
|
||||||
public class SwingMain {
|
public class SwingMain {
|
||||||
public static void main(String[] args) {
|
public static void main(String[] args) {
|
||||||
Game game = new Game();
|
Game game = new Game(new ChessBoard());
|
||||||
CommandExecutor commandExecutor = new CommandExecutor(game);
|
CommandExecutor commandExecutor = new CommandExecutor(game);
|
||||||
|
|
||||||
Window window = new Window(commandExecutor, false);
|
Window window = new Window(commandExecutor, false);
|
||||||
@@ -21,7 +21,7 @@ public class SwingMain {
|
|||||||
DumbAI ai = new DumbAI(commandExecutor, Color.Black);
|
DumbAI ai = new DumbAI(commandExecutor, Color.Black);
|
||||||
commandExecutor.addListener(ai);
|
commandExecutor.addListener(ai);
|
||||||
|
|
||||||
HungryAI ai2 = new HungryAI(commandExecutor, Color.White);
|
DumbAI ai2 = new DumbAI(commandExecutor, Color.White);
|
||||||
commandExecutor.addListener(ai2);
|
commandExecutor.addListener(ai2);
|
||||||
|
|
||||||
commandExecutor.addListener(new GameAdaptator(){
|
commandExecutor.addListener(new GameAdaptator(){
|
||||||
|
|||||||
@@ -1,68 +0,0 @@
|
|||||||
package chess.ai;
|
|
||||||
|
|
||||||
import java.util.List;
|
|
||||||
|
|
||||||
import chess.controller.Command;
|
|
||||||
import chess.controller.CommandExecutor;
|
|
||||||
import chess.controller.commands.GetPieceAtCommand;
|
|
||||||
import chess.controller.commands.GetPlayerMovesCommand;
|
|
||||||
import chess.controller.commands.GetAllowedCastlingsCommand;
|
|
||||||
import chess.controller.commands.GetAllowedCastlingsCommand.CastlingResult;
|
|
||||||
import chess.controller.event.GameAdaptator;
|
|
||||||
import chess.model.Color;
|
|
||||||
import chess.model.Coordinate;
|
|
||||||
import chess.model.Move;
|
|
||||||
import chess.model.Piece;
|
|
||||||
|
|
||||||
public abstract class AI extends GameAdaptator{
|
|
||||||
|
|
||||||
protected final CommandExecutor commandExecutor;
|
|
||||||
protected final Color color;
|
|
||||||
|
|
||||||
public AI(CommandExecutor commandExecutor, Color color) {
|
|
||||||
this.commandExecutor = commandExecutor;
|
|
||||||
this.color = color;
|
|
||||||
}
|
|
||||||
|
|
||||||
protected abstract void play();
|
|
||||||
protected abstract void promote(Coordinate pawnCoords);
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public void onPlayerTurn(Color color, boolean undone) {
|
|
||||||
if (this.color != color || undone)
|
|
||||||
return;
|
|
||||||
|
|
||||||
play();
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public void onPromotePawn(Coordinate pieceCoords) {
|
|
||||||
Piece pawn = pieceAt(pieceCoords);
|
|
||||||
if (pawn.getColor() != this.color)
|
|
||||||
return;
|
|
||||||
promote(pieceCoords);
|
|
||||||
}
|
|
||||||
|
|
||||||
protected Piece pieceAt(Coordinate coordinate) {
|
|
||||||
GetPieceAtCommand command = new GetPieceAtCommand(coordinate);
|
|
||||||
sendCommand(command);
|
|
||||||
return command.getPiece();
|
|
||||||
}
|
|
||||||
|
|
||||||
protected List<Move> getAllowedMoves() {
|
|
||||||
GetPlayerMovesCommand cmd = new GetPlayerMovesCommand();
|
|
||||||
sendCommand(cmd);
|
|
||||||
return cmd.getMoves();
|
|
||||||
}
|
|
||||||
|
|
||||||
protected CastlingResult getAllowedCastlings() {
|
|
||||||
GetAllowedCastlingsCommand cmd2 = new GetAllowedCastlingsCommand();
|
|
||||||
sendCommand(cmd2);
|
|
||||||
return cmd2.getCastlingResult();
|
|
||||||
}
|
|
||||||
|
|
||||||
protected void sendCommand(Command command) {
|
|
||||||
this.commandExecutor.executeCommand(command);
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
|
||||||
@@ -3,28 +3,46 @@ package chess.ai;
|
|||||||
import java.util.List;
|
import java.util.List;
|
||||||
import java.util.Random;
|
import java.util.Random;
|
||||||
|
|
||||||
|
import chess.controller.Command;
|
||||||
import chess.controller.CommandExecutor;
|
import chess.controller.CommandExecutor;
|
||||||
import chess.controller.commands.CastlingCommand;
|
import chess.controller.commands.CastlingCommand;
|
||||||
import chess.controller.commands.GetAllowedCastlingsCommand.CastlingResult;
|
import chess.controller.commands.GetAllowedCastlingsCommand;
|
||||||
|
import chess.controller.commands.GetPieceAtCommand;
|
||||||
|
import chess.controller.commands.GetPlayerMovesCommand;
|
||||||
import chess.controller.commands.MoveCommand;
|
import chess.controller.commands.MoveCommand;
|
||||||
import chess.controller.commands.PromoteCommand;
|
import chess.controller.commands.PromoteCommand;
|
||||||
|
import chess.controller.commands.GetAllowedCastlingsCommand.CastlingResult;
|
||||||
import chess.controller.commands.PromoteCommand.PromoteType;
|
import chess.controller.commands.PromoteCommand.PromoteType;
|
||||||
|
import chess.controller.event.GameAdaptator;
|
||||||
import chess.model.Color;
|
import chess.model.Color;
|
||||||
import chess.model.Coordinate;
|
import chess.model.Coordinate;
|
||||||
import chess.model.Move;
|
import chess.model.Move;
|
||||||
|
import chess.model.Piece;
|
||||||
|
|
||||||
public class DumbAI extends AI {
|
public class DumbAI extends GameAdaptator {
|
||||||
|
|
||||||
|
private final Color player;
|
||||||
|
private final CommandExecutor commandExecutor;
|
||||||
private final Random random = new Random();
|
private final Random random = new Random();
|
||||||
|
|
||||||
public DumbAI(CommandExecutor commandExecutor, Color color) {
|
public DumbAI(CommandExecutor commandExecutor, Color color) {
|
||||||
super(commandExecutor, color);
|
this.player = color;
|
||||||
|
this.commandExecutor = commandExecutor;
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
protected void play() {
|
public void onPlayerTurn(Color color) {
|
||||||
CastlingResult castlings = getAllowedCastlings();
|
if (color != player)
|
||||||
List<Move> moves = getAllowedMoves();
|
return;
|
||||||
|
|
||||||
|
GetPlayerMovesCommand cmd = new GetPlayerMovesCommand();
|
||||||
|
sendCommand(cmd);
|
||||||
|
|
||||||
|
GetAllowedCastlingsCommand cmd2 = new GetAllowedCastlingsCommand();
|
||||||
|
sendCommand(cmd2);
|
||||||
|
|
||||||
|
CastlingResult castlings = cmd2.getCastlingResult();
|
||||||
|
List<Move> moves = cmd.getMoves();
|
||||||
|
|
||||||
switch (castlings) {
|
switch (castlings) {
|
||||||
case Both: {
|
case Both: {
|
||||||
@@ -35,12 +53,20 @@ public class DumbAI extends AI {
|
|||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
case Small:
|
case Small: {
|
||||||
|
int randomMove = this.random.nextInt(moves.size() + 1);
|
||||||
|
if (randomMove != moves.size())
|
||||||
|
break;
|
||||||
|
this.commandExecutor.executeCommand(new CastlingCommand(false));
|
||||||
|
return;
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
case Big: {
|
case Big: {
|
||||||
int randomMove = this.random.nextInt(moves.size() + 1);
|
int randomMove = this.random.nextInt(moves.size() + 1);
|
||||||
if (randomMove != moves.size())
|
if (randomMove != moves.size())
|
||||||
break;
|
break;
|
||||||
this.commandExecutor.executeCommand(new CastlingCommand(castlings == CastlingResult.Big));
|
this.commandExecutor.executeCommand(new CastlingCommand(true));
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -50,12 +76,27 @@ public class DumbAI extends AI {
|
|||||||
|
|
||||||
int randomMove = this.random.nextInt(moves.size());
|
int randomMove = this.random.nextInt(moves.size());
|
||||||
this.commandExecutor.executeCommand(new MoveCommand(moves.get(randomMove)));
|
this.commandExecutor.executeCommand(new MoveCommand(moves.get(randomMove)));
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
protected void promote(Coordinate pawnCoords) {
|
public void onPromotePawn(Coordinate pieceCoords) {
|
||||||
|
Piece pawn = pieceAt(pieceCoords);
|
||||||
|
if (pawn.getColor() != this.player)
|
||||||
|
return;
|
||||||
|
|
||||||
int promote = this.random.nextInt(PromoteType.values().length);
|
int promote = this.random.nextInt(PromoteType.values().length);
|
||||||
this.commandExecutor.executeCommand(new PromoteCommand(PromoteType.values()[promote]));
|
this.commandExecutor.executeCommand(new PromoteCommand(PromoteType.values()[promote]));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private Piece pieceAt(Coordinate coordinate) {
|
||||||
|
GetPieceAtCommand command = new GetPieceAtCommand(coordinate);
|
||||||
|
sendCommand(command);
|
||||||
|
return command.getPiece();
|
||||||
|
}
|
||||||
|
|
||||||
|
private void sendCommand(Command command) {
|
||||||
|
this.commandExecutor.executeCommand(command);
|
||||||
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,61 +0,0 @@
|
|||||||
package chess.ai;
|
|
||||||
|
|
||||||
import java.util.ArrayList;
|
|
||||||
import java.util.List;
|
|
||||||
import java.util.Random;
|
|
||||||
|
|
||||||
import chess.controller.CommandExecutor;
|
|
||||||
import chess.controller.commands.MoveCommand;
|
|
||||||
import chess.controller.commands.PromoteCommand;
|
|
||||||
import chess.controller.commands.PromoteCommand.PromoteType;
|
|
||||||
import chess.model.Color;
|
|
||||||
import chess.model.Coordinate;
|
|
||||||
import chess.model.Move;
|
|
||||||
import chess.model.Piece;
|
|
||||||
|
|
||||||
public class HungryAI extends AI {
|
|
||||||
|
|
||||||
private final PieceCost pieceCost;
|
|
||||||
private final Random random;
|
|
||||||
|
|
||||||
public HungryAI(CommandExecutor commandExecutor, Color color) {
|
|
||||||
super(commandExecutor, color);
|
|
||||||
this.pieceCost = new PieceCost(color);
|
|
||||||
this.random = new Random();
|
|
||||||
}
|
|
||||||
|
|
||||||
private int getMoveCost(Move move) {
|
|
||||||
Piece piece = pieceAt(move.getDeadPieceCoords());
|
|
||||||
return pieceCost.getCost(piece);
|
|
||||||
}
|
|
||||||
|
|
||||||
private List<Move> getBestMoves() {
|
|
||||||
List<Move> moves = getAllowedMoves();
|
|
||||||
List<Move> bestMoves = new ArrayList<>();
|
|
||||||
int bestCost = 0;
|
|
||||||
for (Move move : moves) {
|
|
||||||
int moveCost = getMoveCost(move);
|
|
||||||
if (moveCost == bestCost) {
|
|
||||||
bestMoves.add(move);
|
|
||||||
} else if (moveCost > bestCost) {
|
|
||||||
bestMoves.clear();
|
|
||||||
bestMoves.add(move);
|
|
||||||
bestCost = moveCost;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return bestMoves;
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
protected void play() {
|
|
||||||
List<Move> bestMoves = getBestMoves();
|
|
||||||
int randomMove = this.random.nextInt(bestMoves.size());
|
|
||||||
this.commandExecutor.executeCommand(new MoveCommand(bestMoves.get(randomMove)));
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
protected void promote(Coordinate pawnCoords) {
|
|
||||||
sendCommand(new PromoteCommand(PromoteType.Queen));
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
|
||||||
@@ -1,60 +0,0 @@
|
|||||||
package chess.ai;
|
|
||||||
|
|
||||||
import chess.model.Color;
|
|
||||||
import chess.model.Piece;
|
|
||||||
import chess.model.PieceVisitor;
|
|
||||||
import chess.model.pieces.Bishop;
|
|
||||||
import chess.model.pieces.King;
|
|
||||||
import chess.model.pieces.Knight;
|
|
||||||
import chess.model.pieces.Pawn;
|
|
||||||
import chess.model.pieces.Queen;
|
|
||||||
import chess.model.pieces.Rook;
|
|
||||||
|
|
||||||
public class PieceCost implements PieceVisitor<Integer> {
|
|
||||||
|
|
||||||
private final Color player;
|
|
||||||
|
|
||||||
public PieceCost(Color color) {
|
|
||||||
this.player = color;
|
|
||||||
}
|
|
||||||
|
|
||||||
public int getCost(Piece piece) {
|
|
||||||
if (piece == null)
|
|
||||||
return 0;
|
|
||||||
int cost = visit(piece);
|
|
||||||
if (piece.getColor() == player)
|
|
||||||
cost = -cost;
|
|
||||||
return cost;
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public Integer visitPiece(Bishop bishop) {
|
|
||||||
return 3;
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public Integer visitPiece(King king) {
|
|
||||||
return 90;
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public Integer visitPiece(Knight knight) {
|
|
||||||
return 3;
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public Integer visitPiece(Pawn pawn) {
|
|
||||||
return 1;
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public Integer visitPiece(Queen queen) {
|
|
||||||
return 9;
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public Integer visitPiece(Rook rook) {
|
|
||||||
return 5;
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
|
||||||
@@ -7,14 +7,14 @@ public abstract class Command {
|
|||||||
|
|
||||||
public enum CommandResult {
|
public enum CommandResult {
|
||||||
/**
|
/**
|
||||||
* The command was successful. Should update display and switch player turn.
|
* The command was successfull. Should update display and switch player turn.
|
||||||
*/
|
*/
|
||||||
Moved,
|
Moved,
|
||||||
/** The command was successful. Should not update anything */
|
/** The command was successfull. Should not update anything */
|
||||||
NotMoved,
|
NotMoved,
|
||||||
/** The command was successful. Should only update display */
|
/** The command was successfull. Should only update display */
|
||||||
ActionNeeded,
|
ActionNeeded,
|
||||||
/** The command was not successful */
|
/** The command was not successfull */
|
||||||
NotAllowed;
|
NotAllowed;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -57,14 +57,14 @@ public class CommandExecutor {
|
|||||||
this.dispatcher.onGameEnd();
|
this.dispatcher.onGameEnd();
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
switchPlayerTurn(command instanceof UndoCommand);
|
switchPlayerTurn();
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private void switchPlayerTurn(boolean undone) {
|
private void switchPlayerTurn() {
|
||||||
this.game.switchPlayerTurn();
|
this.game.switchPlayerTurn();
|
||||||
this.dispatcher.onPlayerTurn(this.game.getPlayerTurn(), undone);
|
this.dispatcher.onPlayerTurn(this.game.getPlayerTurn());
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
|||||||
@@ -38,8 +38,4 @@ public class GetAllowedMovesPieceCommand extends Command {
|
|||||||
public List<Coordinate> getDestinations() {
|
public List<Coordinate> getDestinations() {
|
||||||
return destinations;
|
return destinations;
|
||||||
}
|
}
|
||||||
|
|
||||||
public String toString(){
|
|
||||||
return "From position " + start + " to " + destinations;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -51,7 +51,7 @@ public class NewGameCommand extends Command {
|
|||||||
game.reset();
|
game.reset();
|
||||||
|
|
||||||
outputSystem.onGameStart();
|
outputSystem.onGameStart();
|
||||||
outputSystem.onPlayerTurn(game.getPlayerTurn(), false);
|
outputSystem.onPlayerTurn(game.getPlayerTurn());
|
||||||
|
|
||||||
return CommandResult.NotMoved;
|
return CommandResult.NotMoved;
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -43,7 +43,7 @@ public class EmptyGameDispatcher extends GameDispatcher {
|
|||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void onPlayerTurn(Color color, boolean undone) {
|
public void onPlayerTurn(Color color) {
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
|
|||||||
@@ -7,7 +7,7 @@ import chess.model.Move;
|
|||||||
public abstract class GameAdaptator implements GameListener {
|
public abstract class GameAdaptator implements GameListener {
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void onPlayerTurn(Color color, boolean undone) {}
|
public void onPlayerTurn(Color color) {}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void onWin(Color color) {}
|
public void onWin(Color color) {}
|
||||||
|
|||||||
@@ -29,8 +29,8 @@ public class GameDispatcher implements GameListener {
|
|||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void onPlayerTurn(Color color, boolean undone) {
|
public void onPlayerTurn(Color color) {
|
||||||
asyncForEachCall((l) -> l.onPlayerTurn(color, undone));
|
asyncForEachCall((l) -> l.onPlayerTurn(color));
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
|
|||||||
@@ -56,9 +56,8 @@ public interface GameListener {
|
|||||||
/**
|
/**
|
||||||
* Invoked when it's the player turn
|
* Invoked when it's the player turn
|
||||||
* @param color the color of the player who should play
|
* @param color the color of the player who should play
|
||||||
* @param undone true if it's a result of an undo command
|
|
||||||
*/
|
*/
|
||||||
void onPlayerTurn(Color color, boolean undone);
|
void onPlayerTurn(Color color);
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Invoked when a pawn should be promoted
|
* Invoked when a pawn should be promoted
|
||||||
|
|||||||
@@ -20,8 +20,8 @@ public class Game {
|
|||||||
Draw, Check, CheckMate, OnGoing, Pat;
|
Draw, Check, CheckMate, OnGoing, Pat;
|
||||||
}
|
}
|
||||||
|
|
||||||
public Game() {
|
public Game(ChessBoard board) {
|
||||||
this.board = new ChessBoard();
|
this.board = board;
|
||||||
this.movesHistory = new Stack<>();
|
this.movesHistory = new Stack<>();
|
||||||
this.traitsPos = new HashMap<>();
|
this.traitsPos = new HashMap<>();
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -60,8 +60,4 @@ public class Move {
|
|||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
public String toString(){
|
|
||||||
return "Moved from " + getStart() + " to " + getFinish();
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -11,6 +11,7 @@ import chess.controller.commands.MoveCommand;
|
|||||||
import chess.controller.commands.NewGameCommand;
|
import chess.controller.commands.NewGameCommand;
|
||||||
import chess.controller.commands.PromoteCommand;
|
import chess.controller.commands.PromoteCommand;
|
||||||
import chess.controller.event.EmptyGameDispatcher;
|
import chess.controller.event.EmptyGameDispatcher;
|
||||||
|
import chess.model.ChessBoard;
|
||||||
import chess.model.Color;
|
import chess.model.Color;
|
||||||
import chess.model.Coordinate;
|
import chess.model.Coordinate;
|
||||||
import chess.model.Game;
|
import chess.model.Game;
|
||||||
@@ -21,7 +22,7 @@ import chess.model.pieces.Pawn;
|
|||||||
public class PgnExport {
|
public class PgnExport {
|
||||||
|
|
||||||
// public static void main(String[] args) {
|
// public static void main(String[] args) {
|
||||||
// final Game game = new Game();
|
// final Game game = new Game(new ChessBoard());
|
||||||
// final CommandExecutor commandExecutor = new CommandExecutor(game);
|
// final CommandExecutor commandExecutor = new CommandExecutor(game);
|
||||||
|
|
||||||
// DumbAI ai1 = new DumbAI(commandExecutor, Color.White);
|
// DumbAI ai1 = new DumbAI(commandExecutor, Color.White);
|
||||||
@@ -189,7 +190,8 @@ public class PgnExport {
|
|||||||
|
|
||||||
public static String exportGame(Game game) {
|
public static String exportGame(Game game) {
|
||||||
|
|
||||||
Game virtualGame = new Game();
|
ChessBoard board = new ChessBoard();
|
||||||
|
Game virtualGame = new Game(board);
|
||||||
|
|
||||||
CommandExecutor executor = new CommandExecutor(virtualGame, new EmptyGameDispatcher());
|
CommandExecutor executor = new CommandExecutor(virtualGame, new EmptyGameDispatcher());
|
||||||
executor.executeCommand(new NewGameCommand());
|
executor.executeCommand(new NewGameCommand());
|
||||||
|
|||||||
@@ -1,29 +0,0 @@
|
|||||||
package chess.simulator;
|
|
||||||
|
|
||||||
import chess.controller.CommandExecutor;
|
|
||||||
import chess.model.Coordinate;
|
|
||||||
import chess.model.Move;
|
|
||||||
|
|
||||||
import java.util.Arrays;
|
|
||||||
import java.util.List;
|
|
||||||
|
|
||||||
public class EnPassantTest extends Simulator{
|
|
||||||
|
|
||||||
public EnPassantTest(CommandExecutor commandExecutor) {
|
|
||||||
super(commandExecutor);
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
@Override
|
|
||||||
protected List<Move> getMoves() {
|
|
||||||
return Arrays.asList(
|
|
||||||
// white pawn
|
|
||||||
new Move(new Coordinate(4, 6), new Coordinate(4, 4)),
|
|
||||||
// black pawn 1
|
|
||||||
new Move(new Coordinate(4, 1), new Coordinate(4, 2)),
|
|
||||||
// white pawn
|
|
||||||
new Move(new Coordinate(4, 4), new Coordinate(4, 3)),
|
|
||||||
// black pawn #2
|
|
||||||
new Move(new Coordinate(3, 1), new Coordinate(3, 3)));
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -1,102 +0,0 @@
|
|||||||
package chess.view.DDDrender;
|
|
||||||
|
|
||||||
import org.joml.Matrix4f;
|
|
||||||
import org.joml.Vector2f;
|
|
||||||
import org.joml.Vector3f;
|
|
||||||
import org.joml.Vector4f;
|
|
||||||
|
|
||||||
public class Camera {
|
|
||||||
public static final float fov = 70.0f;
|
|
||||||
public static final float zNear = 0.01f;
|
|
||||||
public static final float zFar = 1000.0f;
|
|
||||||
|
|
||||||
private static final Vector3f up = new Vector3f(0.0f, -1.0f, 0.0f);
|
|
||||||
private static final Vector3f center = new Vector3f(0.0f, 0.0f, 0.0f);
|
|
||||||
|
|
||||||
private final float distance = 1.5f;
|
|
||||||
private final float camHeight = 1.5f;
|
|
||||||
|
|
||||||
private float aspectRatio;
|
|
||||||
private float angle;
|
|
||||||
|
|
||||||
private Vector3f pos;
|
|
||||||
|
|
||||||
public Camera() {
|
|
||||||
this.pos = new Vector3f(0.0f, camHeight, 0.0f);
|
|
||||||
setRotateAngle(0.0f);
|
|
||||||
}
|
|
||||||
|
|
||||||
public void move(float x, float y) {
|
|
||||||
this.pos.x += x;
|
|
||||||
this.pos.y += y;
|
|
||||||
}
|
|
||||||
|
|
||||||
public void setRotateAngle(float angle) {
|
|
||||||
this.angle = angle;
|
|
||||||
updatePostion();
|
|
||||||
}
|
|
||||||
|
|
||||||
private void updatePostion() {
|
|
||||||
final float finalX = (float) Math.sin(angle);
|
|
||||||
final float finalZ = (float) -Math.cos(angle);
|
|
||||||
this.pos.set(distance * finalX, this.pos.get(1), distance * finalZ);
|
|
||||||
}
|
|
||||||
|
|
||||||
public float getRotateAngle() {
|
|
||||||
return angle;
|
|
||||||
}
|
|
||||||
|
|
||||||
public Vector3f getPos() {
|
|
||||||
return pos;
|
|
||||||
}
|
|
||||||
|
|
||||||
public float getFov() {
|
|
||||||
return fov;
|
|
||||||
}
|
|
||||||
|
|
||||||
public void setX(float x) {
|
|
||||||
this.pos.x = x;
|
|
||||||
}
|
|
||||||
|
|
||||||
public void setY(float y) {
|
|
||||||
this.pos.y = y;
|
|
||||||
}
|
|
||||||
|
|
||||||
public void setZ(float z) {
|
|
||||||
this.pos.z = z;
|
|
||||||
}
|
|
||||||
|
|
||||||
public void setPosition(Vector3f pos) {
|
|
||||||
this.pos = pos;
|
|
||||||
}
|
|
||||||
|
|
||||||
public void setAspectRatio(float aspectRatio) {
|
|
||||||
this.aspectRatio = aspectRatio;
|
|
||||||
}
|
|
||||||
|
|
||||||
public Matrix4f getPerspectiveMatrix() {
|
|
||||||
return new Matrix4f().perspective((float) (Math.toRadians(fov)), aspectRatio, zNear, zFar);
|
|
||||||
}
|
|
||||||
|
|
||||||
public Matrix4f getViewMatrix() {
|
|
||||||
return new Matrix4f().lookAt(pos, center, up);
|
|
||||||
}
|
|
||||||
|
|
||||||
public Vector2f getCursorWorldFloorPos(Vector2f screenPos, int windowWidth, int windowHeight) {
|
|
||||||
float relativeX = (screenPos.x / (float) windowWidth * 2.0f) - 1.0f;
|
|
||||||
float relativeY = 1.0f - (screenPos.y / (float) windowHeight * 2.0f);
|
|
||||||
|
|
||||||
Vector4f rayClip = new Vector4f(relativeX, relativeY, -1.0f, 1.0f);
|
|
||||||
|
|
||||||
Vector4f rayEye = getPerspectiveMatrix().invert().transform(rayClip);
|
|
||||||
|
|
||||||
rayEye = new Vector4f(rayEye.x, rayEye.y, -1.0f, 0.0f);
|
|
||||||
|
|
||||||
Vector4f rayWorld = getViewMatrix().invert().transform(rayEye);
|
|
||||||
|
|
||||||
float lambda = -this.pos.y / rayWorld.y;
|
|
||||||
|
|
||||||
return new Vector2f(lambda * rayWorld.x + this.pos.x, lambda *
|
|
||||||
rayWorld.z + this.pos.z);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -1,27 +0,0 @@
|
|||||||
package chess.view.DDDrender;
|
|
||||||
|
|
||||||
import java.io.Closeable;
|
|
||||||
import java.io.IOException;
|
|
||||||
import java.util.List;
|
|
||||||
|
|
||||||
import chess.view.DDDrender.opengl.VertexArray;
|
|
||||||
|
|
||||||
public class DDDModel implements Closeable {
|
|
||||||
private final List<VertexArray> vaos;
|
|
||||||
|
|
||||||
public DDDModel(List<VertexArray> vaos) {
|
|
||||||
this.vaos = vaos;
|
|
||||||
}
|
|
||||||
|
|
||||||
public List<VertexArray> getVaos() {
|
|
||||||
return vaos;
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public void close() throws IOException {
|
|
||||||
for (VertexArray vertexArray : vaos) {
|
|
||||||
vertexArray.close();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
|
||||||
@@ -1,21 +0,0 @@
|
|||||||
package chess.view.DDDrender;
|
|
||||||
|
|
||||||
import org.joml.Vector2f;
|
|
||||||
|
|
||||||
import chess.model.Coordinate;
|
|
||||||
|
|
||||||
class DDDPlacement {
|
|
||||||
public static Vector2f coordinatesToVector(Coordinate coo) {
|
|
||||||
return coordinatesToVector(coo.getX(), coo.getY());
|
|
||||||
}
|
|
||||||
|
|
||||||
public static Vector2f coordinatesToVector(float x, float y) {
|
|
||||||
return new Vector2f(1.0f - 0.125f - x * 0.250f, 1.0f - 0.125f - y * 0.250f);
|
|
||||||
}
|
|
||||||
|
|
||||||
public static Coordinate vectorToCoordinates(Vector2f pos) {
|
|
||||||
int x = (int) ((1.0f - pos.x) * 4.0f);
|
|
||||||
int y = (int) ((1.0f - pos.y) * 4.0f);
|
|
||||||
return new Coordinate(x, y);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -1,420 +0,0 @@
|
|||||||
package chess.view.DDDrender;
|
|
||||||
|
|
||||||
import java.io.IOException;
|
|
||||||
import java.util.List;
|
|
||||||
import java.util.function.Consumer;
|
|
||||||
import java.util.function.Function;
|
|
||||||
|
|
||||||
import chess.controller.commands.*;
|
|
||||||
import chess.controller.event.GameListener;
|
|
||||||
import imgui.ImGui;
|
|
||||||
import imgui.type.ImBoolean;
|
|
||||||
import org.joml.Vector2f;
|
|
||||||
import org.joml.Vector3f;
|
|
||||||
|
|
||||||
import chess.controller.Command;
|
|
||||||
import chess.controller.Command.CommandResult;
|
|
||||||
import chess.controller.CommandExecutor;
|
|
||||||
import chess.controller.event.GameAdaptator;
|
|
||||||
import chess.model.Color;
|
|
||||||
import chess.model.Coordinate;
|
|
||||||
import chess.model.Move;
|
|
||||||
import chess.model.Piece;
|
|
||||||
import chess.view.DDDrender.world.BoardEntity;
|
|
||||||
import chess.view.DDDrender.world.PieceEntity;
|
|
||||||
import chess.view.DDDrender.world.World;
|
|
||||||
|
|
||||||
public class DDDView extends GameAdaptator {
|
|
||||||
|
|
||||||
private static final Vector3f BLACK = new Vector3f(0.3f, 0.3f, 0.3f);
|
|
||||||
private static final Vector3f WHITE = new Vector3f(1.0f, 1.0f, 1.0f);
|
|
||||||
|
|
||||||
private final CommandExecutor commandExecutor;
|
|
||||||
private final Window window;
|
|
||||||
private final World world;
|
|
||||||
private BoardEntity boardEntity;
|
|
||||||
private final Camera camera;
|
|
||||||
private Coordinate click = null;
|
|
||||||
|
|
||||||
private static final float animationTime = 1.5f; // in seconds
|
|
||||||
private static final int animationTurns = 1;
|
|
||||||
|
|
||||||
private float moveProgress = 0.0f;
|
|
||||||
|
|
||||||
private String waitingPopup = null;
|
|
||||||
private final ImBoolean popupOpened = new ImBoolean(false);
|
|
||||||
|
|
||||||
public DDDView(CommandExecutor commandExecutor) {
|
|
||||||
this.commandExecutor = commandExecutor;
|
|
||||||
this.world = new World();
|
|
||||||
this.camera = new Camera();
|
|
||||||
this.window = new Window(new Renderer(), this.world, this.camera);
|
|
||||||
}
|
|
||||||
|
|
||||||
private void cancelClick() {
|
|
||||||
this.click = null;
|
|
||||||
}
|
|
||||||
|
|
||||||
private void setClick(Coordinate coordinate) {
|
|
||||||
this.click = coordinate;
|
|
||||||
}
|
|
||||||
|
|
||||||
private CommandResult sendCommand(Command command) {
|
|
||||||
return this.commandExecutor.executeCommand(command);
|
|
||||||
}
|
|
||||||
|
|
||||||
// Invoked when a cell is clicked
|
|
||||||
private void onCellClick(Coordinate coordinate) {
|
|
||||||
if (this.click == null) { // case: first click
|
|
||||||
GetAllowedMovesPieceCommand movesCommand = new GetAllowedMovesPieceCommand(coordinate);
|
|
||||||
if (sendCommand(movesCommand) == CommandResult.NotAllowed) { // case: invalid piece to move
|
|
||||||
System.out.println("Nothing to do here.");
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
List<Coordinate> allowedMoves = movesCommand.getDestinations();
|
|
||||||
if (allowedMoves.isEmpty()) { // case: no movement possible for piece
|
|
||||||
System.out.println("This piece cannot be moved at the moment.");
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
setClick(coordinate);
|
|
||||||
previewMoves(coordinate);
|
|
||||||
System.out.println("First click on " + coordinate);
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
// case: second click
|
|
||||||
GetAllowedMovesPieceCommand movesCommand = new GetAllowedMovesPieceCommand(this.click);
|
|
||||||
if (sendCommand(movesCommand) == CommandResult.NotAllowed) { // case: invalid piece to move
|
|
||||||
cancelPreview(this.click);
|
|
||||||
System.out.println("Nothing to do here.");
|
|
||||||
cancelClick();
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
List<Coordinate> allowedMoves = movesCommand.getDestinations();
|
|
||||||
if (allowedMoves.isEmpty()) { // case: no movement possible for piece
|
|
||||||
cancelPreview(this.click);
|
|
||||||
System.out.println("This piece cannot be moved at the moment.");
|
|
||||||
cancelClick();
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
if (allowedMoves.contains(coordinate)) { // case: valid attempt to move
|
|
||||||
System.out.println("Move on " + coordinate);
|
|
||||||
cancelPreview(this.click);
|
|
||||||
Command.CommandResult result = sendCommand(new MoveCommand(new Move(click, coordinate)));
|
|
||||||
cancelClick();
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
if (!(coordinate == this.click)) {
|
|
||||||
System.out.println("New click on " + coordinate); // cases: invalid move, selecting another piece
|
|
||||||
cancelPreview(this.click);
|
|
||||||
previewMoves(coordinate);
|
|
||||||
setClick(coordinate);
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
System.out.println("Cancelling click."); // case: cancelling previous click
|
|
||||||
cancelClick();
|
|
||||||
}
|
|
||||||
|
|
||||||
private void previewMoves(Coordinate coordinate) {
|
|
||||||
Piece p = pieceAt(coordinate);
|
|
||||||
if (p == null) {
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
GetAllowedMovesPieceCommand movesCommand = new GetAllowedMovesPieceCommand(coordinate);
|
|
||||||
if (sendCommand(movesCommand) == CommandResult.NotAllowed) {
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
this.boardEntity.setCellColor(coordinate, new Vector3f(1, 0, 0));
|
|
||||||
this.world.getPiece(coordinate).setColor(new Vector3f(1, 0, 0));
|
|
||||||
List<Coordinate> allowedMoves = movesCommand.getDestinations();
|
|
||||||
if (allowedMoves.isEmpty())
|
|
||||||
return;
|
|
||||||
for (Coordinate destCoord : allowedMoves) {
|
|
||||||
this.boardEntity.setCellColor(destCoord, new Vector3f(1, 1, 0));
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// Invoked when a cell is hovered
|
|
||||||
private void onCellEnter(Coordinate coordinate) {
|
|
||||||
if (this.click == null) {
|
|
||||||
// small test turning a cell red when hovered
|
|
||||||
this.boardEntity.setCellColor(coordinate, new Vector3f(1, 0, 0));
|
|
||||||
Piece p = pieceAt(coordinate);
|
|
||||||
if (p == null)
|
|
||||||
return;
|
|
||||||
this.world.getPiece(coordinate).setColor(new Vector3f(1, 0, 0));
|
|
||||||
GetAllowedMovesPieceCommand movesCommand = new GetAllowedMovesPieceCommand(coordinate);
|
|
||||||
if (sendCommand(movesCommand) == CommandResult.NotAllowed)
|
|
||||||
return;
|
|
||||||
List<Coordinate> allowedMoves = movesCommand.getDestinations();
|
|
||||||
if (allowedMoves.isEmpty())
|
|
||||||
return;
|
|
||||||
for (Coordinate destCoord : allowedMoves) {
|
|
||||||
this.boardEntity.setCellColor(destCoord, new Vector3f(1, 0, 0));
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// Invoked when a cell is not hovered anymore
|
|
||||||
private void onCellExit(Coordinate coordinate) {
|
|
||||||
if (this.click == null) {
|
|
||||||
this.boardEntity.resetCellColor(coordinate);
|
|
||||||
Piece p = pieceAt(coordinate);
|
|
||||||
if (p == null)
|
|
||||||
return;
|
|
||||||
PieceEntity pEntity = this.world.getPiece(coordinate);
|
|
||||||
if (pEntity == null)
|
|
||||||
return;
|
|
||||||
|
|
||||||
pEntity.setColor(p.getColor() == Color.White ? WHITE : BLACK);
|
|
||||||
GetAllowedMovesPieceCommand movesCommand = new GetAllowedMovesPieceCommand(coordinate);
|
|
||||||
if (sendCommand(movesCommand) == CommandResult.NotAllowed)
|
|
||||||
return;
|
|
||||||
List<Coordinate> allowedMoves = movesCommand.getDestinations();
|
|
||||||
if (allowedMoves.isEmpty())
|
|
||||||
return;
|
|
||||||
for (Coordinate destCoord : allowedMoves) {
|
|
||||||
this.boardEntity.resetCellColor(destCoord);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
private void cancelPreview(Coordinate coordinate) {
|
|
||||||
this.boardEntity.resetCellColor(coordinate);
|
|
||||||
Piece p = pieceAt(coordinate);
|
|
||||||
if (p == null)
|
|
||||||
return;
|
|
||||||
this.world.getPiece(coordinate).setColor(p.getColor() == Color.White ? WHITE : BLACK);
|
|
||||||
GetAllowedMovesPieceCommand movesCommand = new GetAllowedMovesPieceCommand(coordinate);
|
|
||||||
if (sendCommand(movesCommand) == CommandResult.NotAllowed)
|
|
||||||
return;
|
|
||||||
List<Coordinate> allowedMoves = movesCommand.getDestinations();
|
|
||||||
if (allowedMoves.isEmpty())
|
|
||||||
return;
|
|
||||||
for (Coordinate destCoord : allowedMoves) {
|
|
||||||
this.boardEntity.resetCellColor(destCoord);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
private Piece pieceAt(Coordinate pos) {
|
|
||||||
GetPieceAtCommand cmd = new GetPieceAtCommand(pos);
|
|
||||||
this.commandExecutor.executeCommand(cmd);
|
|
||||||
return cmd.getPiece();
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public void onGameStart() {
|
|
||||||
this.window.scheduleTask(() -> {
|
|
||||||
try {
|
|
||||||
initBoard();
|
|
||||||
} catch (IOException e) {
|
|
||||||
e.printStackTrace();
|
|
||||||
}
|
|
||||||
// start listening to mouse events
|
|
||||||
this.window.OnCellClick.connect(this::onCellClick);
|
|
||||||
this.window.OnCellEnter.connect(this::onCellEnter);
|
|
||||||
this.window.OnCellExit.connect(this::onCellExit);
|
|
||||||
this.window.OnImGuiTopRender.connect(this::onHeaderRender);
|
|
||||||
this.window.OnImGuiBottomRender.connect(this::onFooterRender);
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
private void onHeaderRender() {
|
|
||||||
ImGui.text("FPS : " + (int) ImGui.getIO().getFramerate());
|
|
||||||
}
|
|
||||||
|
|
||||||
private void onFooterRender() {
|
|
||||||
if (ImGui.button("Roque")) {
|
|
||||||
sendCommand(new CastlingCommand(false));
|
|
||||||
}
|
|
||||||
ImGui.sameLine();
|
|
||||||
if (ImGui.button("Grand Roque")) {
|
|
||||||
sendCommand(new CastlingCommand(true));
|
|
||||||
}
|
|
||||||
ImGui.sameLine();
|
|
||||||
if (ImGui.button("Annuler le coup précédent")) {
|
|
||||||
sendCommand(new UndoCommand());
|
|
||||||
}
|
|
||||||
openPopup();
|
|
||||||
renderPopups();
|
|
||||||
}
|
|
||||||
|
|
||||||
private void openPopup() {
|
|
||||||
if (waitingPopup != null) {
|
|
||||||
ImGui.openPopup(waitingPopup);
|
|
||||||
waitingPopup = null;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
private void initBoard() throws IOException {
|
|
||||||
for (int i = 0; i < Coordinate.VALUE_MAX; i++) {
|
|
||||||
for (int j = 0; j < Coordinate.VALUE_MAX; j++) {
|
|
||||||
Coordinate pos = new Coordinate(i, j);
|
|
||||||
Piece piece = pieceAt(pos);
|
|
||||||
if (piece == null)
|
|
||||||
continue;
|
|
||||||
|
|
||||||
Vector2f pieceBoardPos = DDDPlacement.coordinatesToVector(pos);
|
|
||||||
Vector3f pieceWorldPos = new Vector3f(pieceBoardPos.x(), 0, pieceBoardPos.y());
|
|
||||||
|
|
||||||
PieceEntity entity = new PieceEntity(piece, pieceWorldPos,
|
|
||||||
piece.getColor() == Color.White ? WHITE : BLACK,
|
|
||||||
piece.getColor() == Color.White ? 0.0f : (float) Math.PI);
|
|
||||||
|
|
||||||
this.world.addPiece(entity, pos);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
this.boardEntity = new BoardEntity();
|
|
||||||
this.world.addEntity(this.boardEntity);
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* @param begin begin
|
|
||||||
* @param middle control point
|
|
||||||
* @param end end
|
|
||||||
* @param t between 0 and 1
|
|
||||||
* @return the point
|
|
||||||
*/
|
|
||||||
private Vector3f bezierCurve(Vector3f begin, Vector3f middle, Vector3f end, float t) {
|
|
||||||
return begin.mul((1.0f - t) * (1.0f - t)).add(middle.mul(2.0f * t * (1.0f - t))).add(end.mul(t * t));
|
|
||||||
}
|
|
||||||
|
|
||||||
private Function<Float, Float> lagrangeInterpolation(Vector3f begin, Vector3f middle, Vector3f end) {
|
|
||||||
return (t) -> {
|
|
||||||
return t+1.0f;
|
|
||||||
};
|
|
||||||
}
|
|
||||||
|
|
||||||
private void pieceTick(float progress, PieceEntity piece, Move move) {
|
|
||||||
float height = 1; // how much the piece is raised
|
|
||||||
Vector2f pieceStartBoard = DDDPlacement.coordinatesToVector(move.getStart());
|
|
||||||
Vector2f pieceDestinationBoard = DDDPlacement.coordinatesToVector(move.getFinish());
|
|
||||||
Vector3f start = new Vector3f(pieceStartBoard.x(), 0, pieceStartBoard.y());
|
|
||||||
Vector3f top = new Vector3f(pieceDestinationBoard.x() - pieceStartBoard.x(), height, pieceDestinationBoard.y() - pieceStartBoard.y());
|
|
||||||
Vector3f end = new Vector3f(pieceDestinationBoard.x(), 0, pieceDestinationBoard.y());
|
|
||||||
|
|
||||||
piece.setPosition(bezierCurve(start, top, end, progress));
|
|
||||||
}
|
|
||||||
|
|
||||||
private void move3DPiece(Move move) {
|
|
||||||
Vector2f pieceDestBoardPos = DDDPlacement.coordinatesToVector(move.getFinish());
|
|
||||||
Vector3f pieceDestWorldPos = new Vector3f(pieceDestBoardPos.x(), 0, pieceDestBoardPos.y());
|
|
||||||
|
|
||||||
final PieceEntity pEntity = this.world.getPiece(move.getStart());
|
|
||||||
final Move pMove = move;
|
|
||||||
|
|
||||||
this.moveProgress = 0.0f;
|
|
||||||
|
|
||||||
Consumer<Float> moveConsumer = (delta) -> {
|
|
||||||
this.moveProgress += delta;
|
|
||||||
pieceTick(this.moveProgress, pEntity, pMove);
|
|
||||||
};
|
|
||||||
|
|
||||||
this.window.addRegularTask(moveConsumer);
|
|
||||||
|
|
||||||
try {
|
|
||||||
Thread.sleep(1000);
|
|
||||||
} catch (InterruptedException e) {
|
|
||||||
}
|
|
||||||
this.window.removeRegularTask(moveConsumer);
|
|
||||||
|
|
||||||
if (move.getDeadPieceCoords() != null) {
|
|
||||||
this.world.ejectPiece(move.getDeadPieceCoords());
|
|
||||||
}
|
|
||||||
pEntity.setPosition(pieceDestWorldPos);
|
|
||||||
|
|
||||||
this.world.movePiece(pEntity, move);
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public void onMove(Move move) {
|
|
||||||
move3DPiece(move);
|
|
||||||
cameraRotate();
|
|
||||||
}
|
|
||||||
|
|
||||||
private void cameraTick(float delta) {
|
|
||||||
int oddAnimationTurn = (2 * (animationTurns - 1)) + 1;
|
|
||||||
final float angle = (float) Math.PI;
|
|
||||||
this.camera.setRotateAngle(this.camera.getRotateAngle() + angle * delta * oddAnimationTurn / animationTime);
|
|
||||||
}
|
|
||||||
|
|
||||||
private void cameraRotate() {
|
|
||||||
float end = this.camera.getRotateAngle() + (float) Math.PI;
|
|
||||||
Consumer<Float> rotationConsumer = this::cameraTick;
|
|
||||||
this.window.addRegularTask(rotationConsumer);
|
|
||||||
try {
|
|
||||||
Thread.sleep((long) (animationTime * 1000));
|
|
||||||
} catch (InterruptedException e) {
|
|
||||||
throw new RuntimeException(e);
|
|
||||||
}
|
|
||||||
this.window.removeRegularTask(rotationConsumer);
|
|
||||||
this.camera.setRotateAngle(end);
|
|
||||||
}
|
|
||||||
|
|
||||||
public void run() {
|
|
||||||
this.window.run();
|
|
||||||
|
|
||||||
// free OpenGL resources
|
|
||||||
try {
|
|
||||||
this.window.close();
|
|
||||||
this.world.close();
|
|
||||||
} catch (IOException e) {
|
|
||||||
e.printStackTrace();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
private void renderPopup(String title, String text) {
|
|
||||||
if(ImGui.beginPopupModal(title, popupOpened)){
|
|
||||||
ImGui.text(text);
|
|
||||||
ImGui.endPopup();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
private void renderPopups() {
|
|
||||||
renderPopup("Check","Your king is in check");
|
|
||||||
renderPopup("Checkmate", "Checkmate, it's a win!");
|
|
||||||
renderPopup("Promotion", "Please promote your pawn.");
|
|
||||||
renderPopup("Pat", "It's a pat!");
|
|
||||||
renderPopup("Tie", "It's a tie!");
|
|
||||||
renderPopup("White surrender", "The white player has surrendered!");
|
|
||||||
renderPopup("Black surrender", "The black player has surrendered!");
|
|
||||||
renderPopup("White victory", "The white player has won !");
|
|
||||||
renderPopup("Black victory", "The black player has won !");
|
|
||||||
renderPopup("End", "End of the game, thank you for playing!");
|
|
||||||
}
|
|
||||||
|
|
||||||
private void openPopup(String title) {
|
|
||||||
this.popupOpened.set(true);
|
|
||||||
this.waitingPopup = title;
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public void onKingInCheck(){
|
|
||||||
openPopup("Check");
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public void onDraw() {
|
|
||||||
openPopup("Tie");
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public void onKingInMat() {
|
|
||||||
openPopup("Checkmate");
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public void onGameEnd() {
|
|
||||||
openPopup("End");
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public void onPatSituation() {
|
|
||||||
openPopup("Pat");
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public void onSurrender(Color color) {
|
|
||||||
openPopup(color == Color.White ? "White surrender": "Black surrender");
|
|
||||||
openPopup(color == Color.White ? "Black victory" : "White victory");
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -1,76 +0,0 @@
|
|||||||
package chess.view.DDDrender;
|
|
||||||
|
|
||||||
import static org.lwjgl.opengl.GL11.GL_UNSIGNED_INT;
|
|
||||||
|
|
||||||
import java.io.Closeable;
|
|
||||||
import java.io.IOException;
|
|
||||||
|
|
||||||
import org.joml.Matrix4f;
|
|
||||||
import org.joml.Vector3f;
|
|
||||||
import org.lwjgl.opengl.GL30;
|
|
||||||
|
|
||||||
import chess.view.DDDrender.opengl.FrameBuffer;
|
|
||||||
import chess.view.DDDrender.opengl.VertexArray;
|
|
||||||
import chess.view.DDDrender.shader.BoardShader;
|
|
||||||
import chess.view.DDDrender.shader.PieceShader;
|
|
||||||
import chess.view.DDDrender.shader.ShaderProgram;
|
|
||||||
|
|
||||||
public class Renderer implements Closeable {
|
|
||||||
private BoardShader boardShader;
|
|
||||||
private PieceShader pieceShader;
|
|
||||||
private FrameBuffer frameBuffer;
|
|
||||||
|
|
||||||
public Renderer() {
|
|
||||||
this.boardShader = new BoardShader();
|
|
||||||
this.pieceShader = new PieceShader();
|
|
||||||
}
|
|
||||||
|
|
||||||
public void Init(float windowWidth, float widowHeight) {
|
|
||||||
boardShader.LoadShader();
|
|
||||||
pieceShader.LoadShader();
|
|
||||||
|
|
||||||
this.frameBuffer = new FrameBuffer((int) windowWidth, (int) (widowHeight * 8.0f / 10.0f));
|
|
||||||
}
|
|
||||||
|
|
||||||
public void Update(Camera cam) {
|
|
||||||
this.boardShader.Start();
|
|
||||||
this.boardShader.SetCamMatrix(cam);
|
|
||||||
this.pieceShader.Start();
|
|
||||||
this.pieceShader.SetCamMatrix(cam);
|
|
||||||
}
|
|
||||||
|
|
||||||
public void Render(DDDModel model, Vector3f color, Matrix4f transform) {
|
|
||||||
this.pieceShader.Start();
|
|
||||||
this.pieceShader.setModelColor(color);
|
|
||||||
this.pieceShader.setModelTransform(transform);
|
|
||||||
Render(model);
|
|
||||||
}
|
|
||||||
|
|
||||||
public void Render(DDDModel model) {
|
|
||||||
for (int i = 0; i < model.getVaos().size(); i++) {
|
|
||||||
VertexArray vao = model.getVaos().get(i);
|
|
||||||
RenderVao(this.pieceShader, vao);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
public void RenderVao(ShaderProgram shader, VertexArray vertexArray) {
|
|
||||||
shader.Start();
|
|
||||||
vertexArray.Bind();
|
|
||||||
GL30.glDrawElements(GL30.GL_TRIANGLES, vertexArray.GetVertexCount(), GL_UNSIGNED_INT, 0);
|
|
||||||
vertexArray.Unbind();
|
|
||||||
}
|
|
||||||
|
|
||||||
public FrameBuffer getFrameBuffer() {
|
|
||||||
return frameBuffer;
|
|
||||||
}
|
|
||||||
|
|
||||||
public BoardShader getBoardShader() {
|
|
||||||
return boardShader;
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public void close() throws IOException {
|
|
||||||
this.boardShader.close();
|
|
||||||
this.pieceShader.close();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -1,312 +0,0 @@
|
|||||||
package chess.view.DDDrender;
|
|
||||||
|
|
||||||
import common.Signal0;
|
|
||||||
import org.joml.Vector2f;
|
|
||||||
import org.lwjgl.*;
|
|
||||||
import org.lwjgl.glfw.*;
|
|
||||||
import org.lwjgl.opengl.*;
|
|
||||||
import org.lwjgl.system.*;
|
|
||||||
|
|
||||||
import chess.model.Coordinate;
|
|
||||||
import chess.view.AssetManager;
|
|
||||||
import chess.view.DDDrender.opengl.FrameBuffer;
|
|
||||||
import chess.view.DDDrender.world.Entity;
|
|
||||||
import chess.view.DDDrender.world.World;
|
|
||||||
import common.Signal1;
|
|
||||||
import imgui.ImFontConfig;
|
|
||||||
import imgui.ImGui;
|
|
||||||
import imgui.ImVec2;
|
|
||||||
import imgui.flag.ImGuiWindowFlags;
|
|
||||||
import imgui.gl3.ImGuiImplGl3;
|
|
||||||
import imgui.glfw.ImGuiImplGlfw;
|
|
||||||
import imgui.type.ImBoolean;
|
|
||||||
import imgui.type.ImInt;
|
|
||||||
|
|
||||||
import java.io.Closeable;
|
|
||||||
import java.io.IOException;
|
|
||||||
import java.nio.*;
|
|
||||||
import java.util.ArrayList;
|
|
||||||
import java.util.List;
|
|
||||||
import java.util.Queue;
|
|
||||||
import java.util.concurrent.ConcurrentLinkedDeque;
|
|
||||||
import java.util.function.Consumer;
|
|
||||||
|
|
||||||
import static org.lwjgl.glfw.Callbacks.*;
|
|
||||||
import static org.lwjgl.glfw.GLFW.*;
|
|
||||||
import static org.lwjgl.opengl.GL11.*;
|
|
||||||
import static org.lwjgl.system.MemoryStack.*;
|
|
||||||
import static org.lwjgl.system.MemoryUtil.*;
|
|
||||||
|
|
||||||
public class Window implements Closeable {
|
|
||||||
|
|
||||||
// The window handle
|
|
||||||
private long window;
|
|
||||||
|
|
||||||
private final ImGuiImplGl3 implGl3 = new ImGuiImplGl3();
|
|
||||||
private final ImGuiImplGlfw implGlfw = new ImGuiImplGlfw();
|
|
||||||
|
|
||||||
private Renderer renderer;
|
|
||||||
private final Camera cam;
|
|
||||||
private final World world;
|
|
||||||
|
|
||||||
private final Queue<Runnable> tasks;
|
|
||||||
private final List<Consumer<Float>> regularTasks;
|
|
||||||
|
|
||||||
private Coordinate lastCell = null;
|
|
||||||
|
|
||||||
public final Signal1<Coordinate> OnCellClick = new Signal1<>();
|
|
||||||
public final Signal1<Coordinate> OnCellEnter = new Signal1<>();
|
|
||||||
public final Signal1<Coordinate> OnCellExit = new Signal1<>();
|
|
||||||
|
|
||||||
public final Signal0 OnImGuiTopRender = new Signal0();
|
|
||||||
public final Signal0 OnImGuiBottomRender = new Signal0();
|
|
||||||
|
|
||||||
private ImInt detailLevel = new ImInt(10);
|
|
||||||
private ImBoolean pixelatedFrame = new ImBoolean(true);
|
|
||||||
|
|
||||||
public Window(Renderer renderer, World world, Camera camera) {
|
|
||||||
this.renderer = new Renderer();
|
|
||||||
this.cam = camera;
|
|
||||||
this.tasks = new ConcurrentLinkedDeque<>();
|
|
||||||
this.world = world;
|
|
||||||
this.regularTasks = new ArrayList<>();
|
|
||||||
}
|
|
||||||
|
|
||||||
public void addRegularTask(Consumer<Float> task) {
|
|
||||||
this.regularTasks.add(task);
|
|
||||||
}
|
|
||||||
|
|
||||||
public void removeRegularTask(Consumer<Float> task) {this.regularTasks.remove(task);}
|
|
||||||
|
|
||||||
public synchronized void scheduleTask(Runnable runnable) {
|
|
||||||
this.tasks.add(runnable);
|
|
||||||
}
|
|
||||||
|
|
||||||
public synchronized Runnable getNextTask() {
|
|
||||||
return this.tasks.poll();
|
|
||||||
}
|
|
||||||
|
|
||||||
public void run() {
|
|
||||||
System.out.println("LWJGL " + Version.getVersion() + "!");
|
|
||||||
|
|
||||||
init();
|
|
||||||
loop();
|
|
||||||
|
|
||||||
// Free the window callbacks and destroy the window
|
|
||||||
glfwFreeCallbacks(window);
|
|
||||||
glfwDestroyWindow(window);
|
|
||||||
|
|
||||||
// Terminate GLFW and free the error callback
|
|
||||||
glfwTerminate();
|
|
||||||
glfwSetErrorCallback(null).free();
|
|
||||||
|
|
||||||
implGl3.shutdown();
|
|
||||||
implGlfw.shutdown();
|
|
||||||
|
|
||||||
ImGui.destroyContext();
|
|
||||||
}
|
|
||||||
|
|
||||||
private void initImGui() {
|
|
||||||
ImGui.setCurrentContext(ImGui.createContext());
|
|
||||||
|
|
||||||
implGl3.init("#version 330");
|
|
||||||
implGlfw.init(window, true);
|
|
||||||
|
|
||||||
ImFontConfig config = new ImFontConfig();
|
|
||||||
config.setFontDataOwnedByAtlas(false);
|
|
||||||
try {
|
|
||||||
ImGui.getIO().getFonts().addFontFromMemoryTTF(AssetManager.getResource("fonts/comic.ttf").readAllBytes(),
|
|
||||||
50.0f, config);
|
|
||||||
} catch (IOException e) {
|
|
||||||
// TODO Auto-generated catch block
|
|
||||||
e.printStackTrace();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
private void init() {
|
|
||||||
// Setup an error callback. The default implementation
|
|
||||||
// will print the error message in System.err.
|
|
||||||
GLFWErrorCallback.createPrint(System.err).set();
|
|
||||||
|
|
||||||
// Initialize GLFW. Most GLFW functions will not work before doing this.
|
|
||||||
if (!glfwInit())
|
|
||||||
throw new IllegalStateException("Unable to initialize GLFW");
|
|
||||||
|
|
||||||
// Configure GLFW
|
|
||||||
glfwDefaultWindowHints(); // optional, the current window hints are already the default
|
|
||||||
glfwWindowHint(GLFW_VISIBLE, GLFW_FALSE); // the window will stay hidden after creation
|
|
||||||
glfwWindowHint(GLFW_RESIZABLE, GLFW_TRUE); // the window will be resizable
|
|
||||||
|
|
||||||
// Create the window
|
|
||||||
window = glfwCreateWindow(1000, 1000, "3DChess", NULL, NULL);
|
|
||||||
if (window == NULL)
|
|
||||||
throw new RuntimeException("Failed to create the GLFW window");
|
|
||||||
|
|
||||||
// Get the thread stack and push a new frame
|
|
||||||
try (MemoryStack stack = stackPush()) {
|
|
||||||
IntBuffer pWidth = stack.mallocInt(1); // int*
|
|
||||||
IntBuffer pHeight = stack.mallocInt(1); // int*
|
|
||||||
|
|
||||||
// Get the window size passed to glfwCreateWindow
|
|
||||||
glfwGetWindowSize(window, pWidth, pHeight);
|
|
||||||
|
|
||||||
// Get the resolution of the primary monitor
|
|
||||||
GLFWVidMode vidmode = glfwGetVideoMode(glfwGetPrimaryMonitor());
|
|
||||||
|
|
||||||
// Center the window
|
|
||||||
glfwSetWindowPos(
|
|
||||||
window,
|
|
||||||
(vidmode.width() - pWidth.get(0)) / 2,
|
|
||||||
(vidmode.height() - pHeight.get(0)) / 2);
|
|
||||||
|
|
||||||
glfwSetWindowSize(window, vidmode.width(), vidmode.height());
|
|
||||||
|
|
||||||
// Make the OpenGL context current
|
|
||||||
glfwMakeContextCurrent(window);
|
|
||||||
|
|
||||||
GL.createCapabilities();
|
|
||||||
|
|
||||||
initImGui();
|
|
||||||
|
|
||||||
renderer.Init(vidmode.width(), vidmode.height());
|
|
||||||
} // the stack frame is popped automatically
|
|
||||||
|
|
||||||
// Enable v-sync
|
|
||||||
glfwSwapInterval(1);
|
|
||||||
|
|
||||||
// Make the window visible
|
|
||||||
glfwShowWindow(window);
|
|
||||||
}
|
|
||||||
|
|
||||||
private void render(float delta, float aspectRatio) {
|
|
||||||
final FrameBuffer frameBuffer = this.renderer.getFrameBuffer();
|
|
||||||
|
|
||||||
cam.setAspectRatio(frameBuffer.getAspectRatio());
|
|
||||||
frameBuffer.Bind();
|
|
||||||
frameBuffer.Clear();
|
|
||||||
renderer.Update(cam);
|
|
||||||
renderWorld();
|
|
||||||
frameBuffer.Unbind();
|
|
||||||
}
|
|
||||||
|
|
||||||
private void renderWorld() {
|
|
||||||
for (Entity entity : this.world.getEntites()) {
|
|
||||||
entity.render(this.renderer);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
private void executeTasks(float delta) {
|
|
||||||
Runnable task = getNextTask();
|
|
||||||
while (task != null) {
|
|
||||||
task.run();
|
|
||||||
task = getNextTask();
|
|
||||||
}
|
|
||||||
for (Consumer<Float> consumer : regularTasks) {
|
|
||||||
consumer.accept(delta);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
private void checkCursor(float cursorPosX, float cursorPosY, int windowWidth, int windowHeight) {
|
|
||||||
Vector2f cursorPos = this.cam.getCursorWorldFloorPos(new Vector2f(cursorPosX, cursorPosY), windowWidth,
|
|
||||||
windowHeight);
|
|
||||||
Coordinate selectedCell = DDDPlacement.vectorToCoordinates(cursorPos);
|
|
||||||
if (this.lastCell == null) {
|
|
||||||
this.lastCell = selectedCell;
|
|
||||||
if (selectedCell.isValid())
|
|
||||||
this.OnCellEnter.emit(selectedCell);
|
|
||||||
} else if (!this.lastCell.equals(selectedCell)) {
|
|
||||||
if (this.lastCell.isValid())
|
|
||||||
this.OnCellExit.emit(this.lastCell);
|
|
||||||
if (selectedCell.isValid())
|
|
||||||
this.OnCellEnter.emit(selectedCell);
|
|
||||||
this.lastCell = selectedCell;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (ImGui.getIO().getMouseClicked(0)) {
|
|
||||||
if (this.lastCell != null && this.lastCell.isValid())
|
|
||||||
this.OnCellClick.emit(this.lastCell);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
private void newFrame() {
|
|
||||||
glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT); // clear the framebuffer
|
|
||||||
|
|
||||||
implGlfw.newFrame();
|
|
||||||
implGl3.newFrame();
|
|
||||||
ImGui.newFrame();
|
|
||||||
}
|
|
||||||
|
|
||||||
private void renderWindow() {
|
|
||||||
ImGui.showDemoWindow();
|
|
||||||
|
|
||||||
final FrameBuffer frameBuffer = this.renderer.getFrameBuffer();
|
|
||||||
final int frameWidth = (int) ImGui.getIO().getDisplaySizeX();
|
|
||||||
final int frameHeight = (int) (ImGui.getIO().getDisplaySizeY() * 8.0f / 10.0f);
|
|
||||||
|
|
||||||
ImGui.setNextWindowSize(ImGui.getIO().getDisplaySize());
|
|
||||||
ImGui.setNextWindowPos(new ImVec2());
|
|
||||||
ImGui.begin("Main Window", ImGuiWindowFlags.NoDecoration);
|
|
||||||
this.OnImGuiTopRender.emit();
|
|
||||||
ImVec2 mousePos = ImGui.getIO().getMousePos();
|
|
||||||
ImVec2 framePos = ImGui.getCursorScreenPos();
|
|
||||||
checkCursor(mousePos.x - framePos.x, frameHeight - (mousePos.y - framePos.y), frameWidth, frameHeight);
|
|
||||||
ImGui.image(frameBuffer.getRenderTexture(), new ImVec2(frameWidth, frameHeight));
|
|
||||||
this.OnImGuiBottomRender.emit();
|
|
||||||
if(ImGui.sliderInt("Niveau de détail", detailLevel.getData(), 1, 10)){
|
|
||||||
frameBuffer.Resize((int) ((float) frameWidth * detailLevel.get() / 10.0f), (int) ((float) frameHeight * detailLevel.get() / 10.0f));
|
|
||||||
}
|
|
||||||
if (ImGui.checkbox("Minecraft", pixelatedFrame)) {
|
|
||||||
frameBuffer.SetPixelScaling(pixelatedFrame.get());
|
|
||||||
}
|
|
||||||
ImGui.end();
|
|
||||||
}
|
|
||||||
|
|
||||||
private void loop() {
|
|
||||||
|
|
||||||
// Set the clear color
|
|
||||||
glClearColor(0.4f, 0.4f, 0.6f, 1.0f);
|
|
||||||
|
|
||||||
glEnable(GL_DEPTH_TEST);
|
|
||||||
|
|
||||||
glEnable(GL_CULL_FACE);
|
|
||||||
glCullFace(GL_FRONT);
|
|
||||||
glFrontFace(GL_CW);
|
|
||||||
|
|
||||||
glColor4f(1.0f, 0.0f, 0.0f, 1.0f);
|
|
||||||
|
|
||||||
int width[] = new int[1];
|
|
||||||
int height[] = new int[1];
|
|
||||||
glfwGetWindowSize(window, width, height);
|
|
||||||
|
|
||||||
// Run the rendering loop until the user has attempted to close
|
|
||||||
// the window or has pressed the ESCAPE key.
|
|
||||||
while (!glfwWindowShouldClose(window)) {
|
|
||||||
|
|
||||||
newFrame();
|
|
||||||
|
|
||||||
render(ImGui.getIO().getDeltaTime(), (float) width[0] / (float) height[0]);
|
|
||||||
|
|
||||||
renderWindow();
|
|
||||||
ImGui.render();
|
|
||||||
implGl3.renderDrawData(ImGui.getDrawData());
|
|
||||||
|
|
||||||
glfwSwapBuffers(window); // swap the color buffers
|
|
||||||
|
|
||||||
// Poll for window events. The key callback above will only be
|
|
||||||
// invoked during this call.
|
|
||||||
glfwPollEvents();
|
|
||||||
|
|
||||||
executeTasks(ImGui.getIO().getDeltaTime());
|
|
||||||
|
|
||||||
glfwGetWindowSize(window, width, height);
|
|
||||||
glViewport(0, 0, width[0], height[0]);
|
|
||||||
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public void close() throws IOException {
|
|
||||||
this.renderer.close();
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
|
||||||
@@ -1,98 +0,0 @@
|
|||||||
package chess.view.DDDrender.loader;
|
|
||||||
|
|
||||||
import org.joml.Vector3f;
|
|
||||||
|
|
||||||
import chess.view.DDDrender.opengl.ElementBuffer;
|
|
||||||
import chess.view.DDDrender.opengl.VertexArray;
|
|
||||||
import chess.view.DDDrender.opengl.VertexBuffer;
|
|
||||||
|
|
||||||
public class BoardModelLoader {
|
|
||||||
|
|
||||||
private static final int BOARD_WIDTH = 8;
|
|
||||||
private static final int BOARD_HEIGHT = 8;
|
|
||||||
private static final int BOARD_SIZE = BOARD_WIDTH * BOARD_HEIGHT;
|
|
||||||
private static final int SQUARE_VERTEX_COUNT = 4;
|
|
||||||
|
|
||||||
private static final Vector3f WHITE = new Vector3f(1, 1, 1);
|
|
||||||
private static final Vector3f BLACK = new Vector3f(0, 0, 0);
|
|
||||||
|
|
||||||
private static float[] GetBoardPositions() {
|
|
||||||
float[] positions = new float[BOARD_SIZE * SQUARE_VERTEX_COUNT * 3];
|
|
||||||
for (int i = 0; i < BOARD_WIDTH; i++) {
|
|
||||||
for (int j = 0; j < BOARD_HEIGHT; j++) {
|
|
||||||
float x = i / (float) BOARD_WIDTH;
|
|
||||||
float dx = (i + 1) / (float) BOARD_WIDTH;
|
|
||||||
float z = j / (float) BOARD_HEIGHT;
|
|
||||||
float dz = (j + 1) / (float) BOARD_HEIGHT;
|
|
||||||
|
|
||||||
float trueX = 2 * x - 1;
|
|
||||||
float trueZ = 2 * z - 1;
|
|
||||||
float trueDX = 2 * dx - 1;
|
|
||||||
float trueDZ = 2 * dz - 1;
|
|
||||||
|
|
||||||
positions[(BOARD_WIDTH * i + j) * SQUARE_VERTEX_COUNT * 3] = trueX;
|
|
||||||
positions[(BOARD_WIDTH * i + j) * SQUARE_VERTEX_COUNT * 3 + 1] = 0.0f;
|
|
||||||
positions[(BOARD_WIDTH * i + j) * SQUARE_VERTEX_COUNT * 3 + 2] = trueZ;
|
|
||||||
|
|
||||||
positions[(BOARD_WIDTH * i + j) * SQUARE_VERTEX_COUNT * 3 + 3] = trueDX;
|
|
||||||
positions[(BOARD_WIDTH * i + j) * SQUARE_VERTEX_COUNT * 3 + 4] = 0.0f;
|
|
||||||
positions[(BOARD_WIDTH * i + j) * SQUARE_VERTEX_COUNT * 3 + 5] = trueZ;
|
|
||||||
|
|
||||||
positions[(BOARD_WIDTH * i + j) * SQUARE_VERTEX_COUNT * 3 + 6] = trueX;
|
|
||||||
positions[(BOARD_WIDTH * i + j) * SQUARE_VERTEX_COUNT * 3 + 7] = 0.0f;
|
|
||||||
positions[(BOARD_WIDTH * i + j) * SQUARE_VERTEX_COUNT * 3 + 8] = trueDZ;
|
|
||||||
|
|
||||||
positions[(BOARD_WIDTH * i + j) * SQUARE_VERTEX_COUNT * 3 + 9] = trueDX;
|
|
||||||
positions[(BOARD_WIDTH * i + j) * SQUARE_VERTEX_COUNT * 3 + 10] = 0.0f;
|
|
||||||
positions[(BOARD_WIDTH * i + j) * SQUARE_VERTEX_COUNT * 3 + 11] = trueDZ;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return positions;
|
|
||||||
}
|
|
||||||
|
|
||||||
private static float[] GetBoardColors() {
|
|
||||||
float[] colors = new float[BOARD_SIZE * SQUARE_VERTEX_COUNT * 3];
|
|
||||||
for (int i = 0; i < BOARD_WIDTH; i++) {
|
|
||||||
for (int j = 0; j < BOARD_HEIGHT; j++) {
|
|
||||||
Vector3f color = (i + j) % 2 == 0 ? WHITE : BLACK;
|
|
||||||
int squareIndex = i * BOARD_WIDTH + j;
|
|
||||||
for (int k = 0; k < SQUARE_VERTEX_COUNT; k++) {
|
|
||||||
colors[squareIndex * SQUARE_VERTEX_COUNT * 3 + k * 3] = color.x;
|
|
||||||
colors[squareIndex * SQUARE_VERTEX_COUNT * 3 + k * 3 + 1] = color.y;
|
|
||||||
colors[squareIndex * SQUARE_VERTEX_COUNT * 3 + k * 3 + 2] = color.z;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return colors;
|
|
||||||
}
|
|
||||||
|
|
||||||
private static int[] GetBoardIndicies() {
|
|
||||||
int[] indices = new int[BOARD_SIZE * 6];
|
|
||||||
for (int i = 0; i < BOARD_SIZE; i++) {
|
|
||||||
indices[i * 6] = i * 4;
|
|
||||||
indices[i * 6 + 1] = i * 4 + 2;
|
|
||||||
indices[i * 6 + 2] = i * 4 + 1;
|
|
||||||
indices[i * 6 + 3] = i * 4 + 1;
|
|
||||||
indices[i * 6 + 4] = i * 4 + 2;
|
|
||||||
indices[i * 6 + 5] = i * 4 + 3;
|
|
||||||
}
|
|
||||||
return indices;
|
|
||||||
}
|
|
||||||
|
|
||||||
public static VertexArray GetBoardModel() {
|
|
||||||
ElementBuffer eBuffer = new ElementBuffer(GetBoardIndicies());
|
|
||||||
VertexArray vao = new VertexArray(eBuffer);
|
|
||||||
|
|
||||||
VertexBuffer positionBuffer = new VertexBuffer(GetBoardPositions(), 3);
|
|
||||||
positionBuffer.AddVertexAttribPointer(0, 3, 0);
|
|
||||||
|
|
||||||
VertexBuffer colorBuffer = new VertexBuffer(GetBoardColors(), 3);
|
|
||||||
colorBuffer.AddVertexAttribPointer(1, 3, 0);
|
|
||||||
|
|
||||||
vao.Bind();
|
|
||||||
vao.BindVertexBuffer(positionBuffer);
|
|
||||||
vao.BindVertexBuffer(colorBuffer);
|
|
||||||
vao.Unbind();
|
|
||||||
return vao;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -1,130 +0,0 @@
|
|||||||
package chess.view.DDDrender.loader;
|
|
||||||
|
|
||||||
import java.io.IOException;
|
|
||||||
import java.io.InputStream;
|
|
||||||
import java.nio.ByteBuffer;
|
|
||||||
import java.nio.IntBuffer;
|
|
||||||
import java.util.ArrayList;
|
|
||||||
import java.util.List;
|
|
||||||
|
|
||||||
import org.lwjgl.assimp.AIFace.Buffer;
|
|
||||||
import org.lwjgl.assimp.AIMesh;
|
|
||||||
import org.lwjgl.assimp.AINode;
|
|
||||||
import org.lwjgl.assimp.AIScene;
|
|
||||||
import org.lwjgl.assimp.AIVector3D;
|
|
||||||
import org.lwjgl.assimp.Assimp;
|
|
||||||
import org.lwjgl.system.MemoryUtil;
|
|
||||||
|
|
||||||
import chess.view.AssetManager;
|
|
||||||
import chess.view.DDDrender.DDDModel;
|
|
||||||
import chess.view.DDDrender.opengl.ElementBuffer;
|
|
||||||
import chess.view.DDDrender.opengl.VertexArray;
|
|
||||||
import chess.view.DDDrender.opengl.VertexBuffer;
|
|
||||||
|
|
||||||
public class ModelLoader {
|
|
||||||
|
|
||||||
private static final int VERTEX_SIZE = 3;
|
|
||||||
private static final int VERTEX_POSITION_INDEX = 0;
|
|
||||||
private static final int VERTEX_NORMAL_INDEX = 1;
|
|
||||||
|
|
||||||
private static float[] toFloatArray(List<Float> list) {
|
|
||||||
float[] result = new float[list.size()];
|
|
||||||
for (int i = 0; i < list.size(); i++) {
|
|
||||||
result[i] = list.get(i);
|
|
||||||
}
|
|
||||||
return result;
|
|
||||||
}
|
|
||||||
|
|
||||||
private static int[] toIntArray(List<Integer> list) {
|
|
||||||
int[] result = new int[list.size()];
|
|
||||||
for (int i = 0; i < list.size(); i++) {
|
|
||||||
result[i] = list.get(i);
|
|
||||||
}
|
|
||||||
return result;
|
|
||||||
}
|
|
||||||
|
|
||||||
private static VertexArray processMesh(AIMesh mesh, AIScene scene) {
|
|
||||||
List<Float> positions = new ArrayList<>();
|
|
||||||
List<Float> normals = new ArrayList<>();
|
|
||||||
|
|
||||||
List<Integer> indicies = new ArrayList<>();
|
|
||||||
|
|
||||||
Buffer faces = mesh.mFaces();
|
|
||||||
int faceNumber = mesh.mNumFaces();
|
|
||||||
|
|
||||||
for (int i = 0; i < faceNumber; i++) {
|
|
||||||
IntBuffer faceIndicies = faces.get(i).mIndices();
|
|
||||||
for (int j = 0; j < faceIndicies.capacity(); j++) {
|
|
||||||
indicies.add(faceIndicies.get(j));
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
int vertNumber = mesh.mNumVertices();
|
|
||||||
org.lwjgl.assimp.AIVector3D.Buffer vertecies = mesh.mVertices();
|
|
||||||
for (int i = 0; i < vertNumber; i++) {
|
|
||||||
AIVector3D vertex = vertecies.get(i);
|
|
||||||
positions.add(vertex.x());
|
|
||||||
positions.add(vertex.y());
|
|
||||||
positions.add(vertex.z());
|
|
||||||
}
|
|
||||||
|
|
||||||
org.lwjgl.assimp.AIVector3D.Buffer vertexNormals = mesh.mNormals();
|
|
||||||
for (int i = 0; i < vertNumber; i++) {
|
|
||||||
AIVector3D normal = vertexNormals.get(i);
|
|
||||||
normals.add(normal.x());
|
|
||||||
normals.add(normal.y());
|
|
||||||
normals.add(normal.z());
|
|
||||||
}
|
|
||||||
|
|
||||||
VertexBuffer positionVBO = new VertexBuffer(toFloatArray(positions), VERTEX_SIZE);
|
|
||||||
positionVBO.AddVertexAttribPointer(VERTEX_POSITION_INDEX, VERTEX_SIZE, 0);
|
|
||||||
VertexBuffer normalVBO = new VertexBuffer(toFloatArray(normals), VERTEX_SIZE);
|
|
||||||
normalVBO.AddVertexAttribPointer(VERTEX_NORMAL_INDEX, VERTEX_SIZE, 0);
|
|
||||||
|
|
||||||
VertexArray vao = new VertexArray(new ElementBuffer(toIntArray(indicies)));
|
|
||||||
vao.Bind();
|
|
||||||
vao.BindVertexBuffer(positionVBO);
|
|
||||||
vao.BindVertexBuffer(normalVBO);
|
|
||||||
vao.Unbind();
|
|
||||||
return vao;
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
private static void processNode(AINode node, AIScene scene, List<VertexArray> meshes) {
|
|
||||||
for (int i = 0; i < node.mNumChildren(); i++) {
|
|
||||||
AINode child = AINode.create(node.mChildren().get(i));
|
|
||||||
processNode(child, scene, meshes);
|
|
||||||
}
|
|
||||||
for (int i = 0; i < node.mNumMeshes(); i++) {
|
|
||||||
AIMesh mesh = AIMesh.create(scene.mMeshes().get(node.mMeshes().get(i)));
|
|
||||||
meshes.add(processMesh(mesh, scene));
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
public static DDDModel loadModel(String filename) throws IOException {
|
|
||||||
InputStream input = AssetManager.getResource(filename);
|
|
||||||
byte[] buffer = input.readAllBytes();
|
|
||||||
ByteBuffer data = MemoryUtil.memCalloc(buffer.length);
|
|
||||||
data.put(buffer);
|
|
||||||
data.flip();
|
|
||||||
|
|
||||||
AIScene scene = Assimp.aiImportFileFromMemory(
|
|
||||||
data,
|
|
||||||
Assimp.aiProcess_Triangulate | Assimp.aiProcess_PreTransformVertices | Assimp.aiProcess_GlobalScale
|
|
||||||
| Assimp.aiProcess_ValidateDataStructure,
|
|
||||||
"");
|
|
||||||
|
|
||||||
if (scene == null)
|
|
||||||
System.err.println(Assimp.aiGetErrorString());
|
|
||||||
|
|
||||||
List<VertexArray> vertecies = new ArrayList<>();
|
|
||||||
|
|
||||||
processNode(scene.mRootNode(), scene, vertecies);
|
|
||||||
|
|
||||||
MemoryUtil.memFree(data);
|
|
||||||
|
|
||||||
return new DDDModel(vertecies);
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
|
||||||
@@ -1,75 +0,0 @@
|
|||||||
package chess.view.DDDrender.loader;
|
|
||||||
|
|
||||||
import java.io.IOException;
|
|
||||||
import java.util.HashMap;
|
|
||||||
import java.util.Map;
|
|
||||||
|
|
||||||
import chess.model.Color;
|
|
||||||
import chess.model.Piece;
|
|
||||||
import chess.model.PieceVisitor;
|
|
||||||
import chess.model.pieces.Bishop;
|
|
||||||
import chess.model.pieces.King;
|
|
||||||
import chess.model.pieces.Knight;
|
|
||||||
import chess.model.pieces.Pawn;
|
|
||||||
import chess.model.pieces.Queen;
|
|
||||||
import chess.model.pieces.Rook;
|
|
||||||
import chess.view.DDDrender.DDDModel;
|
|
||||||
|
|
||||||
public class Piece3DModel implements PieceVisitor<String> {
|
|
||||||
|
|
||||||
private static final String basePath = "3d/";
|
|
||||||
private static final Map<String, DDDModel> cache = new HashMap<>();
|
|
||||||
|
|
||||||
public DDDModel getModel(Piece piece) throws IOException {
|
|
||||||
if (piece == null)
|
|
||||||
return null;
|
|
||||||
|
|
||||||
String path = basePath + colorToString(piece.getColor()) + "-" + visit(piece) + ".fbx";
|
|
||||||
return getModel(path);
|
|
||||||
}
|
|
||||||
|
|
||||||
private DDDModel getModel(String path) throws IOException {
|
|
||||||
DDDModel model = cache.get(path);
|
|
||||||
if (model != null)
|
|
||||||
return model;
|
|
||||||
|
|
||||||
model = ModelLoader.loadModel(path);
|
|
||||||
cache.put(path, model);
|
|
||||||
return model;
|
|
||||||
}
|
|
||||||
|
|
||||||
private String colorToString(Color color) {
|
|
||||||
return color == Color.Black ? "black" : "white";
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public String visitPiece(Bishop bishop) {
|
|
||||||
return "bishop";
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public String visitPiece(King king) {
|
|
||||||
return "king";
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public String visitPiece(Knight knight) {
|
|
||||||
return "knight";
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public String visitPiece(Pawn pawn) {
|
|
||||||
return "pawn";
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public String visitPiece(Queen queen) {
|
|
||||||
return "queen";
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public String visitPiece(Rook rook) {
|
|
||||||
return "rook";
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
|
||||||
@@ -1,106 +0,0 @@
|
|||||||
package chess.view.DDDrender.opengl;
|
|
||||||
|
|
||||||
import static org.lwjgl.opengl.GL11.GL_COLOR_BUFFER_BIT;
|
|
||||||
import static org.lwjgl.opengl.GL11.GL_DEPTH_BUFFER_BIT;
|
|
||||||
import static org.lwjgl.opengl.GL11.GL_DEPTH_COMPONENT;
|
|
||||||
import static org.lwjgl.opengl.GL11.GL_RGB;
|
|
||||||
import static org.lwjgl.opengl.GL11.GL_TEXTURE_2D;
|
|
||||||
import static org.lwjgl.opengl.GL11.GL_UNSIGNED_BYTE;
|
|
||||||
import static org.lwjgl.opengl.GL11.glBindTexture;
|
|
||||||
import static org.lwjgl.opengl.GL11.glClear;
|
|
||||||
import static org.lwjgl.opengl.GL11.glTexImage2D;
|
|
||||||
import static org.lwjgl.opengl.GL11.glViewport;
|
|
||||||
|
|
||||||
import org.lwjgl.opengl.GL30;
|
|
||||||
|
|
||||||
public class FrameBuffer {
|
|
||||||
|
|
||||||
private int fbo;
|
|
||||||
private int renderTexture;
|
|
||||||
private int depthBuffer;
|
|
||||||
|
|
||||||
private int width;
|
|
||||||
private int height;
|
|
||||||
|
|
||||||
public FrameBuffer(int width, int height) {
|
|
||||||
this.width = width;
|
|
||||||
this.height = height;
|
|
||||||
|
|
||||||
// The frame buffer
|
|
||||||
this.fbo = GL30.glGenFramebuffers();
|
|
||||||
GL30.glBindFramebuffer(GL30.GL_FRAMEBUFFER, fbo);
|
|
||||||
|
|
||||||
// The texture
|
|
||||||
this.renderTexture = GL30.glGenTextures();
|
|
||||||
glBindTexture(GL_TEXTURE_2D, renderTexture);
|
|
||||||
|
|
||||||
glTexImage2D(GL_TEXTURE_2D, 0, GL_RGB, width, height, 0, GL_RGB, GL_UNSIGNED_BYTE, 0);
|
|
||||||
|
|
||||||
GL30.glTexParameteri(GL_TEXTURE_2D, GL30.GL_TEXTURE_MAG_FILTER, GL30.GL_NEAREST);
|
|
||||||
GL30.glTexParameteri(GL_TEXTURE_2D, GL30.GL_TEXTURE_MIN_FILTER, GL30.GL_NEAREST);
|
|
||||||
|
|
||||||
// The depth buffer
|
|
||||||
this.depthBuffer = GL30.glGenRenderbuffers();
|
|
||||||
GL30.glBindRenderbuffer(GL30.GL_RENDERBUFFER, depthBuffer);
|
|
||||||
GL30.glRenderbufferStorage(GL30.GL_RENDERBUFFER, GL_DEPTH_COMPONENT, width, height);
|
|
||||||
GL30.glFramebufferRenderbuffer(GL30.GL_FRAMEBUFFER, GL30.GL_DEPTH_ATTACHMENT, GL30.GL_RENDERBUFFER,
|
|
||||||
depthBuffer);
|
|
||||||
|
|
||||||
// Set "renderedTexture" as our colour attachement #0
|
|
||||||
GL30.glFramebufferTexture2D(GL30.GL_FRAMEBUFFER, GL30.GL_COLOR_ATTACHMENT0, GL_TEXTURE_2D, renderTexture, 0);
|
|
||||||
// Set the list of draw buffers.
|
|
||||||
int[] drawBuffers = { GL30.GL_COLOR_ATTACHMENT0 };
|
|
||||||
GL30.glDrawBuffers(drawBuffers);
|
|
||||||
}
|
|
||||||
|
|
||||||
public void Bind() {
|
|
||||||
GL30.glBindFramebuffer(GL30.GL_FRAMEBUFFER, this.fbo);
|
|
||||||
glViewport(0, 0, this.width, this.height);
|
|
||||||
}
|
|
||||||
|
|
||||||
public void Unbind() {
|
|
||||||
GL30.glBindFramebuffer(GL30.GL_FRAMEBUFFER, 0);
|
|
||||||
}
|
|
||||||
|
|
||||||
public void Clear() {
|
|
||||||
glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT); // clear the framebuffer
|
|
||||||
}
|
|
||||||
|
|
||||||
public void Resize(int width, int height) {
|
|
||||||
this.width = width;
|
|
||||||
this.height = height;
|
|
||||||
|
|
||||||
GL30.glBindTexture(GL_TEXTURE_2D, this.renderTexture);
|
|
||||||
|
|
||||||
glTexImage2D(GL_TEXTURE_2D, 0, GL_RGB, this.width, this.height, 0, GL_RGB, GL_UNSIGNED_BYTE, 0);
|
|
||||||
|
|
||||||
GL30.glBindRenderbuffer(GL30.GL_RENDERBUFFER, this.depthBuffer);
|
|
||||||
GL30.glRenderbufferStorage(GL30.GL_RENDERBUFFER, GL_DEPTH_COMPONENT, this.width, this.height);
|
|
||||||
}
|
|
||||||
|
|
||||||
public void SetPixelScaling(boolean pixelated) {
|
|
||||||
glBindTexture(GL_TEXTURE_2D, renderTexture);
|
|
||||||
|
|
||||||
int method = pixelated ? GL30.GL_NEAREST : GL30.GL_LINEAR;
|
|
||||||
|
|
||||||
GL30.glTexParameteri(GL_TEXTURE_2D, GL30.GL_TEXTURE_MAG_FILTER, method);
|
|
||||||
GL30.glTexParameteri(GL_TEXTURE_2D, GL30.GL_TEXTURE_MIN_FILTER, method);
|
|
||||||
}
|
|
||||||
|
|
||||||
public float getAspectRatio() {
|
|
||||||
return (float) width / (float) height;
|
|
||||||
}
|
|
||||||
|
|
||||||
public int getWidth() {
|
|
||||||
return width;
|
|
||||||
}
|
|
||||||
|
|
||||||
public int getHeight() {
|
|
||||||
return height;
|
|
||||||
}
|
|
||||||
|
|
||||||
public int getRenderTexture() {
|
|
||||||
return renderTexture;
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
|
||||||
@@ -1,102 +0,0 @@
|
|||||||
package chess.view.DDDrender.shader;
|
|
||||||
|
|
||||||
import chess.view.DDDrender.Camera;
|
|
||||||
|
|
||||||
public class BoardShader extends ShaderProgram {
|
|
||||||
|
|
||||||
private static String vertexShader = """
|
|
||||||
#version 330
|
|
||||||
|
|
||||||
layout(location = 0) in vec3 position;
|
|
||||||
layout(location = 1) in vec3 color;
|
|
||||||
|
|
||||||
uniform mat4 viewMatrix;
|
|
||||||
uniform mat4 projectionMatrix;
|
|
||||||
uniform vec3 lightPosition = vec3(0, 10, 0);
|
|
||||||
|
|
||||||
flat out vec3 pass_color;
|
|
||||||
|
|
||||||
out vec3 toLightVector;
|
|
||||||
out vec3 toCameraVector;
|
|
||||||
out vec3 surfaceNormal;
|
|
||||||
|
|
||||||
void main(void){
|
|
||||||
const vec4 normal = vec4(0.0, 1.0, 0.0, 1.0);
|
|
||||||
|
|
||||||
gl_Position = projectionMatrix * viewMatrix * vec4(position, 1.0);
|
|
||||||
|
|
||||||
vec3 camPos = (inverse(viewMatrix) * vec4(0.0, 0.0, 0.0, 1.0)).xyz;
|
|
||||||
|
|
||||||
toLightVector = lightPosition - position;
|
|
||||||
|
|
||||||
toCameraVector = camPos - position;
|
|
||||||
surfaceNormal = (normal).xyz;
|
|
||||||
|
|
||||||
pass_color = color;
|
|
||||||
}
|
|
||||||
|
|
||||||
""";
|
|
||||||
|
|
||||||
private static String fragmentShader = """
|
|
||||||
#version 330
|
|
||||||
|
|
||||||
flat in vec3 pass_color;
|
|
||||||
|
|
||||||
in vec3 toLightVector;
|
|
||||||
in vec3 toCameraVector;
|
|
||||||
in vec3 surfaceNormal;
|
|
||||||
|
|
||||||
layout(location = 0) out vec4 out_color;
|
|
||||||
|
|
||||||
void main(void){
|
|
||||||
const float shineDamper = 10.0;
|
|
||||||
const float reflectivity = 1.0;
|
|
||||||
|
|
||||||
float lightDistance = length(toLightVector);
|
|
||||||
|
|
||||||
const vec3 attenuation = vec3(0.2, 0.1, 0.0);
|
|
||||||
float attenuationFactor = attenuation.x + attenuation.y * lightDistance + attenuation.z * lightDistance * lightDistance;
|
|
||||||
|
|
||||||
vec3 unitNormal = normalize(surfaceNormal);
|
|
||||||
vec3 unitLightVector = normalize(toLightVector);
|
|
||||||
vec3 unitCamVector = normalize(toCameraVector);
|
|
||||||
|
|
||||||
vec3 lightDirection = -unitLightVector;
|
|
||||||
vec3 reflectedLightDirection = reflect(lightDirection, unitNormal);
|
|
||||||
|
|
||||||
float diffuse = max(0.2, dot(unitNormal, unitLightVector));
|
|
||||||
|
|
||||||
float specularFactor = max(0.0, dot(reflectedLightDirection, unitCamVector));
|
|
||||||
float specular = pow(specularFactor, shineDamper) * reflectivity;
|
|
||||||
|
|
||||||
float brightness = (diffuse + specular) / attenuationFactor;
|
|
||||||
|
|
||||||
out_color = brightness * vec4(pass_color, 1.0);
|
|
||||||
out_color.w = 1.0;
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
""";
|
|
||||||
|
|
||||||
private int location_ProjectionMatrix = 0;
|
|
||||||
private int location_ViewMatrix = 0;
|
|
||||||
|
|
||||||
public BoardShader() {
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
public void LoadShader() {
|
|
||||||
super.LoadProgram(vertexShader, fragmentShader);
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
protected void GetAllUniformLocation() {
|
|
||||||
location_ProjectionMatrix = GetUniformLocation("projectionMatrix");
|
|
||||||
location_ViewMatrix = GetUniformLocation("viewMatrix");
|
|
||||||
}
|
|
||||||
|
|
||||||
public void SetCamMatrix(Camera camera) {
|
|
||||||
LoadMat4(location_ProjectionMatrix, camera.getPerspectiveMatrix());
|
|
||||||
LoadMat4(location_ViewMatrix, camera.getViewMatrix());
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -1,116 +0,0 @@
|
|||||||
package chess.view.DDDrender.shader;
|
|
||||||
|
|
||||||
import org.joml.Matrix4f;
|
|
||||||
import org.joml.Vector3f;
|
|
||||||
|
|
||||||
import chess.view.DDDrender.Camera;
|
|
||||||
|
|
||||||
public class PieceShader extends ShaderProgram {
|
|
||||||
|
|
||||||
private static String vertexShader = """
|
|
||||||
#version 330
|
|
||||||
|
|
||||||
layout(location = 0) in vec3 position;
|
|
||||||
layout(location = 1) in vec3 normal;
|
|
||||||
|
|
||||||
uniform mat4 projectionMatrix;
|
|
||||||
uniform mat4 viewMatrix;
|
|
||||||
uniform mat4 modelTransform;
|
|
||||||
uniform vec3 lightPosition = vec3(0, 10, 0);
|
|
||||||
|
|
||||||
out vec3 toLightVector;
|
|
||||||
out vec3 toCameraVector;
|
|
||||||
out vec3 surfaceNormal;
|
|
||||||
|
|
||||||
void main(void){
|
|
||||||
|
|
||||||
vec4 modelPos = modelTransform * vec4(position, 1.0);
|
|
||||||
vec4 globalNormal = modelTransform * vec4(normal, 1.0);
|
|
||||||
|
|
||||||
gl_Position = projectionMatrix * viewMatrix * modelPos;
|
|
||||||
|
|
||||||
vec3 camPos = (inverse(viewMatrix) * vec4(0.0, 0.0, 0.0, 1.0)).xyz;
|
|
||||||
|
|
||||||
toLightVector = lightPosition - modelPos.xyz;
|
|
||||||
|
|
||||||
toCameraVector = camPos - position;
|
|
||||||
surfaceNormal = normalize(globalNormal.xyz);
|
|
||||||
}
|
|
||||||
|
|
||||||
""";
|
|
||||||
|
|
||||||
private static String fragmentShader = """
|
|
||||||
#version 330
|
|
||||||
|
|
||||||
in vec3 toLightVector;
|
|
||||||
in vec3 toCameraVector;
|
|
||||||
in vec3 surfaceNormal;
|
|
||||||
|
|
||||||
uniform vec3 modelColor;
|
|
||||||
|
|
||||||
layout(location = 0) out vec4 out_color;
|
|
||||||
|
|
||||||
void main(void){
|
|
||||||
const float shineDamper = 10.0;
|
|
||||||
const float reflectivity = 1.0;
|
|
||||||
|
|
||||||
float lightDistance = length(toLightVector);
|
|
||||||
|
|
||||||
const vec3 attenuation = vec3(0.2, 0.1, 0.0);
|
|
||||||
float attenuationFactor = attenuation.x + attenuation.y * lightDistance + attenuation.z * lightDistance * lightDistance;
|
|
||||||
|
|
||||||
vec3 unitNormal = normalize(surfaceNormal);
|
|
||||||
vec3 unitLightVector = normalize(toLightVector);
|
|
||||||
vec3 unitCamVector = normalize(toCameraVector);
|
|
||||||
|
|
||||||
vec3 lightDirection = -unitLightVector;
|
|
||||||
vec3 reflectedLightDirection = reflect(lightDirection, unitNormal);
|
|
||||||
|
|
||||||
float diffuse = max(0.2, dot(unitNormal, unitLightVector));
|
|
||||||
|
|
||||||
float specularFactor = max(0.0, dot(reflectedLightDirection, unitCamVector));
|
|
||||||
float specular = pow(specularFactor, shineDamper) * reflectivity;
|
|
||||||
|
|
||||||
float brightness = (diffuse + specular) / attenuationFactor;
|
|
||||||
|
|
||||||
out_color = brightness * vec4(modelColor, 1.0);
|
|
||||||
out_color.w = 1.0;
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
""";
|
|
||||||
|
|
||||||
private int location_ProjectionMatrix = 0;
|
|
||||||
private int location_ViewMatrix = 0;
|
|
||||||
private int location_ModelTransform = 0;
|
|
||||||
private int location_ModelColor = 0;
|
|
||||||
|
|
||||||
public PieceShader() {
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
public void LoadShader() {
|
|
||||||
super.LoadProgram(vertexShader, fragmentShader);
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
protected void GetAllUniformLocation() {
|
|
||||||
location_ProjectionMatrix = GetUniformLocation("projectionMatrix");
|
|
||||||
location_ViewMatrix = GetUniformLocation("viewMatrix");
|
|
||||||
location_ModelTransform = GetUniformLocation("modelTransform");
|
|
||||||
location_ModelColor = GetUniformLocation("modelColor");
|
|
||||||
}
|
|
||||||
|
|
||||||
public void SetCamMatrix(Camera camera) {
|
|
||||||
LoadMat4(location_ProjectionMatrix, camera.getPerspectiveMatrix());
|
|
||||||
LoadMat4(location_ViewMatrix, camera.getViewMatrix());
|
|
||||||
}
|
|
||||||
|
|
||||||
public void setModelTransform(Matrix4f mat) {
|
|
||||||
LoadMat4(location_ModelTransform, mat);
|
|
||||||
}
|
|
||||||
|
|
||||||
public void setModelColor(Vector3f color) {
|
|
||||||
LoadVector(location_ModelColor, color);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -1,54 +0,0 @@
|
|||||||
package chess.view.DDDrender.world;
|
|
||||||
|
|
||||||
import java.io.IOException;
|
|
||||||
|
|
||||||
import org.joml.Matrix4f;
|
|
||||||
import org.joml.Vector3f;
|
|
||||||
|
|
||||||
import chess.model.Coordinate;
|
|
||||||
import chess.view.DDDrender.Renderer;
|
|
||||||
import chess.view.DDDrender.loader.BoardModelLoader;
|
|
||||||
import chess.view.DDDrender.opengl.VertexArray;
|
|
||||||
import chess.view.DDDrender.opengl.VertexBuffer;
|
|
||||||
|
|
||||||
public class BoardEntity extends Entity {
|
|
||||||
|
|
||||||
private final VertexArray vao;
|
|
||||||
private final VertexBuffer colorVbo;
|
|
||||||
|
|
||||||
private static final Vector3f WHITE = new Vector3f(1, 1, 1);
|
|
||||||
private static final Vector3f BLACK = new Vector3f(0, 0, 0);
|
|
||||||
|
|
||||||
public BoardEntity() {
|
|
||||||
this.vao = BoardModelLoader.GetBoardModel();
|
|
||||||
this.colorVbo = this.vao.getVertexBuffers().get(1);
|
|
||||||
}
|
|
||||||
|
|
||||||
public void setCellColor(Coordinate coord, Vector3f color) {
|
|
||||||
float[] data = { color.x, color.y, color.z, color.x, color.y, color.z, color.x, color.y, color.z, color.x,
|
|
||||||
color.y, color.z};
|
|
||||||
int cellNumber = (Coordinate.VALUE_MAX - 1 - coord.getX()) * Coordinate.VALUE_MAX + Coordinate.VALUE_MAX - 1 - coord.getY();
|
|
||||||
int offset = cellNumber * 4 * 4 * 3;
|
|
||||||
this.colorVbo.UpdateData(offset, data);
|
|
||||||
}
|
|
||||||
|
|
||||||
public void resetCellColor(Coordinate coord) {
|
|
||||||
setCellColor(coord, (coord.getX() + coord.getY()) % 2 == 0 ? WHITE : BLACK);
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public void render(Renderer renderer) {
|
|
||||||
renderer.RenderVao(renderer.getBoardShader(), vao);
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public void close() throws IOException {
|
|
||||||
vao.close();
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public Matrix4f getTransform() {
|
|
||||||
return null;
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
|
||||||
@@ -1,15 +0,0 @@
|
|||||||
package chess.view.DDDrender.world;
|
|
||||||
|
|
||||||
import java.io.Closeable;
|
|
||||||
|
|
||||||
import org.joml.Matrix4f;
|
|
||||||
|
|
||||||
import chess.view.DDDrender.Renderer;
|
|
||||||
|
|
||||||
public abstract class Entity implements Closeable{
|
|
||||||
|
|
||||||
public abstract void render(Renderer renderer);
|
|
||||||
|
|
||||||
public abstract Matrix4f getTransform();
|
|
||||||
|
|
||||||
}
|
|
||||||
@@ -1,61 +0,0 @@
|
|||||||
package chess.view.DDDrender.world;
|
|
||||||
|
|
||||||
import java.io.IOException;
|
|
||||||
|
|
||||||
import org.joml.Matrix4f;
|
|
||||||
import org.joml.Vector3f;
|
|
||||||
|
|
||||||
import chess.view.DDDrender.DDDModel;
|
|
||||||
import chess.view.DDDrender.Renderer;
|
|
||||||
|
|
||||||
public class ModelEntity extends Entity {
|
|
||||||
|
|
||||||
protected Vector3f position;
|
|
||||||
protected Vector3f color;
|
|
||||||
protected float rotation;
|
|
||||||
protected DDDModel model;
|
|
||||||
|
|
||||||
private Matrix4f transform;
|
|
||||||
|
|
||||||
public ModelEntity(DDDModel model, Vector3f position, Vector3f color, float rotation) {
|
|
||||||
this.position = position;
|
|
||||||
this.color = color;
|
|
||||||
this.rotation = rotation;
|
|
||||||
this.model = model;
|
|
||||||
updateTransform();
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public void render(Renderer renderer) {
|
|
||||||
renderer.Render(model, color, transform);
|
|
||||||
}
|
|
||||||
|
|
||||||
public void setPosition(Vector3f position) {
|
|
||||||
this.position = position;
|
|
||||||
updateTransform();
|
|
||||||
}
|
|
||||||
|
|
||||||
public void setColor(Vector3f color) {
|
|
||||||
this.color = color;
|
|
||||||
}
|
|
||||||
|
|
||||||
public void setRotation(float rotation) {
|
|
||||||
this.rotation = rotation;
|
|
||||||
updateTransform();
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public void close() throws IOException {
|
|
||||||
this.model.close();
|
|
||||||
}
|
|
||||||
|
|
||||||
private void updateTransform() {
|
|
||||||
this.transform = new Matrix4f().translate(this.position).rotate(this.rotation, new Vector3f(0, 1, 0));
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public Matrix4f getTransform() {
|
|
||||||
return transform;
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
|
||||||
@@ -1,25 +0,0 @@
|
|||||||
package chess.view.DDDrender.world;
|
|
||||||
|
|
||||||
import java.io.IOException;
|
|
||||||
|
|
||||||
import org.joml.Vector3f;
|
|
||||||
|
|
||||||
import chess.model.Piece;
|
|
||||||
import chess.view.DDDrender.loader.Piece3DModel;
|
|
||||||
|
|
||||||
public class PieceEntity extends ModelEntity {
|
|
||||||
|
|
||||||
private static final Piece3DModel modelLoader = new Piece3DModel();
|
|
||||||
|
|
||||||
private final Piece piece;
|
|
||||||
|
|
||||||
public PieceEntity(Piece piece, Vector3f position, Vector3f color, float rotation) throws IOException {
|
|
||||||
super(modelLoader.getModel(piece), position, color, rotation);
|
|
||||||
this.piece = piece;
|
|
||||||
}
|
|
||||||
|
|
||||||
public Piece getPiece() {
|
|
||||||
return piece;
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
|
||||||
@@ -1,74 +0,0 @@
|
|||||||
package chess.view.DDDrender.world;
|
|
||||||
|
|
||||||
import java.io.Closeable;
|
|
||||||
import java.io.IOException;
|
|
||||||
import java.util.ArrayList;
|
|
||||||
import java.util.List;
|
|
||||||
|
|
||||||
import chess.model.Coordinate;
|
|
||||||
import chess.model.Move;
|
|
||||||
import chess.model.Piece;
|
|
||||||
|
|
||||||
public class World implements Closeable{
|
|
||||||
/** Renderable entity list */
|
|
||||||
private final List<Entity> entites;
|
|
||||||
|
|
||||||
/** provides fast access to 3d pieces */
|
|
||||||
private final PieceEntity[] pieces;
|
|
||||||
|
|
||||||
public World() {
|
|
||||||
this.entites = new ArrayList<>();
|
|
||||||
this.pieces = new PieceEntity[Coordinate.VALUE_MAX * Coordinate.VALUE_MAX];
|
|
||||||
}
|
|
||||||
|
|
||||||
public PieceEntity getEntity(Piece piece) {
|
|
||||||
for (Entity entity : entites) {
|
|
||||||
if (entity instanceof PieceEntity p) {
|
|
||||||
if (p.getPiece() == piece)
|
|
||||||
return p;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return null;
|
|
||||||
}
|
|
||||||
|
|
||||||
public void addPiece(PieceEntity entity, Coordinate coordinate) {
|
|
||||||
addEntity(entity);
|
|
||||||
setPieceCoords(entity, coordinate);
|
|
||||||
}
|
|
||||||
|
|
||||||
private void setPieceCoords(PieceEntity entity, Coordinate coordinate) {
|
|
||||||
pieces[coordinate.toIndex()] = entity;
|
|
||||||
}
|
|
||||||
|
|
||||||
public void movePiece(PieceEntity entity, Move move) {
|
|
||||||
setPieceCoords(entity, move.getFinish());
|
|
||||||
setPieceCoords(null, move.getStart());
|
|
||||||
}
|
|
||||||
|
|
||||||
public void ejectPiece(Coordinate coordinate) {
|
|
||||||
PieceEntity entity = getPiece(coordinate);
|
|
||||||
if (entity != null)
|
|
||||||
this.entites.remove(entity);
|
|
||||||
setPieceCoords(null, coordinate);
|
|
||||||
}
|
|
||||||
|
|
||||||
public PieceEntity getPiece(Coordinate coordinate) {
|
|
||||||
return pieces[coordinate.toIndex()];
|
|
||||||
}
|
|
||||||
|
|
||||||
public void addEntity(Entity entity) {
|
|
||||||
this.entites.add(entity);
|
|
||||||
}
|
|
||||||
|
|
||||||
public List<Entity> getEntites() {
|
|
||||||
return entites;
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public void close() throws IOException {
|
|
||||||
for (Entity entity : entites) {
|
|
||||||
entity.close();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
|
||||||
@@ -20,17 +20,12 @@ public class Console implements GameListener {
|
|||||||
private final Scanner scanner = new Scanner(System.in);
|
private final Scanner scanner = new Scanner(System.in);
|
||||||
private final CommandExecutor commandExecutor;
|
private final CommandExecutor commandExecutor;
|
||||||
private final ConsolePieceName consolePieceName = new ConsolePieceName();
|
private final ConsolePieceName consolePieceName = new ConsolePieceName();
|
||||||
private boolean captureInput;
|
private boolean captureInput = false;
|
||||||
private final ExecutorService executor;
|
private final ExecutorService executor;
|
||||||
|
|
||||||
public Console(CommandExecutor commandExecutor, boolean captureInput) {
|
public Console(CommandExecutor commandExecutor) {
|
||||||
this.commandExecutor = commandExecutor;
|
this.commandExecutor = commandExecutor;
|
||||||
this.executor = Executors.newSingleThreadExecutor();
|
this.executor = Executors.newSingleThreadExecutor();
|
||||||
this.captureInput = captureInput;
|
|
||||||
}
|
|
||||||
|
|
||||||
public Console(CommandExecutor commandExecutor) {
|
|
||||||
this(commandExecutor, true);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
private Piece pieceAt(int x, int y) {
|
private Piece pieceAt(int x, int y) {
|
||||||
@@ -66,7 +61,7 @@ public class Console implements GameListener {
|
|||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void onPlayerTurn(Color color, boolean undone) {
|
public void onPlayerTurn(Color color) {
|
||||||
if (!captureInput)
|
if (!captureInput)
|
||||||
return;
|
return;
|
||||||
System.out.println(Colors.RED + "Player turn: " + color + Colors.RESET);
|
System.out.println(Colors.RED + "Player turn: " + color + Colors.RESET);
|
||||||
|
|||||||
128
app/src/main/java/chess/view/render/Camera.java
Normal file
128
app/src/main/java/chess/view/render/Camera.java
Normal file
@@ -0,0 +1,128 @@
|
|||||||
|
package chess.view.render;
|
||||||
|
|
||||||
|
import org.joml.Matrix4f;
|
||||||
|
import org.joml.Vector3f;
|
||||||
|
|
||||||
|
public class Camera {
|
||||||
|
public static final float fov = 70.0f;
|
||||||
|
// should be changed to match screen
|
||||||
|
public static final float aspect = 1.0f;
|
||||||
|
public static final float zNear = 0.01f;
|
||||||
|
public static final float zFar = 100.0f;
|
||||||
|
|
||||||
|
private Vector3f pos;
|
||||||
|
|
||||||
|
private float yaw = 0.0f;
|
||||||
|
private float pitch = 0.0f;
|
||||||
|
|
||||||
|
public Camera() {
|
||||||
|
this.pos = new Vector3f(0, 2.0f, 0);
|
||||||
|
setRotation(0.0f, -3.14150f / 2.0f);
|
||||||
|
}
|
||||||
|
|
||||||
|
public void move(float x, float y) {
|
||||||
|
this.pos.x += x;
|
||||||
|
this.pos.y += y;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void rotate(float yaw, float pitch) {
|
||||||
|
this.yaw += yaw;
|
||||||
|
this.pitch += pitch;
|
||||||
|
}
|
||||||
|
|
||||||
|
public Vector3f getPos() {
|
||||||
|
return pos;
|
||||||
|
}
|
||||||
|
|
||||||
|
public float getYaw() {
|
||||||
|
return yaw;
|
||||||
|
}
|
||||||
|
|
||||||
|
public float getPitch() {
|
||||||
|
return pitch;
|
||||||
|
}
|
||||||
|
|
||||||
|
public float getFov() {
|
||||||
|
return fov;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setX(float x) {
|
||||||
|
this.pos.x = x;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setY(float y) {
|
||||||
|
this.pos.y = y;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setZ(float z) {
|
||||||
|
this.pos.z = z;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setYaw(float yaw) {
|
||||||
|
this.yaw = yaw;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setPitch(float pitch) {
|
||||||
|
this.pitch = pitch;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void reset() {
|
||||||
|
resetPosition();
|
||||||
|
resetRotation();
|
||||||
|
}
|
||||||
|
|
||||||
|
public void resetPosition() {
|
||||||
|
pos = new Vector3f(0.0f, 0.0f, 0.0f);
|
||||||
|
}
|
||||||
|
|
||||||
|
public void resetRotation() {
|
||||||
|
yaw = 0.0f;
|
||||||
|
pitch = 0.0f;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void moveForward(float distance) {
|
||||||
|
pos.x += distance * (float) Math.cos(yaw);
|
||||||
|
pos.y += distance * (float) Math.sin(yaw);
|
||||||
|
}
|
||||||
|
|
||||||
|
public void moveRight(float distance) {
|
||||||
|
pos.x += distance * (float) Math.cos(yaw);
|
||||||
|
pos.y += distance * (float) Math.sin(yaw);
|
||||||
|
}
|
||||||
|
|
||||||
|
public void moveUp(float distance) {
|
||||||
|
pos.z += distance;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void moveDown(float distance) {
|
||||||
|
pos.z -= distance;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void addYaw(float angle) {
|
||||||
|
yaw += angle;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void addPitch(float angle) {
|
||||||
|
pitch += angle;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setPosition(Vector3f pos) {
|
||||||
|
this.pos = pos;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setRotation(float yaw, float pitch) {
|
||||||
|
this.yaw = yaw;
|
||||||
|
this.pitch = pitch;
|
||||||
|
}
|
||||||
|
|
||||||
|
public Matrix4f getMatrix() {
|
||||||
|
Vector3f forward = new Vector3f(
|
||||||
|
(float) (Math.cos(yaw) * Math.cos(pitch)),
|
||||||
|
(float) (Math.sin(pitch)),
|
||||||
|
(float) (Math.sin(yaw) * Math.cos(pitch)));
|
||||||
|
|
||||||
|
return new Matrix4f()
|
||||||
|
.perspective((float) (Math.toRadians(fov)), aspect, zNear, zFar)
|
||||||
|
.lookAt(pos, forward, new Vector3f(0.0f, 1.0f, 0.0f));
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -1,13 +1,10 @@
|
|||||||
package chess.view.DDDrender.opengl;
|
package chess.view.render;
|
||||||
|
|
||||||
import java.io.Closeable;
|
|
||||||
import java.io.IOException;
|
|
||||||
|
|
||||||
import org.lwjgl.opengl.GL30;
|
import org.lwjgl.opengl.GL30;
|
||||||
|
|
||||||
public class ElementBuffer implements Closeable {
|
public class ElementBuffer {
|
||||||
private final int id;
|
private int id;
|
||||||
private final int indiciesCount;
|
private int indiciesCount;
|
||||||
|
|
||||||
public ElementBuffer(int[] indicies) {
|
public ElementBuffer(int[] indicies) {
|
||||||
this.indiciesCount = indicies.length;
|
this.indiciesCount = indicies.length;
|
||||||
@@ -18,6 +15,10 @@ public class ElementBuffer implements Closeable {
|
|||||||
Unbind();
|
Unbind();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public void Destroy() {
|
||||||
|
GL30.glDeleteBuffers(this.id);
|
||||||
|
}
|
||||||
|
|
||||||
public void Bind() {
|
public void Bind() {
|
||||||
GL30.glBindBuffer(GL30.GL_ELEMENT_ARRAY_BUFFER, this.id);
|
GL30.glBindBuffer(GL30.GL_ELEMENT_ARRAY_BUFFER, this.id);
|
||||||
}
|
}
|
||||||
@@ -29,9 +30,4 @@ public class ElementBuffer implements Closeable {
|
|||||||
public int GetIndiciesCount() {
|
public int GetIndiciesCount() {
|
||||||
return this.indiciesCount;
|
return this.indiciesCount;
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
|
||||||
public void close() throws IOException {
|
|
||||||
GL30.glDeleteBuffers(this.id);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
157
app/src/main/java/chess/view/render/Renderer.java
Normal file
157
app/src/main/java/chess/view/render/Renderer.java
Normal file
@@ -0,0 +1,157 @@
|
|||||||
|
package chess.view.render;
|
||||||
|
|
||||||
|
import org.joml.Vector3f;
|
||||||
|
import org.lwjgl.opengl.*;
|
||||||
|
|
||||||
|
import chess.model.Coordinate;
|
||||||
|
import chess.view.render.shader.BoardShader;
|
||||||
|
|
||||||
|
import static org.lwjgl.opengl.GL30.*;
|
||||||
|
|
||||||
|
public class Renderer {
|
||||||
|
private BoardShader shader;
|
||||||
|
private VertexArray vao;
|
||||||
|
|
||||||
|
private static int BOARD_WIDTH = 8;
|
||||||
|
private static int BOARD_HEIGHT = 8;
|
||||||
|
private static int BOARD_SIZE = BOARD_WIDTH * BOARD_HEIGHT;
|
||||||
|
private static int SQUARE_VERTEX_COUNT = 4;
|
||||||
|
|
||||||
|
public Renderer() {
|
||||||
|
this.shader = new BoardShader();
|
||||||
|
}
|
||||||
|
|
||||||
|
public void Init() {
|
||||||
|
shader.LoadShader();
|
||||||
|
InitBoard();
|
||||||
|
}
|
||||||
|
|
||||||
|
private float[] GetBoardPositions() {
|
||||||
|
float[] positions = new float[BOARD_SIZE * SQUARE_VERTEX_COUNT * 3];
|
||||||
|
for (int i = 0; i < BOARD_WIDTH; i++) {
|
||||||
|
for (int j = 0; j < BOARD_HEIGHT; j++) {
|
||||||
|
float x = i / (float) BOARD_WIDTH;
|
||||||
|
float dx = (i + 1) / (float) BOARD_WIDTH;
|
||||||
|
float z = j / (float) BOARD_HEIGHT;
|
||||||
|
float dz = (j + 1) / (float) BOARD_HEIGHT;
|
||||||
|
|
||||||
|
float trueX = 2 * x - 1;
|
||||||
|
float trueZ = 2 * z - 1;
|
||||||
|
float trueDX = 2 * dx - 1;
|
||||||
|
float trueDZ = 2 * dz - 1;
|
||||||
|
|
||||||
|
positions[(BOARD_WIDTH * i + j) * SQUARE_VERTEX_COUNT * 3] = trueX;
|
||||||
|
positions[(BOARD_WIDTH * i + j) * SQUARE_VERTEX_COUNT * 3 + 1] = 0.0f;
|
||||||
|
positions[(BOARD_WIDTH * i + j) * SQUARE_VERTEX_COUNT * 3 + 2] = trueZ;
|
||||||
|
|
||||||
|
positions[(BOARD_WIDTH * i + j) * SQUARE_VERTEX_COUNT * 3 + 3] = trueDX;
|
||||||
|
positions[(BOARD_WIDTH * i + j) * SQUARE_VERTEX_COUNT * 3 + 4] = 0.0f;
|
||||||
|
positions[(BOARD_WIDTH * i + j) * SQUARE_VERTEX_COUNT * 3 + 5] = trueZ;
|
||||||
|
|
||||||
|
positions[(BOARD_WIDTH * i + j) * SQUARE_VERTEX_COUNT * 3 + 6] = trueX;
|
||||||
|
positions[(BOARD_WIDTH * i + j) * SQUARE_VERTEX_COUNT * 3 + 7] = 0.0f;
|
||||||
|
positions[(BOARD_WIDTH * i + j) * SQUARE_VERTEX_COUNT * 3 + 8] = trueDZ;
|
||||||
|
|
||||||
|
positions[(BOARD_WIDTH * i + j) * SQUARE_VERTEX_COUNT * 3 + 9] = trueDX;
|
||||||
|
positions[(BOARD_WIDTH * i + j) * SQUARE_VERTEX_COUNT * 3 + 10] = 0.0f;
|
||||||
|
positions[(BOARD_WIDTH * i + j) * SQUARE_VERTEX_COUNT * 3 + 11] = trueDZ;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return positions;
|
||||||
|
}
|
||||||
|
|
||||||
|
private Coordinate GetCellFromColor(Vector3f color) {
|
||||||
|
int offset = 1;
|
||||||
|
|
||||||
|
if (color.x > 0.5) {
|
||||||
|
color = new Vector3f(1.0f, 1.0f, 1.0f).sub(color);
|
||||||
|
offset = 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
int r = (int) (color.x * 255.0f);
|
||||||
|
int g = (int) (color.y * 255.0f);
|
||||||
|
int b = (int) (color.z * 255.0f);
|
||||||
|
|
||||||
|
int index = (r + g + b) * 2 + offset;
|
||||||
|
|
||||||
|
return Coordinate.fromIndex(index);
|
||||||
|
}
|
||||||
|
|
||||||
|
private Vector3f GetCellColor(int x, int y) {
|
||||||
|
float index = (y * BOARD_WIDTH + x) / 2.0f;
|
||||||
|
float r = (int) (index / 3) / 255.0f;
|
||||||
|
float g = (int) ((index + 1) / 3) / 255.0f;
|
||||||
|
float b = (int) ((index + 2) / 3) / 255.0f;
|
||||||
|
if ((x + y) % 2 != 0) {
|
||||||
|
System.out.println(GetCellFromColor(new Vector3f(1.0f - r - 1.0f / 255.0f, 1.0f - g - 1.0f / 255.0f, 1.0f - b - 1.0f / 255.0f)));
|
||||||
|
return new Vector3f(1.0f - r - 1.0f / 255.0f, 1.0f - g - 1.0f / 255.0f, 1.0f - b - 1.0f / 255.0f);
|
||||||
|
} else {
|
||||||
|
System.out.println(GetCellFromColor(new Vector3f(r, g, b)));
|
||||||
|
return new Vector3f(r, g, b);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private float[] GetBoardColors() {
|
||||||
|
float[] colors = new float[BOARD_SIZE * SQUARE_VERTEX_COUNT * 3];
|
||||||
|
for (int j = 0; j < BOARD_HEIGHT; j++) {
|
||||||
|
for (int i = 0; i < BOARD_WIDTH; i++) {
|
||||||
|
Vector3f color = GetCellColor(i, j);
|
||||||
|
int squareIndex = i * BOARD_WIDTH + j;
|
||||||
|
for (int k = 0; k < SQUARE_VERTEX_COUNT; k++) {
|
||||||
|
colors[squareIndex * SQUARE_VERTEX_COUNT * 3 + k * 3] = color.x;
|
||||||
|
colors[squareIndex * SQUARE_VERTEX_COUNT * 3 + k * 3 + 1] = color.y;
|
||||||
|
colors[squareIndex * SQUARE_VERTEX_COUNT * 3 + k * 3 + 2] = color.z;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return colors;
|
||||||
|
}
|
||||||
|
|
||||||
|
private int[] GetBoardIndicies() {
|
||||||
|
int[] indices = new int[BOARD_SIZE * 6];
|
||||||
|
for (int i = 0; i < BOARD_SIZE; i++) {
|
||||||
|
indices[i * 6] = i * 4;
|
||||||
|
indices[i * 6 + 1] = i * 4 + 1;
|
||||||
|
indices[i * 6 + 2] = i * 4 + 2;
|
||||||
|
indices[i * 6 + 3] = i * 4 + 1;
|
||||||
|
indices[i * 6 + 4] = i * 4 + 2;
|
||||||
|
indices[i * 6 + 5] = i * 4 + 3;
|
||||||
|
}
|
||||||
|
return indices;
|
||||||
|
}
|
||||||
|
|
||||||
|
private void InitBoard() {
|
||||||
|
ElementBuffer eBuffer = new ElementBuffer(GetBoardIndicies());
|
||||||
|
this.vao = new VertexArray(eBuffer);
|
||||||
|
|
||||||
|
VertexBuffer positionBuffer = new VertexBuffer(GetBoardPositions(), 3);
|
||||||
|
positionBuffer.AddVertexAttribPointer(0, 3, 0);
|
||||||
|
|
||||||
|
VertexBuffer colorBuffer = new VertexBuffer(GetBoardColors(), 3);
|
||||||
|
colorBuffer.AddVertexAttribPointer(1, 3, 0);
|
||||||
|
|
||||||
|
this.vao.Bind();
|
||||||
|
this.vao.BindVertexBuffer(positionBuffer);
|
||||||
|
this.vao.BindVertexBuffer(colorBuffer);
|
||||||
|
this.vao.Unbind();
|
||||||
|
}
|
||||||
|
|
||||||
|
public Coordinate GetSelectedCell() {
|
||||||
|
float pixels[] = new float[3];
|
||||||
|
GL30.glReadPixels(500, 500, 1, 1, GL_RGB, GL_FLOAT, pixels);
|
||||||
|
return GetCellFromColor(new Vector3f(pixels[0], pixels[1], pixels[2]));
|
||||||
|
}
|
||||||
|
|
||||||
|
public void Render(Camera cam) {
|
||||||
|
this.shader.Start();
|
||||||
|
this.shader.SetCamMatrix(cam.getMatrix());
|
||||||
|
RenderVao(vao);
|
||||||
|
}
|
||||||
|
|
||||||
|
public void RenderVao(VertexArray vertexArray) {
|
||||||
|
this.shader.Start();
|
||||||
|
vertexArray.Bind();
|
||||||
|
GL30.glDrawElements(GL30.GL_TRIANGLES, vertexArray.GetVertexCount(), GL_UNSIGNED_INT, 0);
|
||||||
|
vertexArray.Unbind();
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -1,17 +1,14 @@
|
|||||||
package chess.view.DDDrender.opengl;
|
package chess.view.render;
|
||||||
|
|
||||||
import java.io.Closeable;
|
|
||||||
import java.io.IOException;
|
|
||||||
import java.util.ArrayList;
|
import java.util.ArrayList;
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
|
|
||||||
import org.lwjgl.opengl.GL30;
|
import org.lwjgl.opengl.GL30;
|
||||||
|
|
||||||
public class VertexArray implements Closeable {
|
public class VertexArray {
|
||||||
|
private int id;
|
||||||
private final int id;
|
private ElementBuffer elementBuffer;
|
||||||
private final ElementBuffer elementBuffer;
|
private List<VertexBuffer> vertexBuffers;
|
||||||
private final List<VertexBuffer> vertexBuffers;
|
|
||||||
|
|
||||||
public VertexArray(ElementBuffer elementBuffer) {
|
public VertexArray(ElementBuffer elementBuffer) {
|
||||||
this.id = GL30.glGenVertexArrays();
|
this.id = GL30.glGenVertexArrays();
|
||||||
@@ -22,6 +19,10 @@ public class VertexArray implements Closeable {
|
|||||||
Unbind();
|
Unbind();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public void Destroy() {
|
||||||
|
GL30.glDeleteBuffers(this.id);
|
||||||
|
}
|
||||||
|
|
||||||
public int GetVertexCount() {
|
public int GetVertexCount() {
|
||||||
return this.elementBuffer.GetIndiciesCount();
|
return this.elementBuffer.GetIndiciesCount();
|
||||||
}
|
}
|
||||||
@@ -43,17 +44,4 @@ public class VertexArray implements Closeable {
|
|||||||
private void BindElementArrayBuffer() {
|
private void BindElementArrayBuffer() {
|
||||||
this.elementBuffer.Bind();
|
this.elementBuffer.Bind();
|
||||||
}
|
}
|
||||||
|
|
||||||
public List<VertexBuffer> getVertexBuffers() {
|
|
||||||
return vertexBuffers;
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public void close() throws IOException {
|
|
||||||
GL30.glDeleteBuffers(this.id);
|
|
||||||
for (VertexBuffer vertexBuffer : vertexBuffers) {
|
|
||||||
vertexBuffer.close();
|
|
||||||
}
|
|
||||||
elementBuffer.close();
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
@@ -1,4 +1,4 @@
|
|||||||
package chess.view.DDDrender.opengl;
|
package chess.view.render;
|
||||||
|
|
||||||
public record VertexAttribPointer(int index, int size, int offset) {
|
public record VertexAttribPointer(int index, int size, int offset) {
|
||||||
|
|
||||||
@@ -1,18 +1,16 @@
|
|||||||
package chess.view.DDDrender.opengl;
|
package chess.view.render;
|
||||||
|
|
||||||
import static org.lwjgl.opengl.GL11.GL_FLOAT;
|
import static org.lwjgl.opengl.GL11.GL_FLOAT;
|
||||||
|
|
||||||
import java.io.Closeable;
|
|
||||||
import java.io.IOException;
|
|
||||||
import java.util.ArrayList;
|
import java.util.ArrayList;
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
|
|
||||||
import org.lwjgl.opengl.GL30;
|
import org.lwjgl.opengl.GL30;
|
||||||
|
|
||||||
public class VertexBuffer implements Closeable {
|
public class VertexBuffer {
|
||||||
private final int id;
|
private int id;
|
||||||
private final int dataStride;
|
private int dataStride;
|
||||||
private final List<VertexAttribPointer> vertexAttribs;
|
List<VertexAttribPointer> vertexAttribs;
|
||||||
|
|
||||||
public VertexBuffer(float[] data, int stride) {
|
public VertexBuffer(float[] data, int stride) {
|
||||||
this.id = GL30.glGenBuffers();
|
this.id = GL30.glGenBuffers();
|
||||||
@@ -24,10 +22,8 @@ public class VertexBuffer implements Closeable {
|
|||||||
Unbind();
|
Unbind();
|
||||||
}
|
}
|
||||||
|
|
||||||
public void UpdateData(int offset, float[] data) {
|
public void Destroy() {
|
||||||
Bind();
|
GL30.glDeleteBuffers(id);
|
||||||
GL30.glBufferSubData(GL30.GL_ARRAY_BUFFER, offset, data);
|
|
||||||
Unbind();
|
|
||||||
}
|
}
|
||||||
|
|
||||||
public void Bind() {
|
public void Bind() {
|
||||||
@@ -50,9 +46,4 @@ public class VertexBuffer implements Closeable {
|
|||||||
this.dataStride * 4, vertexAttribPointer.offset());
|
this.dataStride * 4, vertexAttribPointer.offset());
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
|
||||||
public void close() throws IOException {
|
|
||||||
GL30.glDeleteBuffers(id);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
224
app/src/main/java/chess/view/render/Window.java
Normal file
224
app/src/main/java/chess/view/render/Window.java
Normal file
@@ -0,0 +1,224 @@
|
|||||||
|
package chess.view.render;
|
||||||
|
|
||||||
|
import org.lwjgl.*;
|
||||||
|
import org.lwjgl.glfw.*;
|
||||||
|
import org.lwjgl.opengl.*;
|
||||||
|
import org.lwjgl.system.*;
|
||||||
|
|
||||||
|
import chess.controller.CommandExecutor;
|
||||||
|
import chess.controller.event.GameListener;
|
||||||
|
import chess.model.Color;
|
||||||
|
import chess.model.Coordinate;
|
||||||
|
import chess.model.Move;
|
||||||
|
|
||||||
|
import java.nio.*;
|
||||||
|
|
||||||
|
import static org.lwjgl.glfw.Callbacks.*;
|
||||||
|
import static org.lwjgl.glfw.GLFW.*;
|
||||||
|
import static org.lwjgl.opengl.GL11.*;
|
||||||
|
import static org.lwjgl.system.MemoryStack.*;
|
||||||
|
import static org.lwjgl.system.MemoryUtil.*;
|
||||||
|
|
||||||
|
public class Window implements GameListener{
|
||||||
|
|
||||||
|
// The window handle
|
||||||
|
private long window;
|
||||||
|
|
||||||
|
private final CommandExecutor commandExecutor;
|
||||||
|
|
||||||
|
private Renderer renderer;
|
||||||
|
private Camera cam;
|
||||||
|
|
||||||
|
public Window(CommandExecutor commandExecutor) {
|
||||||
|
this.renderer = new Renderer();
|
||||||
|
this.cam = new Camera();
|
||||||
|
this.commandExecutor = new CommandExecutor();
|
||||||
|
}
|
||||||
|
|
||||||
|
public void run() {
|
||||||
|
System.out.println("LWJGL " + Version.getVersion() + "!");
|
||||||
|
|
||||||
|
init();
|
||||||
|
loop();
|
||||||
|
|
||||||
|
// Free the window callbacks and destroy the window
|
||||||
|
glfwFreeCallbacks(window);
|
||||||
|
glfwDestroyWindow(window);
|
||||||
|
|
||||||
|
// Terminate GLFW and free the error callback
|
||||||
|
glfwTerminate();
|
||||||
|
glfwSetErrorCallback(null).free();
|
||||||
|
}
|
||||||
|
|
||||||
|
private void init() {
|
||||||
|
// Setup an error callback. The default implementation
|
||||||
|
// will print the error message in System.err.
|
||||||
|
GLFWErrorCallback.createPrint(System.err).set();
|
||||||
|
|
||||||
|
// Initialize GLFW. Most GLFW functions will not work before doing this.
|
||||||
|
if (!glfwInit())
|
||||||
|
throw new IllegalStateException("Unable to initialize GLFW");
|
||||||
|
|
||||||
|
// Configure GLFW
|
||||||
|
glfwDefaultWindowHints(); // optional, the current window hints are already the default
|
||||||
|
glfwWindowHint(GLFW_VISIBLE, GLFW_FALSE); // the window will stay hidden after creation
|
||||||
|
glfwWindowHint(GLFW_RESIZABLE, GLFW_TRUE); // the window will be resizable
|
||||||
|
|
||||||
|
// Create the window
|
||||||
|
window = glfwCreateWindow(1000, 1000, "3DChess", NULL, NULL);
|
||||||
|
if (window == NULL)
|
||||||
|
throw new RuntimeException("Failed to create the GLFW window");
|
||||||
|
|
||||||
|
// Get the thread stack and push a new frame
|
||||||
|
try (MemoryStack stack = stackPush()) {
|
||||||
|
IntBuffer pWidth = stack.mallocInt(1); // int*
|
||||||
|
IntBuffer pHeight = stack.mallocInt(1); // int*
|
||||||
|
|
||||||
|
// Get the window size passed to glfwCreateWindow
|
||||||
|
glfwGetWindowSize(window, pWidth, pHeight);
|
||||||
|
|
||||||
|
// Get the resolution of the primary monitor
|
||||||
|
GLFWVidMode vidmode = glfwGetVideoMode(glfwGetPrimaryMonitor());
|
||||||
|
|
||||||
|
// Center the window
|
||||||
|
glfwSetWindowPos(
|
||||||
|
window,
|
||||||
|
(vidmode.width() - pWidth.get(0)) / 2,
|
||||||
|
(vidmode.height() - pHeight.get(0)) / 2);
|
||||||
|
} // the stack frame is popped automatically
|
||||||
|
|
||||||
|
// Make the OpenGL context current
|
||||||
|
glfwMakeContextCurrent(window);
|
||||||
|
// Enable v-sync
|
||||||
|
glfwSwapInterval(1);
|
||||||
|
|
||||||
|
// Make the window visible
|
||||||
|
glfwShowWindow(window);
|
||||||
|
}
|
||||||
|
|
||||||
|
private void render() {
|
||||||
|
cam.rotate(0.01f, 0.01f);
|
||||||
|
renderer.Render(cam);
|
||||||
|
}
|
||||||
|
|
||||||
|
private void loop() {
|
||||||
|
// This line is critical for LWJGL's interoperation with GLFW's
|
||||||
|
// OpenGL context, or any context that is managed externally.
|
||||||
|
// LWJGL detects the context that is current in the current thread,
|
||||||
|
// creates the GLCapabilities instance and makes the OpenGL
|
||||||
|
// bindings available for use.
|
||||||
|
GL.createCapabilities();
|
||||||
|
|
||||||
|
renderer.Init();
|
||||||
|
|
||||||
|
// Set the clear color
|
||||||
|
glClearColor(0.0f, 0.0f, 0.0f, 0.0f);
|
||||||
|
|
||||||
|
glColor4f(1.0f, 0.0f, 0.0f, 1.0f);
|
||||||
|
|
||||||
|
// Run the rendering loop until the user has attempted to close
|
||||||
|
// the window or has pressed the ESCAPE key.
|
||||||
|
while (!glfwWindowShouldClose(window)) {
|
||||||
|
glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT); // clear the framebuffer
|
||||||
|
|
||||||
|
render();
|
||||||
|
|
||||||
|
System.out.println(this.renderer.GetSelectedCell());
|
||||||
|
|
||||||
|
glfwSwapBuffers(window); // swap the color buffers
|
||||||
|
|
||||||
|
// Poll for window events. The key callback above will only be
|
||||||
|
// invoked during this call.
|
||||||
|
glfwPollEvents();
|
||||||
|
|
||||||
|
try (MemoryStack stack = stackPush()) {
|
||||||
|
IntBuffer pWidth = stack.mallocInt(1); // int*
|
||||||
|
IntBuffer pHeight = stack.mallocInt(1); // int*
|
||||||
|
|
||||||
|
// Get the window size passed to glfwCreateWindow
|
||||||
|
glfwGetWindowSize(window, pWidth, pHeight);
|
||||||
|
|
||||||
|
glViewport(0, 0, pWidth.get(), pHeight.get());
|
||||||
|
} // the stack frame is popped automatically
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void onBoardUpdate() {
|
||||||
|
// TODO Auto-generated method stub
|
||||||
|
throw new UnsupportedOperationException("Unimplemented method 'onBoardUpdate'");
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void onDraw() {
|
||||||
|
// TODO Auto-generated method stub
|
||||||
|
throw new UnsupportedOperationException("Unimplemented method 'onDraw'");
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void onGameEnd() {
|
||||||
|
// TODO Auto-generated method stub
|
||||||
|
throw new UnsupportedOperationException("Unimplemented method 'onGameEnd'");
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void onGameStart() {
|
||||||
|
// TODO Auto-generated method stub
|
||||||
|
throw new UnsupportedOperationException("Unimplemented method 'onGameStart'");
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void onKingInCheck() {
|
||||||
|
// TODO Auto-generated method stub
|
||||||
|
throw new UnsupportedOperationException("Unimplemented method 'onKingInCheck'");
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void onKingInMat() {
|
||||||
|
// TODO Auto-generated method stub
|
||||||
|
throw new UnsupportedOperationException("Unimplemented method 'onKingInMat'");
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void onMove(Move move) {
|
||||||
|
// TODO Auto-generated method stub
|
||||||
|
throw new UnsupportedOperationException("Unimplemented method 'onMove'");
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void onMoveNotAllowed(Move move) {
|
||||||
|
// TODO Auto-generated method stub
|
||||||
|
throw new UnsupportedOperationException("Unimplemented method 'onMoveNotAllowed'");
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void onPatSituation() {
|
||||||
|
// TODO Auto-generated method stub
|
||||||
|
throw new UnsupportedOperationException("Unimplemented method 'onPatSituation'");
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void onPlayerTurn(Color color) {
|
||||||
|
// TODO Auto-generated method stub
|
||||||
|
throw new UnsupportedOperationException("Unimplemented method 'onPlayerTurn'");
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void onPromotePawn(Coordinate pieceCoords) {
|
||||||
|
// TODO Auto-generated method stub
|
||||||
|
throw new UnsupportedOperationException("Unimplemented method 'onPromotePawn'");
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void onSurrender(Color coward) {
|
||||||
|
// TODO Auto-generated method stub
|
||||||
|
throw new UnsupportedOperationException("Unimplemented method 'onSurrender'");
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void onWin(Color winner) {
|
||||||
|
// TODO Auto-generated method stub
|
||||||
|
throw new UnsupportedOperationException("Unimplemented method 'onWin'");
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
53
app/src/main/java/chess/view/render/shader/BoardShader.java
Normal file
53
app/src/main/java/chess/view/render/shader/BoardShader.java
Normal file
@@ -0,0 +1,53 @@
|
|||||||
|
package chess.view.render.shader;
|
||||||
|
|
||||||
|
import org.joml.Matrix4f;
|
||||||
|
|
||||||
|
public class BoardShader extends ShaderProgram {
|
||||||
|
|
||||||
|
private static String vertexShader = """
|
||||||
|
#version 330
|
||||||
|
|
||||||
|
layout(location = 0) in vec3 position;
|
||||||
|
layout(location = 1) in vec3 color;
|
||||||
|
|
||||||
|
uniform mat4 camMatrix;
|
||||||
|
|
||||||
|
flat out vec3 pass_color;
|
||||||
|
|
||||||
|
void main(void){
|
||||||
|
gl_Position = camMatrix * vec4(position, 1.0);
|
||||||
|
pass_color = color;
|
||||||
|
}
|
||||||
|
""";
|
||||||
|
|
||||||
|
private static String fragmentShader = """
|
||||||
|
#version 330
|
||||||
|
|
||||||
|
flat in vec3 pass_color;
|
||||||
|
|
||||||
|
out vec4 out_color;
|
||||||
|
|
||||||
|
void main(void){
|
||||||
|
out_color = vec4(pass_color, 1.0);
|
||||||
|
}
|
||||||
|
""";
|
||||||
|
|
||||||
|
private int location_CamMatrix = 0;
|
||||||
|
|
||||||
|
public BoardShader() {
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
public void LoadShader() {
|
||||||
|
super.LoadProgram(vertexShader, fragmentShader);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
protected void GetAllUniformLocation() {
|
||||||
|
location_CamMatrix = GetUniformLocation("camMatrix");
|
||||||
|
}
|
||||||
|
|
||||||
|
public void SetCamMatrix(Matrix4f mat) {
|
||||||
|
LoadMat4(location_CamMatrix, mat);
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -1,7 +1,5 @@
|
|||||||
package chess.view.DDDrender.shader;
|
package chess.view.render.shader;
|
||||||
|
|
||||||
import java.io.Closeable;
|
|
||||||
import java.io.IOException;
|
|
||||||
import java.nio.FloatBuffer;
|
import java.nio.FloatBuffer;
|
||||||
import java.nio.IntBuffer;
|
import java.nio.IntBuffer;
|
||||||
|
|
||||||
@@ -11,7 +9,7 @@ import org.lwjgl.BufferUtils;
|
|||||||
import org.lwjgl.opengl.GL30;
|
import org.lwjgl.opengl.GL30;
|
||||||
import org.lwjgl.system.MemoryStack;
|
import org.lwjgl.system.MemoryStack;
|
||||||
|
|
||||||
public abstract class ShaderProgram implements Closeable {
|
public abstract class ShaderProgram {
|
||||||
private int programId;
|
private int programId;
|
||||||
private int vertexShaderId;
|
private int vertexShaderId;
|
||||||
private int fragmentShaderId;
|
private int fragmentShaderId;
|
||||||
@@ -58,8 +56,8 @@ public abstract class ShaderProgram implements Closeable {
|
|||||||
|
|
||||||
if (compileSuccesful.get() != 1) {
|
if (compileSuccesful.get() != 1) {
|
||||||
System.out.println("Shader did not compile !");
|
System.out.println("Shader did not compile !");
|
||||||
System.err.println(GL30.glGetShaderInfoLog(shaderId));
|
|
||||||
return -1;
|
return -1;
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
return shaderId;
|
return shaderId;
|
||||||
@@ -70,7 +68,7 @@ public abstract class ShaderProgram implements Closeable {
|
|||||||
protected int GetUniformLocation(String uniformName) {
|
protected int GetUniformLocation(String uniformName) {
|
||||||
int location = GL30.glGetUniformLocation(programId, uniformName);
|
int location = GL30.glGetUniformLocation(programId, uniformName);
|
||||||
if (location == -1) {
|
if (location == -1) {
|
||||||
System.out.println("Uniform value \"" + uniformName + "\" not found !");
|
System.out.println("Uniform value not found !");
|
||||||
}
|
}
|
||||||
return location;
|
return location;
|
||||||
}
|
}
|
||||||
@@ -93,11 +91,4 @@ public abstract class ShaderProgram implements Closeable {
|
|||||||
GL30.glUniformMatrix4fv(location, false, buffer);
|
GL30.glUniformMatrix4fv(location, false, buffer);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
|
||||||
public void close() throws IOException {
|
|
||||||
GL30.glDeleteShader(vertexShaderId);
|
|
||||||
GL30.glDeleteShader(fragmentShaderId);
|
|
||||||
GL30.glDeleteProgram(programId);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
@@ -213,7 +213,7 @@ public class Window extends JFrame implements GameListener {
|
|||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void onPlayerTurn(chess.model.Color color, boolean undone) {
|
public void onPlayerTurn(chess.model.Color color) {
|
||||||
this.displayText.setText("Current turn: " + color);
|
this.displayText.setText("Current turn: " + color);
|
||||||
updateButtons();
|
updateButtons();
|
||||||
}
|
}
|
||||||
|
|||||||
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
@@ -3,20 +3,24 @@
|
|||||||
*/
|
*/
|
||||||
package chess;
|
package chess;
|
||||||
|
|
||||||
import org.junit.jupiter.api.Test;
|
|
||||||
|
|
||||||
import chess.ai.DumbAI;
|
import chess.ai.DumbAI;
|
||||||
import chess.controller.Command;
|
import chess.controller.Command;
|
||||||
import chess.controller.CommandExecutor;
|
import chess.controller.CommandExecutor;
|
||||||
import chess.controller.commands.NewGameCommand;
|
import chess.controller.commands.NewGameCommand;
|
||||||
import chess.controller.commands.UndoCommand;
|
import chess.controller.commands.UndoCommand;
|
||||||
import chess.controller.event.GameAdaptator;
|
import chess.controller.event.GameAdaptator;
|
||||||
import chess.model.Color;
|
import chess.model.*;
|
||||||
import chess.model.Game;
|
import chess.model.pieces.*;
|
||||||
|
import chess.simulator.Simulator;
|
||||||
|
import chess.view.simplerender.Window;
|
||||||
|
import org.junit.jupiter.api.Test;
|
||||||
|
|
||||||
|
import java.util.List;
|
||||||
|
import java.util.Objects;
|
||||||
|
|
||||||
class AppTest {
|
class AppTest {
|
||||||
@Test void functionalRollback(){
|
@Test void functionalRollback(){
|
||||||
Game game = new Game();
|
Game game = new Game(new ChessBoard());
|
||||||
CommandExecutor commandExecutor = new CommandExecutor(game);
|
CommandExecutor commandExecutor = new CommandExecutor(game);
|
||||||
|
|
||||||
DumbAI ai = new DumbAI(commandExecutor, Color.Black);
|
DumbAI ai = new DumbAI(commandExecutor, Color.Black);
|
||||||
@@ -34,9 +38,9 @@ class AppTest {
|
|||||||
result = commandExecutor.executeCommand(new UndoCommand());
|
result = commandExecutor.executeCommand(new UndoCommand());
|
||||||
} while (result != Command.CommandResult.NotAllowed);
|
} while (result != Command.CommandResult.NotAllowed);
|
||||||
|
|
||||||
Game initialGame = new Game();
|
Game initialGame = new Game(new ChessBoard());
|
||||||
CommandExecutor initialCommandExecutor = new CommandExecutor(initialGame);
|
CommandExecutor initialCommandExecutor = new CommandExecutor(initialGame);
|
||||||
initialCommandExecutor.executeCommand(new NewGameCommand());
|
commandExecutor.executeCommand(new NewGameCommand());
|
||||||
|
|
||||||
assert(game.getBoard().equals(initialGame.getBoard()));
|
assert(game.getBoard().equals(initialGame.getBoard()));
|
||||||
|
|
||||||
|
|||||||
Reference in New Issue
Block a user