MaterialPreviewer.java :  » Graphic-3D » Art-of-Illusion » ArtOfIllusion » Java Open Source

Java Open Source » Graphic 3D » Art of Illusion 
Art of Illusion » ArtOfIllusion » MaterialPreviewer.java
/* Copyright (C) 1999-2009 by Peter Eastman

   This program is free software; you can redistribute it and/or modify it under the
   terms of the GNU General Public License as published by the Free Software
   Foundation; either version 2 of the License, or (at your option) any later version.

   This program 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 General Public License for more details. */

package artofillusion;

import artofillusion.image.*;
import artofillusion.material.*;
import artofillusion.math.*;
import artofillusion.object.*;
import artofillusion.texture.*;
import artofillusion.ui.*;
import buoy.event.*;
import buoy.widget.*;
import java.awt.*;
import java.awt.event.*;

/** MaterialPreviewer is a component used for renderering previews of Materials.  It displays
    a scene consisting of a Sphere with the desired Material applied to it, a ground plane,
    and a single light.  Optionally, an Object3D may be specified which will then be used
    instead of a Sphere. */

public class MaterialPreviewer extends CustomWidget implements RenderListener
{
  Scene theScene;
  Camera theCamera;
  ObjectInfo info;
  CoordinateSystem objectCoords;
  Image theImage;
  boolean mouseInside, renderInProgress;
  Point clickPoint;
  private Mat4 dragTransform;
  private Object3D shape[];

  public static final int HANDLE_SIZE = 5;
  static final double DRAG_SCALE = Math.PI/360.0;

  /** Create a MaterialPreviewer to display a Texture and/or Material mapped to a sphere.
      Either tex or mat may be null. */

  public MaterialPreviewer(Texture tex, Material mat, int width, int height)
  {
    shape = new Object3D [] {
        new Sphere(1.0, 1.0, 1.0),
        new Cube(2.0, 2.0, 2.0),
        new Cylinder(2.0, 1.0, 1.0, 1.0),
        new Cylinder(2.0, 1.0, 1.0, 0.0)
      };
    ObjectInfo objInfo = new ObjectInfo(shape[0], new CoordinateSystem(), "");
    initObject(tex, mat, objInfo);
    init(objInfo, width, height);
  }
  
  /** Same as above, except you can specify a different object to use instead of a sphere. */

  public MaterialPreviewer(Texture tex, Material mat, Object3D obj, int width, int height)
  {
    ObjectInfo objInfo = new ObjectInfo(obj, new CoordinateSystem(), "");
    initObject(tex, mat, objInfo);
    init(objInfo, width, height);
  }

  /** Create a MaterialPreviewer to display the specified object, with its current texture
      and material. */

  public MaterialPreviewer(ObjectInfo obj, int width, int height)
  {
    init(obj.duplicate(), width, height);
  }
  
  /** Initialize the object's texture and material. */
  
  private void initObject(Texture tex, Material mat, ObjectInfo objInfo)
  {
    if (tex == null)
      tex = UniformTexture.invisibleTexture();
    objInfo.setTexture(tex, tex.getDefaultMapping(objInfo.getObject()));
    if (mat != null)
      objInfo.setMaterial(mat, mat.getDefaultMapping(objInfo.getObject()));
  }
  
  /** Initialize the MaterialPreviewer. */
  
