com.quadbits.gdxhelper.utils.SpriteGrid.java Source code

Java tutorial

Introduction

Here is the source code for com.quadbits.gdxhelper.utils.SpriteGrid.java

Source

/*
 * Copyright (c) 2015 Quadbits SLU
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 * http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */
package com.quadbits.gdxhelper.utils;

import com.badlogic.gdx.graphics.Color;
import com.badlogic.gdx.graphics.Texture;
import com.badlogic.gdx.graphics.g2d.Batch;
import com.badlogic.gdx.graphics.g2d.Sprite;
import com.badlogic.gdx.graphics.g2d.TextureRegion;
import com.badlogic.gdx.math.MathUtils;
import com.badlogic.gdx.utils.Array;
import com.badlogic.gdx.utils.Pool;

import javax.inject.Inject;

/**
 *
 */
public class SpriteGrid implements Pool.Poolable, DrawUtils.BatchDrawableSprite {
    protected Pool<SpriteGrid> spriteGridPool;
    protected Array<Sprite> spriteGrid;
    protected int nCols;
    protected int nRows;
    protected float originalWidth;
    protected float originalHeight;
    protected float x;
    protected float y;
    protected float width;
    protected float height;
    protected float scaleX;
    protected float scaleY;
    protected float originX;
    protected float originY;
    protected float rotation;
    protected boolean tileableX;
    protected boolean tileableY;
    protected float minTiledX;
    protected float maxTiledX;
    protected float minTiledY;
    protected float maxTiledY;
    protected boolean flipX;
    protected boolean flipY;
    protected Color color;
    protected boolean dirty;

    @Inject
    TextureAtlasProxy textureAtlasProxy;

    public static final int NCOLS_MAX = 1024;
    public static final int NROWS_MAX = 1024;

    @Inject
    public SpriteGrid() {
        spriteGridPool = null;
        spriteGrid = new Array<Sprite>();
        color = new Color();
        reset();
    }

    @Override
    public void reset() {
        spriteGrid.clear();
        nCols = nRows = 0;
        originalWidth = originalHeight = 0;
        x = y = 0;
        width = height = 0;
        scaleX = scaleY = 1;
        originX = originY = 0;
        rotation = 0;
        tileableX = tileableY = false;
        minTiledX = maxTiledX = minTiledY = maxTiledY = 0;
        flipX = flipY = false;
        color.set(1, 1, 1, 1);
        dirty = false;
    }

    public void setPool(Pool<SpriteGrid> spriteGridPool) {
        this.spriteGridPool = spriteGridPool;
    }

    public void free() {
        spriteGridPool.free(this);
    }

    public void setTexture(String textureName) {
        TextureRegion textureRegion = textureAtlasProxy.get().findRegion(textureName);

        // One single texture
        if (textureRegion != null) {
            nRows = 1;
            nCols = 1;
            spriteGrid.add(new Sprite(textureRegion));
        }

        // A grid of textures
        else {
            // Initialize nCols and nRows to a reasonably high value; these values will be adjusted
            // as the actual number of rows and columns is obtained by reading textures from the
            // atlas.
            nRows = NROWS_MAX;
            nCols = NCOLS_MAX;
            for (int i = 0; i < nRows; i++) {
                for (int j = 0; j < nCols; j++) {
                    String textureCellName = String.format("%s-%d-%d", textureName, i, j);
                    textureRegion = textureAtlasProxy.get().findRegion(textureCellName);
                    if (textureRegion == null) {
                        if (i == 0) {
                            nCols = j;
                        }
                        if (j == 0) {
                            nRows = i;
                        }
                        break;
                    }
                    spriteGrid.add(new Sprite(textureRegion));
                }
            }
        }

        // Check if we have really loaded an image
        if (nRows == 0 || nCols == 0) {
            throw new IllegalArgumentException(
                    String.format("Texture '%s' not found in texture atlas", textureName));
        }

        // Calculate original width
        originalWidth = 0;
        for (int j = 0; j < nCols; j++) {
            originalWidth += getSprite(0, j).getRegionWidth();
        }

        // Calculate original height
        originalHeight = 0;
        for (int i = 0; i < nRows; i++) {
            originalHeight += getSprite(i, 0).getRegionHeight();
        }

        // Set current width/height to the original values
        setSize(originalWidth, originalHeight);
    }

    protected Sprite getSprite(int i, int j) {
        return spriteGrid.get(i * nCols + j);
    }

    public void setTextureFilter(Texture.TextureFilter minFilter, Texture.TextureFilter maxFilter) {
        for (Sprite sprite : spriteGrid) {
            sprite.getTexture().setFilter(minFilter, maxFilter);
        }
    }

    private void adjustSpriteCellsPositionsAndSizes() {
        float widthScale = width / originalWidth;
        float heightScale = height / originalHeight;
        int offsetY = 0;
        for (int i = 0; i < nRows; i++) {
            int offsetX = 0;
            for (int j = 0; j < nCols; j++) {
                Sprite spriteCell = getSprite(i, j);
                int spriteCellWidth = (int) (widthScale * spriteCell.getRegionWidth());
                int spriteCellHeight = (int) (heightScale * spriteCell.getRegionHeight());
                spriteCell.setPosition(offsetX, offsetY);
                spriteCell.setSize(spriteCellWidth, spriteCellHeight);
                offsetX += spriteCell.getWidth();
            }
            offsetY += getSprite(i, 0).getHeight();
        }

        dirty = false;
    }

    public void draw(Batch batch, float parentAlpha) {
        if (dirty) {
            adjustSpriteCellsPositionsAndSizes();
        }

        // Special case: not tileable
        if (!tileableX && !tileableY) {
            drawSprite(batch, parentAlpha);
        }

        // General case: tileable in at least one dimension
        else {
            DrawUtils.drawTileableSprite(batch, parentAlpha, this, tileableX, tileableY, minTiledX, maxTiledX,
                    minTiledY, maxTiledY);
        }
    }

