package org.gbcpainter.view.draw;
import org.gbcpainter.env.GraphicsEnv;
import org.gbcpainter.game.levels.Level;
import org.gbcpainter.game.model.Monster;
import org.gbcpainter.game.model.Player;
import org.gbcpainter.game.model.grid.Face;
import org.gbcpainter.game.model.grid.Junction;
import org.gbcpainter.game.model.grid.OpaqueRandomFace;
import org.gbcpainter.game.model.grid.Pipe;
import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.Nullable;
import org.jgrapht.Graph;
import org.jgrapht.graph.UnmodifiableUndirectedGraph;
import java.awt.*;
import java.awt.geom.GeneralPath;
import java.util.*;
/**
* Draws the entire level to screen
* <p/>
* This is class is used as a development tool.
*
* @author Lorenzo Pellegrini
* @exclude
*/
public class ZoomRedrawJob extends ComposableRedrawJob<Object> {
@Nullable
private Map<Face, Integer> faces = null;
@NotNull
private final Rectangle levelBounds;
public ZoomRedrawJob(@NotNull Canvas whereTo, @NotNull Level level) {
super(whereTo, level, 1, Collections.singletonList( new Object() ));
this.levelBounds = makeBoundRectangle( level.getMap() );
tryCreateFaces();
}
@NotNull
private static Rectangle makeBoundRectangle( @NotNull
Graph<Junction, Pipe> levelGraph ) {
int minY = Integer.MAX_VALUE;
int maxY = 0;
int minX = Integer.MAX_VALUE;
int maxX = 0;
for (Junction vertex : levelGraph.vertexSet()) {
final Point vertexPosition = vertex.getPosition();
minX = Math.min( vertexPosition.x, minX );
maxX = Math.max( vertexPosition.x, maxX );
minY = Math.min( vertexPosition.y, minY );
maxY = Math.max( vertexPosition.y, maxY );
}
return new Rectangle( minX, minY, maxX - minX, maxY - minY );
}
/**
* Draws the component on screen
* <p/>
* The Graphics object is clipped to the position specified from {@link
* #getComponentRect(Object)}
*
* @param component The component to be drawn
* @param g2d The grphics object
*
* @throws Exception If an error occurs
*/
@Override
protected void drawComponent( @NotNull final Object component,
@NotNull final Graphics2D g2d )
throws Exception {
final Rectangle screenBounds = GraphicsEnv.getInstance()
.gameRectangleToActualScreen(
this.levelBounds );
final Point screenCenter = new Point( (int) screenBounds.getCenterX() ,
(int) screenBounds.getCenterY() );
g2d.translate( - screenCenter.x/2, - screenCenter.y/2 );
final Level level = getLevel();
final Player player = level.getPlayer();
for (Map.Entry<Face, Integer> faceEntry : this.faces.entrySet()) {
final Face face = faceEntry.getKey();
face.setColored( level.isFaceColored( faceEntry.getValue() ) );
face.draw( g2d );
}
for (Pipe pipe : level.getMap().edgeSet()) {
pipe.draw( g2d );
}
for (Junction junction : level.getMap().vertexSet()) {
junction.draw( g2d );
}
for (Monster mob : level.getMonsters()) {
mob.draw( g2d );
}
player.draw( g2d ) ;
}
/**
* Returns the clip of the component
*
* @param component The component whose size is required
*
* @return The size of the component or null if the element is hidden
*/
@Nullable
@Override
protected Rectangle getComponentRect( @NotNull final Object component ) {
final Dimension windowSize = GraphicsEnv.getInstance().getWindowSize();
return new Rectangle( windowSize );
}
protected boolean tryCreateFaces() {
try {
final Level level = getLevel();
Map<Set<Pipe>, Integer> facesMap = level.getFacesMap();
UnmodifiableUndirectedGraph<Junction, Pipe> levelMap = level.getMap();
faces = new HashMap<>( facesMap.size() );
for (Map.Entry<Set<Pipe>, Integer> faceAndId : facesMap.entrySet()) {
/* Per ogni faccia ... */
Pipe firstPipe = faceAndId.getKey().iterator().next();
Junction lastJunction = levelMap.getEdgeSource( firstPipe );
Pipe lastPipe = null;
GeneralPath faceShape = new GeneralPath();
faceShape.moveTo( lastJunction.getPosition().x, lastJunction.getPosition().y );
while ( ! firstPipe.equals( lastPipe ) ) {
/* Aggiunge la linea*/
Pipe nextPipe = null;
final Set<Pipe> connectedSegments = new HashSet<>( levelMap.edgesOf( lastJunction ) );
if ( lastPipe == null ) {
/* È il primo loop */
lastPipe = firstPipe;
}
/* Scarta il segmento già percorso */
connectedSegments.remove( lastPipe );
for (Pipe perimeterSegment : faceAndId.getKey()) {
/* Tra tutti i segmenti del perimetro seleziona solo quello che confina con il vertice corrente */
if ( connectedSegments.contains( perimeterSegment ) ) {
nextPipe = perimeterSegment;
break;
}
}
if ( nextPipe == null ) {
throw new IllegalArgumentException();
}
lastPipe = nextPipe;
final Junction edgeSource = levelMap.getEdgeSource( nextPipe );
lastJunction = edgeSource.equals( lastJunction ) ? levelMap.getEdgeTarget( nextPipe ) : edgeSource;
final Point junctionPosition = lastJunction.getPosition();
faceShape.lineTo( junctionPosition.x, junctionPosition.y );
}
faceShape.closePath();
faces.put( new OpaqueRandomFace( faceShape ), faceAndId.getValue() );
}
return true;
} catch ( Exception e ) {
this.faces = null;
return false;
}
}
}