Package com.ardor3d.framework.lwjgl

Source Code of com.ardor3d.framework.lwjgl.LwjglCanvas

/**
* 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.framework.lwjgl;

import java.nio.ByteBuffer;
import java.util.concurrent.CountDownLatch;
import java.util.logging.Level;
import java.util.logging.Logger;

import org.lwjgl.LWJGLException;
import org.lwjgl.opengl.Display;
import org.lwjgl.opengl.DisplayMode;
import org.lwjgl.opengl.PixelFormat;

import com.ardor3d.annotation.MainThread;
import com.ardor3d.framework.CanvasRenderer;
import com.ardor3d.framework.DisplaySettings;
import com.ardor3d.framework.NativeCanvas;
import com.ardor3d.image.Image;
import com.ardor3d.image.ImageDataFormat;
import com.ardor3d.image.PixelDataType;
import com.ardor3d.input.FocusWrapper;
import com.ardor3d.util.Ardor3dException;
import com.ardor3d.util.geom.BufferUtils;

/**
* A canvas implementation for use with native LWJGL windows.
*/
public class LwjglCanvas implements NativeCanvas, FocusWrapper {
    private static final Logger logger = Logger.getLogger(LwjglCanvas.class.getName());

    private final LwjglCanvasRenderer _canvasRenderer;

    private final DisplaySettings _settings;
    private boolean _inited = false;

    private volatile boolean _focusLost = false;

    /**
     * If true, we will not try to drop and reclaim the context on each frame.
     */
    public static boolean SINGLE_THREADED_MODE = true;

    public LwjglCanvas(final DisplaySettings settings, final LwjglCanvasRenderer canvasRenderer) {
        _canvasRenderer = canvasRenderer;
        _canvasRenderer.setCanvasCallback(new LwjglCanvasCallback() {
            @Override
            public void makeCurrent() throws LWJGLException {
                if (!SINGLE_THREADED_MODE) {
                    Display.makeCurrent();
                }
            }

            @Override
            public void releaseContext() throws LWJGLException {
                if (!SINGLE_THREADED_MODE) {
                    Display.releaseContext();
                }
            }
        });
        _settings = settings;
    }

    public boolean getAndClearFocusLost() {
        final boolean result = _focusLost;

        _focusLost = false;

        return result;
    }

    @MainThread
    // hm, seem to have to control the order of initialization: display first, then keyboard/etc, in native windows
    public void init() {
        if (_inited) {
            return;
        }

        // create the Display.
        DisplayMode mode;
        if (_settings.isFullScreen()) {
            mode = getValidDisplayMode(_settings);
            if (null == mode) {
                throw new Ardor3dException("Bad display mode (w/h/bpp/freq): " + _settings.getWidth() + " / "
                        + _settings.getHeight() + " / " + _settings.getColorDepth() + " / " + _settings.getFrequency());
            }
        } else {
            mode = new DisplayMode(_settings.getWidth(), _settings.getHeight());
        }

        final PixelFormat format = new PixelFormat(_settings.getAlphaBits(), _settings.getDepthBits(),
                _settings.getStencilBits()).withSamples(_settings.getSamples()).withStereo(_settings.isStereo());

        try {
            Display.setDisplayMode(mode);
            Display.setFullscreen(_settings.isFullScreen());
            Display.create(format);
        } catch (final Exception e) {
            logger.severe("Cannot create window");
            logger.logp(Level.SEVERE, this.getClass().toString(), "initDisplay()", "Exception", e);
            throw new Ardor3dException("Cannot create window: " + e.getMessage());
        }

        _canvasRenderer.init(_settings, true); // true - do swap in renderer.
        _inited = true;
    }

    @MainThread
    public void draw(final CountDownLatch latch) {
        if (!_inited) {
            init();
        }

        checkFocus();

        _canvasRenderer.draw();

        if (latch != null) {
            latch.countDown();
        }
    }

    private void checkFocus() {
        // focusLost should be true if it is already true (hasn't been read/cleared yet), or
        // the display is presently not in focus
        _focusLost = _focusLost || !(Display.isActive() && Display.isVisible());

        //
        // final boolean newFocus =
        //
        // if (!focusLost && newFocus) {
        // // didn't use to have focus, but now we do
        // // do nothing for now, just keep track of the fact that we have focus
        // focusLost = newFocus;
        // } else if (focusLost && !newFocus) {
        // // had focus, but don't anymore - notify the physical input layer
        // physicalLayer.lostFocus();
        // focusLost = newFocus;
        // }
    }

    public CanvasRenderer getCanvasRenderer() {
        return _canvasRenderer;
    }

