Package com.ardor3d.extension.terrain.providers.awt

Source Code of com.ardor3d.extension.terrain.providers.awt.AwtTextureSource

/**
* Copyright (c) 2008-2012 Ardor Labs, Inc.
*
* This file is part of Ardor3D.
*
* Ardor3D is free software: you can redistribute it and/or modify it
* under the terms of its license which may be found in the accompanying
* LICENSE file or at <http://www.ardor3d.com/LICENSE>.
*/

package com.ardor3d.extension.terrain.providers.awt;

import java.awt.AlphaComposite;
import java.awt.Composite;
import java.awt.Graphics2D;
import java.awt.image.BufferedImage;
import java.awt.image.DataBufferInt;
import java.nio.ByteBuffer;
import java.util.Iterator;
import java.util.List;
import java.util.Map;
import java.util.Set;

import com.ardor3d.extension.terrain.client.TextureConfiguration;
import com.ardor3d.extension.terrain.client.TextureSource;
import com.ardor3d.extension.terrain.util.Tile;
import com.ardor3d.image.TextureStoreFormat;
import com.ardor3d.math.MathUtils;
import com.ardor3d.math.Transform;
import com.ardor3d.math.type.ReadOnlyVector4;
import com.ardor3d.util.geom.BufferUtils;
import com.google.common.collect.Lists;
import com.google.common.collect.Maps;
import com.google.common.collect.Sets;

public class AwtTextureSource implements TextureSource, ElementUpdateListener {
    private static final int tileSize = 128;
    private final int availableClipmapLevels;

    private final AwtElementProvider provider;
    private final TextureStoreFormat format;
    private final boolean hasAlpha;

    private final BufferedImage _image[];
    private final Set<Tile> _updatedTiles[];

    private final ThreadLocal<byte[]> tileDataPool = new ThreadLocal<byte[]>() {
        @Override
        protected byte[] initialValue() {
            return new byte[tileSize * tileSize * (hasAlpha ? 4 : 3)];
        }
    };

    @SuppressWarnings("unchecked")
    public AwtTextureSource(final int availableClipmapLevels, final TextureStoreFormat format) {
        if (format != TextureStoreFormat.RGB8 && format != TextureStoreFormat.RGBA8) {
            throw new IllegalArgumentException("Only RGB8 and RGBA8 currently supported.");
        }

        this.availableClipmapLevels = availableClipmapLevels;
        this.format = format;
        hasAlpha = format == TextureStoreFormat.RGBA8;

        _image = new BufferedImage[availableClipmapLevels];
        _updatedTiles = new Set[availableClipmapLevels];

        provider = new AwtElementProvider();
        provider.addElementUpdateListener(this);

        for (int i = 0; i < availableClipmapLevels; i++) {
            _image[i] = new BufferedImage(tileSize, tileSize, BufferedImage.TYPE_INT_ARGB);
            _updatedTiles[i] = Sets.newHashSet();
        }
    }

    public AwtElementProvider getProvider() {
        return provider;
    }

    @Override
    public TextureConfiguration getConfiguration() throws Exception {
        final Map<Integer, TextureStoreFormat> textureStoreFormat = Maps.newHashMap();
        textureStoreFormat.put(0, format);

        return new TextureConfiguration(availableClipmapLevels, textureStoreFormat, tileSize, 1f, false, true);
    }

    @Override
    public Set<Tile> getValidTiles(final int clipmapLevel, final int tileX, final int tileY, final int numTilesX,
            final int numTilesY) throws Exception {
        return null;
    }

    @Override
    public Set<Tile> getInvalidTiles(final int clipmapLevel, final int tileX, final int tileY, final int numTilesX,
            final int numTilesY) throws Exception {
        final int baseClipmapLevel = availableClipmapLevels - clipmapLevel - 1;

        if (_updatedTiles[baseClipmapLevel].isEmpty()) {
            return null;
        }

        final Set<Tile> tiles = Sets.newHashSet();

        int checkX, checkY;
        for (final Iterator<Tile> it = _updatedTiles[baseClipmapLevel].iterator(); it.hasNext();) {
            final Tile tile = it.next();
            checkX = tile.getX();
            checkY = tile.getY();
            if (checkX >= tileX && checkX < tileX + numTilesX && checkY >= tileY && checkY < tileY + numTilesY) {
                tiles.add(tile);
                it.remove();
            }
        }

        return tiles;
    }

    @Override
    public int getContributorId(final int clipmapLevel, final Tile sourceTile) {
        return 0;
    }