    public void drawSprite(Batch batch, float parentAlpha) {
        final float cos = MathUtils.cosDeg(rotation);
        final float sin = MathUtils.sinDeg(rotation);
        final float alpha = color.a * parentAlpha;
        for (int i = 0; i < nRows; i++) {
            for (int j = 0; j < nCols; j++) {
                // get the sprite
                int row = i;
                int col = j;
                if (flipX) {
                    col = nCols - 1 - j;
                }
                if (flipY) {
                    row = nRows - 1 - i;
                }
                Sprite spriteCell = getSprite(row, col);

                // save old position
                float oldSpriteCellX = spriteCell.getX();
                float oldSpriteCellY = spriteCell.getY();
                float spriteCellX = MathUtils.floor(oldSpriteCellX);
                float spriteCellY = MathUtils.floor(oldSpriteCellY);
                if (flipX) {
                    spriteCellX = width - (spriteCellX + spriteCell.getWidth());
                }
                if (flipY) {
                    spriteCellY = height - (spriteCellY + spriteCell.getHeight());
                }

                // set rotation and position
                if (rotation != 0) {
                    spriteCell.setOrigin(originX, originY);
                    spriteCell.setRotation(rotation);
                    spriteCell.setPosition(x + cos * spriteCellX - sin * spriteCellY,
                            y + sin * spriteCellX + cos * spriteCellY);
                } else {
                    spriteCell.setPosition(x + spriteCellX, y + spriteCellY);
                }
                spriteCell.setColor(color);
                // set alpha *after* color; otherwise, alpha is overwritten by the color's alpha
                spriteCell.setAlpha(alpha);

                // set flip
                spriteCell.setFlip(flipX, flipY);

                // draw the sprite
                spriteCell.draw(batch);

                // restore position and rotation
                spriteCell.setPosition(oldSpriteCellX, oldSpriteCellY);
                spriteCell.setRotation(0);
            }
        }
    }

    public float getOriginalWidth() {
        return originalWidth;
    }

    public float getOriginalHeight() {
        return originalHeight;
    }

    public float getX() {
        return x;
    }

    public void setX(float x) {
        this.x = x;
        dirty = true;
    }

    public float getY() {
        return y;
    }

    public void setY(float y) {
        this.y = y;
        dirty = true;
    }

    public void setPosition(float x, float y) {
        this.x = x;
        this.y = y;
        dirty = true;
    }

    public float getWidth() {
        return width;
    }

    public void setWidth(float width) {
        this.width = width;
        dirty = true;
    }

    public float getHeight() {
        return height;
    }

    public void setHeight(float height) {
        this.height = height;
        dirty = true;
    }

    public void setSize(float width, float height) {
        this.width = width;
        this.height = height;
        dirty = true;
    }

    public void scaleBy(float scale) {
        setSize(originalWidth * this.scaleX * scale, originalHeight * this.scaleY * scale);
    }

    public void scaleBy(float scaleX, float scaleY) {
        setSize(originalWidth * this.scaleX * scaleX, originalHeight * this.scaleY * scaleY);
    }

    public float getScaleX() {
        return scaleX;
    }

    public void setScaleX(float scaleX) {
        this.scaleX = scaleX;
        setWidth(originalWidth * scaleX);
        dirty = true;
    }

    public float getScaleY() {
        return scaleY;
    }

    public void setScaleY(float scaleY) {
        this.scaleY = scaleY;
        setHeight(originalHeight * scaleY);
        dirty = true;
    }

    public void setScale(float scaleX, float scaleY) {
        this.scaleX = scaleX;
        this.scaleY = scaleY;
        setSize(originalWidth * scaleX, originalHeight * scaleY);
        dirty = true;
    }

    public float getOriginX() {
        return originX;
    }

    public void setOriginX(float originX) {
        this.originX = originX;
    }

    public float getOriginY() {
        return originY;
    }

    public void setOriginY(float originY) {
        this.originY = originY;
    }

    public void setOrigin(float originX, float originY) {
        this.originX = originX;
        this.originY = originY;
    }

    public float getRotation() {
        return rotation;
    }

    public void setRotation(float rotation) {
        this.rotation = rotation;
    }

    public boolean isTileableX() {
        return tileableX;
    }

    public void setTileableX(boolean isTileableX) {
        this.tileableX = isTileableX;
    }

    public boolean isTileableY() {
        return tileableY;
    }

    public void setTileableY(boolean isTileableY) {
        this.tileableY = isTileableY;
    }

    public boolean isFlipX() {
        return flipX;
    }

    public void setFlipX(boolean flipX) {
        this.flipX = flipX;
    }

    public boolean isFlipY() {
        return flipY;
    }

    public void setFlipY(boolean flipY) {
        this.flipY = flipY;
    }

    public Color getColor() {
        return color;
    }

    public void setColor(Color color) {
        this.color = color;
    }

    public float getMinTiledX() {
        return minTiledX;
    }

    public void setMinTiledX(float minTiledX) {
        this.minTiledX = minTiledX;
    }

    public float getMaxTiledX() {
        return maxTiledX;
    }

    public void setMaxTiledX(float maxTiledX) {
        this.maxTiledX = maxTiledX;
    }

    public float getMinTiledY() {
        return minTiledY;
    }

    public void setMinTiledY(float minTiledY) {
        this.minTiledY = minTiledY;
    }

    public float getMaxTiledY() {
        return maxTiledY;
    }

    public void setMaxTiledY(float maxTiledY) {
        this.maxTiledY = maxTiledY;
    }
}