edu.csun.ecs.cs.multitouchj.application.whiteboard.ui.InteractiveCanvas.java Source code

Java tutorial

Introduction

Here is the source code for edu.csun.ecs.cs.multitouchj.application.whiteboard.ui.InteractiveCanvas.java

Source

/**
 * Copyright 2009 Atsuya Takagi
 *
 * 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 edu.csun.ecs.cs.multitouchj.application.whiteboard.ui;

import java.awt.BasicStroke;
import java.awt.Color;
import java.awt.Graphics2D;
import java.awt.Stroke;
import java.awt.image.BufferedImage;
import java.nio.ByteBuffer;
import java.nio.ByteOrder;
import java.util.Date;
import java.util.Hashtable;
import java.util.Iterator;
import java.util.LinkedList;
import java.util.List;
import java.util.Map;

import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
import org.lwjgl.opengl.DisplayMode;
import org.lwjgl.opengl.EXTTextureRectangle;
import org.lwjgl.opengl.GL11;

import edu.csun.ecs.cs.multitouchj.objectobserver.event.ObjectObserverEvent;
import edu.csun.ecs.cs.multitouchj.ui.control.Canvas;
import edu.csun.ecs.cs.multitouchj.ui.event.ControlEvent;
import edu.csun.ecs.cs.multitouchj.ui.event.ObjectEvent;
import edu.csun.ecs.cs.multitouchj.ui.event.TouchEvent;
import edu.csun.ecs.cs.multitouchj.ui.geometry.Point;
import edu.csun.ecs.cs.multitouchj.ui.geometry.Size;
import edu.csun.ecs.cs.multitouchj.ui.gesture.GestureHandler;
import edu.csun.ecs.cs.multitouchj.ui.graphic.image.Image;
import edu.csun.ecs.cs.multitouchj.ui.graphic.image.ResizableBufferedImage;
import edu.csun.ecs.cs.multitouchj.ui.graphic.image.Texture;

/**
 * @author Atsuya Takagi
 *
 * $Id: InteractiveCanvas.java 85 2009-03-16 07:04:24Z Atsuya Takagi $
 */
public class InteractiveCanvas extends Canvas {
    private static Log log = LogFactory.getLog(InteractiveCanvas.class);
    private static final long POINT_CLEAR_DURATION = 200;
    private Hashtable<Integer, LinkedList<Point>> previousPoints;
    private Hashtable<Integer, Long> previousTimes;
    private Hashtable<Integer, Pen> pens;
    private boolean isDirty;

    public InteractiveCanvas() {
        super();

        previousPoints = new Hashtable<Integer, LinkedList<Point>>();
        previousTimes = new Hashtable<Integer, Long>();
        pens = new Hashtable<Integer, Pen>();

        setDirty(true);
    }

    public void addPen(int id, Pen pen) {
        setPen(id, pen);
    }

    public void removePen(int id) {
        pens.remove(id);
    }

    public Pen getPen(int id) {
        return pens.get(id);
    }

    public Map<Integer, Pen> getPens() {
        return new Hashtable<Integer, Pen>(pens);
    }

    public void setPen(int id, Pen pen) {
        pens.put(id, pen);
    }

    public void clearCanvas(Color color) {
        synchronized (resizableBufferedImage) {
            BufferedImage bufferedImage = resizableBufferedImage.getBufferedImage();

            Graphics2D graphics = bufferedImage.createGraphics();
            graphics.setPaint(color);
            graphics.fillRect(0, 0, bufferedImage.getWidth(), bufferedImage.getHeight());
            graphics.dispose();

            setDirty(true);
        }
    }