    /**
     * @return a <code>DisplayMode</code> object that has the requested settings. If there is no mode that supports a
     *         requested resolution, null is returned.
     */
    private DisplayMode getValidDisplayMode(final DisplaySettings settings) {
        // get all the modes, and find one that matches our settings.
        DisplayMode[] modes;
        try {
            modes = Display.getAvailableDisplayModes();
        } catch (final LWJGLException e) {
            logger.logp(Level.SEVERE, this.getClass().toString(), "getValidDisplayMode(width, height, bpp, freq)",
                    "Exception", e);
            return null;
        }

        // Try to find a best match.
        int best_match = -1; // looking for request size/bpp followed by exact or highest freq
        int match_freq = -1;
        for (int i = 0; i < modes.length; i++) {
            if (modes[i].getWidth() != settings.getWidth()) {
                logger.fine("DisplayMode " + modes[i] + ": Width != " + settings.getWidth());
                continue;
            }
            if (modes[i].getHeight() != settings.getHeight()) {
                logger.fine("DisplayMode " + modes[i] + ": Height != " + settings.getHeight());
                continue;
            }
            if (settings.getColorDepth() != 0 && modes[i].getBitsPerPixel() != settings.getColorDepth()) {
                // should pick based on best match here too
                logger.fine("DisplayMode " + modes[i] + ": Bits per pixel != " + settings.getColorDepth());
                continue;
            }
            if (best_match == -1) {
                logger.fine("DisplayMode " + modes[i] + ": Match! ");
                best_match = i;
                match_freq = modes[i].getFrequency();
            } else {
                final int cur_freq = modes[i].getFrequency();
                if (match_freq != settings.getFrequency() && // Previous is not a perfect match
                        (cur_freq == settings.getFrequency() || // Current is perfect match
                        match_freq < cur_freq)) // or is higher freq
                {
                    logger.fine("DisplayMode " + modes[i] + ": Better match!");
                    best_match = i;
                    match_freq = cur_freq;
                }
            }
        }

        if (best_match == -1) {
            return null; // none found;
        } else {
            logger.info("Selected DisplayMode: " + modes[best_match]);
            return modes[best_match];
        }
    }

    public void close() {
        if (Display.isCreated()) {
            Display.destroy();
        }
    }

    public boolean isActive() {
        return Display.isCreated() && Display.isActive();
    }

    @MainThread
    public boolean isClosing() {
        return Display.isCreated() && Display.isCloseRequested();
    }

    public void moveWindowTo(final int locX, final int locY) {
        if (Display.isCreated()) {
            Display.setLocation(locX, locY);
        }
    }

    public void setIcon(final Image[] iconImages) {
        final ByteBuffer[] iconData = new ByteBuffer[iconImages.length];
        for (int i = 0; i < iconData.length; i++) {
            // Image.Format.RGBA8 is the format that LWJGL requires, so try to convert if it's not.
            if (iconImages[i].getDataType() != PixelDataType.UnsignedByte) {
                throw new Ardor3dException(
                        "Your icon is in a format that could not be converted to UnsignedByte - RGBA");
            }

            if (iconImages[i].getDataFormat() != ImageDataFormat.RGBA) {
                if (iconImages[i].getDataFormat() != ImageDataFormat.RGB) {
                    throw new Ardor3dException(
                            "Your icon is in a format that could not be converted to UnsignedByte - RGBA");
                }
                iconImages[i] = _RGB888_to_RGBA8888(iconImages[i]);
            }

            iconData[i] = iconImages[i].getData(0);
            iconData[i].rewind();
        }
        Display.setIcon(iconData);
    }

    private static Image _RGB888_to_RGBA8888(final Image rgb888) {
        final int size = rgb888.getWidth() * rgb888.getHeight() * 4;

        final ByteBuffer rgb = rgb888.getData(0);

        final ByteBuffer rgba8888 = BufferUtils.createByteBuffer(size);
        rgb.rewind();
        for (int j = 0; j < size; j++) {
            if ((j + 1) % 4 == 0) {
                rgba8888.put((byte) 0xFF);
            } else {
                rgba8888.put(rgb.get());
            }
        }
        return new Image(ImageDataFormat.RGBA, PixelDataType.UnsignedByte, rgb888.getWidth(), rgb888.getHeight(),
                rgba8888, null);
    }

    public void setTitle(final String title) {
        Display.setTitle(title);
    }

    public void setVSyncEnabled(final boolean enabled) {
        Display.setVSyncEnabled(enabled);
    }
}
TOP

Related Classes of com.ardor3d.framework.lwjgl.LwjglCanvas

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.