VASSAL.tools.imageop.OrthoRotateOpBitmapImpl.java Source code

Java tutorial

Introduction

Here is the source code for VASSAL.tools.imageop.OrthoRotateOpBitmapImpl.java

Source

/*
 * $Id$
 *
 * Copyright (c) 2007-2008 by Joel Uckelman
 *
 * This library is free software; you can redistribute it and/or
 * modify it under the terms of the GNU Library General Public
 * License (LGPL) as published by the Free Software Foundation.
 *
 * This library 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
 * Library General Public License for more details.
 *
 * You should have received a copy of the GNU Library General Public
 * License along with this library; if not, copies are available
 * at http://www.opensource.org.
 */

package VASSAL.tools.imageop;

import java.awt.Dimension;
import java.awt.Graphics2D;
import java.awt.RenderingHints;
import java.awt.image.BufferedImage;
import java.util.Collections;
import java.util.List;

import org.apache.commons.lang.builder.HashCodeBuilder;

import VASSAL.tools.image.ImageUtils;

public class OrthoRotateOpBitmapImpl extends AbstractTiledOpImpl implements RotateOp {
    private final ImageOp sop;
    private final int angle;
    private final int hash;

    public OrthoRotateOpBitmapImpl(ImageOp sop, int angle) {
        if (sop == null)
            throw new IllegalArgumentException();

        angle = (360 + (angle % 360)) % 360; // put angle in [0,360)
        if (angle % 90 != 0)
            throw new IllegalArgumentException();

        // angle is now in { 0, 90, 180, 270 }.

        this.sop = sop;
        this.angle = angle / 90;

        hash = new HashCodeBuilder().append(sop).append(angle).toHashCode();
    }

    public List<VASSAL.tools.opcache.Op<?>> getSources() {
        return Collections.<VASSAL.tools.opcache.Op<?>>singletonList(sop);
    }

    public BufferedImage eval() throws Exception {
        final BufferedImage src = sop.getImage(null);
        if (size == null)
            fixSize();

        // remain opaque if our parent image is
        final BufferedImage dst = ImageUtils.createCompatibleImage(size.width, size.height,
                src.getTransparency() != BufferedImage.OPAQUE);

        final Graphics2D g = dst.createGraphics();
        g.rotate(Math.PI / 2.0 * angle, src.getWidth() / 2.0, src.getHeight() / 2.0);
        g.drawImage(src, 0, 0, null);
        g.dispose();

        return dst;
    }

    protected void fixSize() {
        if ((size = getSizeFromCache()) == null) {
            size = sop.getSize();

            // transpose dimensions for 90- and 270-degree rotations
            if (angle == 1 || angle == 3)
                size.setSize(size.height, size.width);
        }
    }

    public double getAngle() {
        return angle * 90;
    }

    public RenderingHints getHints() {
        //    return ImageUtils.getDefaultHints();
        return null;
    }

    protected ImageOp createTileOp(int tileX, int tileY) {
        return new TileOp(this, tileX, tileY);
    }

    private static class TileOp extends AbstractTileOpImpl {
        private final ImageOp sop;
        private final int angle;
        private final int hash;

        public TileOp(OrthoRotateOpBitmapImpl rop, int tileX, int tileY) {
            if (rop == null)
                throw new IllegalArgumentException();

            if (tileX < 0 || tileX >= rop.getNumXTiles() || tileY < 0 || tileY >= rop.getNumYTiles())
                throw new IndexOutOfBoundsException();

            this.angle = rop.angle;

            final int sx0, sy0, sx1, sy1;

            switch (angle) {
            case 0:
                sx0 = tileX * rop.tileSize.width;
                sy0 = tileY * rop.tileSize.height;
                sx1 = Math.min((tileX + 1) * rop.tileSize.width, rop.size.width);
                sy1 = Math.min((tileY + 1) * rop.tileSize.height, rop.size.height);
                break;
            case 1:
                sx0 = tileY * rop.tileSize.height;
                sy0 = tileX * rop.tileSize.width;
                sx1 = Math.min((tileY + 1) * rop.tileSize.height, rop.size.height);
                sy1 = Math.min((tileX + 1) * rop.tileSize.width, rop.size.width);
                break;
            case 2:
                sx1 = rop.size.width - tileX * rop.tileSize.width;
                sy1 = rop.size.height - tileY * rop.tileSize.height;
                sx0 = rop.size.width - Math.min((tileX + 1) * rop.tileSize.width, rop.size.width);
                sy0 = rop.size.height - Math.min((tileY + 1) * rop.tileSize.height, rop.size.height);
                break;
            case 3:
            default:
                sx1 = rop.size.height - tileY * rop.tileSize.height;
                sy1 = rop.size.width - tileX * rop.tileSize.width;
                sx0 = rop.size.height - Math.min((tileY + 1) * rop.tileSize.height, rop.size.height);
                sy0 = rop.size.width - Math.min((tileX + 1) * rop.tileSize.width, rop.size.width);
                break;
            }

            size = new Dimension(sx1 - sx0, sy1 - sy0);

            sop = new CropOpBitmapImpl(rop.sop, sx0, sy0, sx1, sy1);

            hash = new HashCodeBuilder().append(sop).append(angle).toHashCode();
        }

        public List<VASSAL.tools.opcache.Op<?>> getSources() {
            return Collections.<VASSAL.tools.opcache.Op<?>>singletonList(sop);
        }

        public BufferedImage eval() throws Exception {
            final BufferedImage src = sop.getImage(null);

            // remain opaque if our parent image is
            final BufferedImage dst = ImageUtils.createCompatibleImage(size.width, size.height,
                    src.getTransparency() != BufferedImage.OPAQUE);

            final Graphics2D g = dst.createGraphics();
            g.rotate(Math.PI / 2.0 * angle, src.getWidth() / 2.0, src.getHeight() / 2.0);
            g.drawImage(src, 0, 0, null);
            g.dispose();

            return dst;
        }

        protected void fixSize() {
        }

        @Override
        public boolean equals(Object o) {
            if (this == o)
                return true;
            if (o == null || o.getClass() != this.getClass())
                return false;

            final TileOp op = (TileOp) o;
            return angle == op.angle && sop.equals(op.sop);
        }

        @Override
        public int hashCode() {
            return hash;
        }
    }

    @Override
    public boolean equals(Object o) {
        if (this == o)
            return true;
        if (o == null || o.getClass() != this.getClass())
            return false;

        final OrthoRotateOpBitmapImpl op = (OrthoRotateOpBitmapImpl) o;
        return angle == op.getAngle() && sop.equals(op.sop);
    }

    @Override
    public int hashCode() {
        return hash;
    }
}