// Asteroid Push - A game featuring selfmade spaceships and pompous physics // Copyright (C) 2013 Christian Meyer, Silvan Wegmann // // This program is free software: you can redistribute it and/or modify // it under the terms of the GNU General Public License as published by // the Free Software Foundation, either version 3 of the License, or // (at your option) any later version. // // This program is distributed in the hope that it will be useful, // but WITHOUT ANY WARRANTY; without even the implied warranty of // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the // GNU General Public License for more details. // // You should have received a copy of the GNU General Public License // along with this program. If not, see <http://www.gnu.org/licenses/>. package org.codecranachan.asteroidpush.base.ui.workshop; import java.util.Collection; import java.util.LinkedList; import java.util.List; import org.codecranachan.asteroidpush.base.ResourceLoader; import org.codecranachan.asteroidpush.base.ui.widget.BasicWidget; import org.codecranachan.asteroidpush.base.visuals.MultipartRepresentation; import org.codecranachan.asteroidpush.base.visuals.OffsetRepresentation; import org.codecranachan.asteroidpush.base.visuals.Representation; import org.codecranachan.asteroidpush.base.visuals.RepresentationRenderer; import org.codecranachan.asteroidpush.base.workshop.Blueprint; import org.codecranachan.asteroidpush.base.workshop.ManipulatedArea; import org.codecranachan.asteroidpush.base.workshop.WorkshopCoordinator; import org.codecranachan.asteroidpush.base.workshop.assembly.Part; import org.codecranachan.asteroidpush.base.workshop.tokenboard.Placement; import org.codecranachan.asteroidpush.base.workshop.tokenboard.Token; import org.codecranachan.asteroidpush.content.visuals.OriginRepresentation; import org.codecranachan.asteroidpush.utils.Angle; import org.codecranachan.asteroidpush.utils.Arrow; import org.codecranachan.asteroidpush.utils.Circle; import org.codecranachan.asteroidpush.utils.FieldOfView; import org.codecranachan.asteroidpush.utils.GeometryConverter; import org.codecranachan.asteroidpush.utils.OrthogonalCoordinate; import org.codecranachan.asteroidpush.utils.RectangleMath; import org.jbox2d.common.MathUtils; import org.jbox2d.common.Vec2; import org.newdawn.slick.Color; import org.newdawn.slick.Graphics; import org.newdawn.slick.Input; import org.newdawn.slick.geom.Rectangle; import org.newdawn.slick.geom.Vector2f; public class ManipulatorWidget extends BasicWidget { private WorkshopCoordinator coordinator; private RepresentationRenderer renderer; public ManipulatorWidget(WorkshopCoordinator coordinator, ResourceLoader loader) { this.coordinator = coordinator; this.renderer = new RepresentationRenderer(); } @Override public void render(Graphics g) { if (getFrame() == null) { return; } if (coordinator.getManipulatedBlueprint() == null) { renderNoBlueprint(g); return; } updateRendererFocus(); g.setAntiAlias(true); renderBackground(g); renderBlueprint(g); renderHover(g); } private void renderNoBlueprint(Graphics g) { g.setColor(Color.red); g.drawString("ManipulatorWidget: No blueprint selected", 10, 30); } private void renderBackground(Graphics g) { g.setColor(Color.blue); g.fill(getFrame()); } private void renderBlueprint(Graphics g) { Rectangle blueprintArea = getBlueprintArea(); // Draw blueprint frame g.setColor(new Color(1.0f, 1.0f, 1.0f, 0.75f)); g.setLineWidth(1.5f); g.draw(blueprintArea); // Draw blueprint grid float tileSize = getTileSize(); g.setLineWidth(1.5f); g.setColor(new Color(1.0f, 1.0f, 1.0f, 0.25f)); for (int i = 1; i < getTilesPerSide(); ++i) { float offset = tileSize * i; // vertical float x = blueprintArea.getX() + offset; g.drawLine(x, blueprintArea.getMinY(), x, blueprintArea.getMaxY()); // horizontal float y = blueprintArea.getY() + offset; g.drawLine(blueprintArea.getMinX(), y, blueprintArea.getMaxX(), y); } // Draw tokens and origin Blueprint blueprint = coordinator.getManipulatedBlueprint(); Collection<Token> tokens = blueprint.getTokens(); List<Representation> representations = new LinkedList<Representation>(); representations.add(new OriginRepresentation()); for (Token token : tokens) { representations.addAll(token.getRepresentations()); } renderer.setRepresentations(representations); renderer.render(g); } private Rectangle getBlueprintArea() { float margin = 10.0f; Rectangle square = RectangleMath.getCenteredSquare(getFrame()); Rectangle area = new Rectangle(square.getX() + margin, square.getY() + margin, square.getWidth() - margin * 2, square.getHeight() - margin * 2); return area; } private void updateRendererFocus() { float magnitude = (float) getTilesPerSide() / 2.0f; ManipulatedArea area = coordinator.getManipulatedArea(); OrthogonalCoordinate offset = area.getBottomLeftCorner(); float deltaX = MathUtils.floor((float) area.getWidth() / 2.0f); float deltaY = MathUtils.floor((float) area.getHeight() / 2.0f); if (getTilesPerSide() % 2 == 0) { deltaX -= 0.5f; deltaY -= 0.5f; } Vec2 origin = new Vec2(offset.getX() + deltaX, offset.getY() + deltaY); FieldOfView fov = new FieldOfView(new Circle(origin, magnitude), new Angle()); renderer.setFieldOfView(fov); } private void renderHover(Graphics g) { renderer.setRepresentations(getHoverRepresentations()); renderer.render(g); } private List<Representation> getHoverRepresentations() { LinkedList<Representation> list = new LinkedList<Representation>(); Vector2f hover = getHover(); Part selected = coordinator.getSelectedPart(); if (hover != null && selected != null) { MultipartRepresentation base = new MultipartRepresentation(3); base.addAll(selected.getRepresentations()); float scale = 1.0f; Placement placement = coordinator.getPartSelectedPartPlacement(); Arrow offset = GeometryConverter.convertToArrow(renderer .mapToWorldCoordinates(hover), placement.getOrientation()); list.add(new OffsetRepresentation(base, offset, scale)); } return list; } private int getTilesPerSide() { ManipulatedArea area = coordinator.getManipulatedArea(); int margin = 1; int sizeProposal = area.getLargestSide() + 2 * (margin + 1); int minSize = 9; if (sizeProposal < minSize) { sizeProposal = minSize; } return sizeProposal; } private float getTileSize() { Rectangle square = getBlueprintArea(); return square.getHeight() / getTilesPerSide(); } private OrthogonalCoordinate getCoordinateForPoint(Vec2 point) { return new OrthogonalCoordinate(Math.round(point.x), Math.round(point.y)); } public void resize(Rectangle frame) { setFrame(frame); renderer.setFrame(getBlueprintArea()); } public void mousePressed(int button, int x, int y) { if (coordinator.getManipulatedBlueprint() == null) { return; } Vec2 world = renderer.mapToWorldCoordinates(new Vector2f(x, y)); OrthogonalCoordinate coordinate = getCoordinateForPoint(world); switch (button) { case Input.MOUSE_LEFT_BUTTON: coordinator.pickSquare(coordinate); break; case Input.MOUSE_RIGHT_BUTTON: coordinator.clearSquare(coordinate); break; } } }