  private void init(ObjectInfo obj, int width, int height)
  {
    BoundingBox bounds = obj.getBounds();
    Vec3 size = bounds.getSize();
    double max = Math.max(size.x, Math.max(size.y, size.z))/2.0;
    double floor = -bounds.getSize().length()/2.0;
    CoordinateSystem coords = new CoordinateSystem(new Vec3(0.0, 0.0, 10.0*max), new Vec3(0.0, 0.0, -1.0), Vec3.vy());
    if (max > 10.0)
      max = 10.0;
    Vec3 vert[] = new Vec3 [] {new Vec3(100.0*max, floor, 100.0*max), new Vec3(-100.0*max, floor, 100.0*max), new Vec3(0.0, floor, -100.0*max)};
    int face[][] = {{0, 1, 2}};
    TriangleMesh tri;

    theScene = new Scene();
    theCamera = new Camera();
    theCamera.setCameraCoordinates(coords);
    coords = new CoordinateSystem(new Vec3(), new Vec3(-0.5, -0.4, -1.0), Vec3.vy());
    theScene.addObject(new DirectionalLight(new RGBColor(1.0f, 1.0f, 1.0f), 0.8f), coords, "", null);
    coords = new CoordinateSystem(new Vec3(), Vec3.vz(), Vec3.vy());
    theScene.addObject(tri = new TriangleMesh(vert, face), coords, "", null);
    Texture tex = theScene.getDefaultTexture();
    tri.setTexture(tex, tex.getDefaultMapping(tri));
    info = obj;
    info.setCoords(new CoordinateSystem());
    objectCoords = info.getCoords();
    theScene.addObject(info, null);
    setPreferredSize(new Dimension(width, height));
    addEventLink(MousePressedEvent.class, this, "mousePressed");
    addEventLink(MouseReleasedEvent.class, this, "mouseReleased");
    addEventLink(MouseClickedEvent.class, this, "mouseClicked");
    addEventLink(MouseEnteredEvent.class, this, "mouseEntered");
    addEventLink(MouseExitedEvent.class, this, "mouseExited");
    addEventLink(MouseDraggedEvent.class, this, "mouseDragged");
    addEventLink(RepaintEvent.class, this, "paint");

    // Set up other listeners.
    
    getComponent().addComponentListener(new ComponentAdapter() {
      public void componentResized(ComponentEvent ev)
      {
        render();
      }
    });
    getComponent().addHierarchyListener(new HierarchyListener() {
      public void hierarchyChanged(HierarchyEvent ev)
      {
        if ((ev.getChangeFlags()&HierarchyEvent.DISPLAYABILITY_CHANGED) != 0)
          if (!getComponent().isDisplayable())
          {
            Renderer rend = ArtOfIllusion.getPreferences().getTexturePreviewRenderer();
            if (rend != null)
              rend.cancelRendering(theScene);
          }
      }
    });
    render();
  }
  
  /** Get the object on which the texture and material are being displayed. */
  
  public ObjectInfo getObject()
  {
    return info;
  }

  /** Get the scene being rendererd as the preview. */

  public Scene getScene()
  {
    return theScene;
  }
  
  /* The following methods are used to modify the properties of the object being displayed. */

  public void setTexture(Texture tex, TextureMapping map)
  {
    if (tex == null)
      tex = UniformTexture.invisibleTexture();
    if (map == null)
      map = tex.getDefaultMapping(info.getObject());
    info.setTexture(tex, map);
  }
  
  public void setMaterial(Material mat, MaterialMapping map)
  {
    info.setMaterial(mat, map);
  }

  /** Render the preview. */

  public synchronized void render()
  {
    Renderer rend = ArtOfIllusion.getPreferences().getTexturePreviewRenderer();
    if (rend == null)
      return;
    rend.cancelRendering(theScene);
    Rectangle bounds = getBounds();
    if (bounds.width == 0 || bounds.height == 0)
      return;
    SceneCamera sc = new SceneCamera();
    sc.setFieldOfView(16.0);
    theCamera.setScreenTransform(sc.getScreenTransform(bounds.width, bounds.height), bounds.width, bounds.height);
    rend.configurePreview();
    rend.renderScene(theScene, theCamera, this, sc);
    renderInProgress = true;
    repaint();
  }

  /** Cancel rendering. */
  
  public synchronized void cancelRendering()
  {
    Renderer rend = ArtOfIllusion.getPreferences().getTexturePreviewRenderer();
    if (rend != null)
      rend.cancelRendering(theScene);
  }

  private void paint(RepaintEvent ev)
  {
    Graphics2D g = ev.getGraphics();
    if (theImage != null)
      g.drawImage(theImage, 0, 0, getComponent());
    if (mouseInside)
      drawHilight(g);
    if (renderInProgress)
      {
        Rectangle bounds = getBounds();
        g.setColor(Color.red);
        g.drawRect(0, 0, bounds.width-1, bounds.height-1);
      }
  }