    @Override
    public ByteBuffer getTile(final int clipmapLevel, final Tile tile) throws Exception {
        final int tileX = tile.getX();
        final int tileY = tile.getY();

        final int baseClipmapLevel = availableClipmapLevels - clipmapLevel - 1;

        // build a transform that would take us to the local space of the tile.
        final Transform localTransform = new Transform();
        localTransform.setTranslation(-tileX * tileSize, -tileY * tileSize, 0);
        final double scale = 1.0 / MathUtils.pow2(baseClipmapLevel);
        localTransform.setScale(scale);

        final double tileInScale = MathUtils.pow2(baseClipmapLevel) * tileSize;
        final double minX = tileInScale * tileX;
        final double minY = tileInScale * tileY;
        final double maxX = minX + tileInScale - 1;
        final double maxY = minY + tileInScale - 1;

        // Clear image
        final Graphics2D graphics = (Graphics2D) _image[baseClipmapLevel].getGraphics();
        final Composite composite = graphics.getComposite();
        // TODO: Add: do regular clear with black if no alpha channel right?
        graphics.setComposite(AlphaComposite.getInstance(AlphaComposite.CLEAR));
        graphics.fillRect(0, 0, tileSize, tileSize);
        graphics.setComposite(composite);

        // get list of elements that intersect the given region
        final List<AbstractAwtElement> elements = Lists.newArrayList(provider.getElements());
        for (final Iterator<AbstractAwtElement> it = elements.iterator(); it.hasNext();) {
            final AbstractAwtElement element = it.next();

            // check bounds to toss it or keep it.
            final ReadOnlyVector4 bounds = element.getBounds();

            if (bounds.getX() > maxX || bounds.getX() + bounds.getZ() <= minX || bounds.getY() > maxY
                    || bounds.getY() + bounds.getW() <= minY) {
                // toss it
                it.remove();
            }
        }

        // make our buffer - init to all 0's
        final ByteBuffer data = BufferUtils.createByteBufferOnHeap(tileSize * tileSize * (hasAlpha ? 4 : 3));

        // shortcut - no data, return buffer.
        if (elements.isEmpty()) {
            // graphics.setBackground((tileX + tileY) % 2 == 0 ? Color.GREEN : Color.GRAY);
            // graphics.clearRect(0, 0, tileSize, tileSize);
            return data;
        }

        // otherwise draw... for each element, apply to our image.
        for (final AbstractAwtElement element : elements) {
            element.drawTo(_image[baseClipmapLevel], localTransform, clipmapLevel);
        }

        // if (clipmapLevel == 0) {
        // graphics.setBackground((tileX + tileY) % 2 == 0 ? Color.GREEN : Color.GRAY);
        // graphics.clearRect(0, 0, tileSize, tileSize);
        // }

        // grab image contents to buffer
        final byte[] byteArray = tileDataPool.get();
        final DataBufferInt dataBuffer = (DataBufferInt) _image[baseClipmapLevel].getData().getDataBuffer();
        final int[] tmpData = dataBuffer.getData();
        int index = 0;
        for (int i = 0; i < tileSize * tileSize; i++) {
            final int argb = tmpData[i];
            byteArray[index++] = (byte) (argb >> 16 & 0xFF);
            byteArray[index++] = (byte) (argb >> 8 & 0xFF);
            byteArray[index++] = (byte) (argb & 0xFF);
            if (hasAlpha) {
                byteArray[index++] = (byte) (argb >> 24 & 0xFF);
            }
        }

        data.put(byteArray);
        data.flip();

        // return buffer
        return data;
    }

    @Override
    public void elementUpdated(final ReadOnlyVector4 oldBounds, final ReadOnlyVector4 newBounds) {
        addTiles(oldBounds);
        addTiles(newBounds);
    }

    protected void addTiles(final ReadOnlyVector4 bounds) {
        for (int i = 0; i < availableClipmapLevels; i++) {
            final double scale = 1.0 / (tileSize * MathUtils.pow2(i));
            final int minX = (int) MathUtils.floor(bounds.getX() * scale);
            final int minY = (int) MathUtils.floor(bounds.getY() * scale);
            final int maxX = (int) MathUtils.floor((bounds.getX() + bounds.getZ() - 1) * scale);
            final int maxY = (int) MathUtils.floor((bounds.getY() + bounds.getW() - 1) * scale);

            Tile tile;
            for (int y = minY; y <= maxY; y++) {
                for (int x = minX; x <= maxX; x++) {
                    tile = new Tile(x, y);
                    _updatedTiles[i].add(tile);
                }
            }
        }
    }
}
TOP

Related Classes of com.ardor3d.extension.terrain.providers.awt.AwtTextureSource

TOP
Copyright © 2018 www.massapi.com. All rights reserved.
All source code are property of their respective owners. Java is a trademark of Sun Microsystems, Inc and owned by ORACLE Inc. Contact coftware#gmail.com.