    public void render() {
        synchronized (resizableBufferedImage) {
            Texture texture = getTexture();
            if (texture == null) {
                try {
                    Image image = getBufferedImageImage(resizableBufferedImage.getBufferedImage());
                    texture = getTextureManager().createTexture("" + this.hashCode(), image, true);
                    setTexture(texture);
                } catch (Exception exception) {
                    log.debug("Failed to generate texture from ResizableBufferedImage.", exception);
                }
            }

            if (isDirty) {
                Image image = getBufferedImageImage(resizableBufferedImage.getBufferedImage());
                ByteBuffer imageData = prepareImage(image);

                GL11.glEnable(EXTTextureRectangle.GL_TEXTURE_RECTANGLE_EXT);
                GL11.glBindTexture(EXTTextureRectangle.GL_TEXTURE_RECTANGLE_EXT, texture.getId().intValue());
                GL11.glTexSubImage2D(EXTTextureRectangle.GL_TEXTURE_RECTANGLE_EXT, 0, 0, 0, image.getWidth(),
                        image.getHeight(), (image.hasAlpha()) ? GL11.GL_RGBA : GL11.GL_RGB, GL11.GL_UNSIGNED_BYTE,
                        imageData);
                isDirty = false;
            }
        }

        super.render();
    }

    protected void onControlResized(ControlEvent controlEvent) {
        super.onControlResized(controlEvent);

        setDirty(true);
    }

    protected void onTouchStarted(TouchEvent touchEvent) {
        super.onTouchStarted(touchEvent);

        addPreviousPoints(touchEvent.getObjectObserverEvents());
    }

    protected void onTouchMoved(TouchEvent touchEvent) {
        super.onTouchMoved(touchEvent);

        addPreviousPoints(touchEvent.getObjectObserverEvents());
        drawPoints();
    }

    protected void onTouchEnded(TouchEvent touchEvent) {
        super.onTouchEnded(touchEvent);

        clearPreviousPoints();
    }

    protected boolean isDirty() {
        return isDirty;
    }

    protected void setDirty(boolean isDirty) {
        this.isDirty = isDirty;
    }

    protected void drawPoints() {
        synchronized (previousPoints) {
            synchronized (resizableBufferedImage) {
                // clear points for pen if it's been long since last changed
                long currentTime = new Date().getTime();
                for (int id : pens.keySet()) {
                    if (previousTimes.containsKey(id)) {
                        long time = previousTimes.get(id);
                        if ((currentTime - time) > POINT_CLEAR_DURATION) {
                            previousPoints.remove(id);
                            previousTimes.remove(id);
                        }
                    }
                }

                DisplayMode displayMode = getWindowManager().getDisplayManager().getCurrentDisplayMode();
                BufferedImage bufferedImage = resizableBufferedImage.getBufferedImage();

                Graphics2D graphics = bufferedImage.createGraphics();
                for (int id : pens.keySet()) {
                    Pen pen = pens.get(id);
                    LinkedList<Point> points = previousPoints.get(id);
                    if ((pen != null) && (points != null) && (points.size() > 1)) {
                        log.debug("id: " + id + ", points: " + points.size());

                        Point previousPoint = points.removeFirst();
                        Iterator<Point> iterator = points.iterator();
                        while (iterator.hasNext()) {
                            Point point = iterator.next();
                            if (iterator.hasNext()) {
                                iterator.remove();
                            }

                            graphics.setStroke(pen.getStroke());
                            graphics.setPaint(pen.getPaint());
                            graphics.drawLine((int) Math.floor(previousPoint.getX()),
                                    (displayMode.getHeight() - (int) Math.floor(previousPoint.getY())),
                                    (int) Math.floor(point.getX()),
                                    (displayMode.getHeight() - (int) Math.floor(point.getY())));

                            previousPoint = point;
                        }

                        setDirty(true);
                    }
                }
                graphics.dispose();
            }
        }
    }

    protected void addPreviousPoints(List<ObjectObserverEvent> objectObserverEvents) {
        synchronized (previousPoints) {
            for (ObjectObserverEvent ooe : objectObserverEvents) {
                LinkedList<Point> points = previousPoints.get(ooe.getId());
                if (points == null) {
                    points = new LinkedList<Point>();
                }

                points.add(new Point(ooe.getX(), ooe.getY()));
                previousPoints.put(ooe.getId(), points);
                previousTimes.put(ooe.getId(), ooe.getTime());
            }
        }
    }

    protected void clearPreviousPoints() {
        synchronized (previousPoints) {
            previousPoints.clear();
            previousTimes.clear();
        }
    }
}