  private void drawHilight(Graphics g)
  {
    Rectangle bounds = getBounds();
    g.setColor(Color.red);
    g.fillRect(0, 0, HANDLE_SIZE, HANDLE_SIZE);
    g.fillRect(bounds.width-HANDLE_SIZE, 0, HANDLE_SIZE, HANDLE_SIZE);
    g.fillRect(0, bounds.height-HANDLE_SIZE, HANDLE_SIZE, HANDLE_SIZE);
    g.fillRect(bounds.width-HANDLE_SIZE, bounds.height-HANDLE_SIZE, HANDLE_SIZE, HANDLE_SIZE);
  }

  private void drawObject(Graphics g)
  {
    g.setColor(Color.gray);
    Vec3 origin = objectCoords.getOrigin();
    Mat4 m = objectCoords.fromLocal();
    m = Mat4.translation(-origin.x, -origin.y, -origin.z).times(m);
    m = dragTransform.times(m);
    m = Mat4.translation(origin.x, origin.y, origin.z).times(m);
    theCamera.setObjectTransform(m);
    WireframeMesh mesh = info.getObject().getWireframeMesh();
    int from[] = mesh.from, to[] = mesh.to, last = -1;
    Vec3 vert[] = mesh.vert;
    for (int i = 0; i < mesh.from.length; i++)
    {
      if (from[i] == last)
        theCamera.drawClippedLineTo(g, vert[(last=to[i])]);
      else
        theCamera.drawClippedLine(g, vert[from[i]], vert[(last=to[i])]);
    }
  }
  
  /** Rotate the object to show a specific side. */
  
  private void changeView(int view)
  {
    double angles[][] = new double [][] {
        {0.0, 0.0, 0.0}, 
        {0.0, 180.0, 0.0}, 
        {0.0, -90.0, 0.0}, 
        {0.0, 90.0, 0.0}, 
        {-90.0, 0.0, 0.0}, 
        {90.0, 0.0, 0.0}, 
    };
    objectCoords.setOrientation(angles[view][0], angles[view][1], angles[view][2]);
    objectCoords.setOrigin(new Vec3());
    render();
  }
  
  /** Change what object the texture/material is displayed ob. */
  
  private void changeObject(int object)
  {
    shape[object].setTexture(info.getObject().getTexture(), info.getObject().getTextureMapping());
    shape[object].setMaterial(info.getObject().getMaterial(), info.getObject().getMaterialMapping());
    info.setObject(shape[object]);
    render();
  }

  /** Called when more pixels are available for the current image. */
  
  public void imageUpdated(Image image)
  {
    theImage = image;
    repaint();
  }

  /** The renderer may call this method periodically during rendering, to give the listener text descriptions
      of the current status of rendering. */
  
  public void statusChanged(String status)
  {
  }

  /** Called when rendering is complete. */
  
  public void imageComplete(ComplexImage image)
  {
    theImage = image.getImage();
    renderInProgress = false;
    repaint();
  }
  
  /** Called when rendering is cancelled. */
  
  public void renderingCanceled()
  {
  }

  private void mouseEntered(MouseEnteredEvent e)
  {
    mouseInside = true;
    Graphics g = getComponent().getGraphics();
    drawHilight(g);
    g.dispose();
  }
  
  private void mouseExited(MouseExitedEvent e)
  {
    mouseInside = false;
    repaint();
  }
  
  private void mousePressed(MousePressedEvent e)
  {
    Graphics g = getComponent().getGraphics();
    clickPoint = e.getPoint();
    Renderer rend = ArtOfIllusion.getPreferences().getTexturePreviewRenderer();
    if (rend != null)
      rend.cancelRendering(theScene);
    dragTransform = Mat4.identity();
    drawObject(g);
    g.dispose();
  }

  private void mouseReleased(MouseReleasedEvent e)
  {
    if (clickPoint == null)
      return;
    Point dragPoint = e.getPoint();
    if (!clickPoint.equals(dragPoint))
    {
      if (e.isMetaDown())
      {
        if (e.isControlDown())
          dragTransform = Mat4.translation(0.0, 0.0, (dragPoint.y-clickPoint.y)*0.01);
        else
          dragTransform = Mat4.translation((dragPoint.x-clickPoint.x)*0.01, (clickPoint.y-dragPoint.y)*0.01, 0.0);
        objectCoords.transformOrigin(dragTransform);
      }
      else
      {
        Vec3 rotAxis = new Vec3((clickPoint.y-dragPoint.y)*DRAG_SCALE, (dragPoint.x-clickPoint.x)*DRAG_SCALE, 0.0);
        double angle = rotAxis.length();
        rotAxis = rotAxis.times(1.0/angle);
        rotAxis = theCamera.getViewToWorld().timesDirection(rotAxis);
        dragTransform = Mat4.axisRotation(rotAxis, angle);
        objectCoords.transformAxes(dragTransform);
      }
    }
    render();
  }

  private void mouseClicked(MouseClickedEvent e)
  {
    if (e.getClickCount() == 2)
      showConfigurationDialog();
  }

  private void mouseDragged(MouseDraggedEvent e)
  {
    if (clickPoint == null)
      return;
    Graphics g = getComponent().getGraphics();
    Point dragPoint = e.getPoint();
    if (e.isMetaDown())
    {
      if (e.isControlDown())
        dragTransform = Mat4.translation(0.0, 0.0, (dragPoint.y-clickPoint.y)*0.01);
      else
        dragTransform = Mat4.translation((dragPoint.x-clickPoint.x)*0.01, (clickPoint.y-dragPoint.y)*0.01, 0.0);
    }
    else
    {
      Vec3 rotAxis = new Vec3((clickPoint.y-dragPoint.y)*DRAG_SCALE, (dragPoint.x-clickPoint.x)*DRAG_SCALE, 0.0);
      double angle = rotAxis.length();
      rotAxis = rotAxis.times(1.0/angle);
      rotAxis = theCamera.getViewToWorld().timesDirection(rotAxis);
      dragTransform = Mat4.axisRotation(rotAxis, angle);
    }
    g.drawImage(theImage, 0, 0, getComponent());
    drawHilight(g);
    drawObject(g);
    g.dispose();
  }

  /**
   * Show a dialog for configuring the view.
   */

  private void showConfigurationDialog()
  {
    BComboBox viewChoice = new BComboBox(new String [] {
      "",
      Translate.text("Front"),
      Translate.text("Back"),
      Translate.text("Left"),
      Translate.text("Right"),
      Translate.text("Top"),
      Translate.text("Bottom")
    });
    BComboBox shapeChoice = new BComboBox(new String [] {
      Translate.text("menu.sphere"),
      Translate.text("menu.cube"),
      Translate.text("menu.cylinder"),
      Translate.text("menu.cone")
    });
    ComponentsDialog dlg;
    if (shape == null)
      dlg = new ComponentsDialog(UIUtilities.findWindow(this), Translate.text("configurePreview"),
          new Widget [] {viewChoice}, new String [] {Translate.text("resetViewTo")});
    else
    {
      for (int i = 0; i < shape.length; i++)
      if (shape[i] == info.getObject())
        shapeChoice.setSelectedIndex(i);
      dlg = new ComponentsDialog(UIUtilities.findWindow(this), Translate.text("configurePreview"),
          new Widget [] {shapeChoice, viewChoice}, new String [] {Translate.text("Shape"), Translate.text("resetViewTo")});
    }
    if (!dlg.clickedOk())
      return;
    if (shape != null && shape[shapeChoice.getSelectedIndex()] != info.getObject())
      changeObject(shapeChoice.getSelectedIndex());
    if (viewChoice.getSelectedIndex() > 0)
      changeView(viewChoice.getSelectedIndex()-1);
  }
}
java2s.com  | Contact Us | Privacy Policy
Copyright 2009 - 12 Demo Source and Support. All rights reserved.
All other trademarks are property of their respective owners.