001/*
002
003*/
004
005package renderer.gui;
006import  renderer.framebuffer.FrameBuffer;
007
008import java.awt.Graphics;
009import java.awt.Graphics2D;
010import java.awt.Dimension;
011import java.awt.Image;
012import java.awt.image.MemoryImageSource;
013import javax.swing.JPanel;
014
015/**
016   This class is an interface between our renderer and the Java GUI system.
017<p>
018   This class is meant to be instantiated as a sub-panel of a
019   {@link javax.swing.JFrame}. The {@link javax.swing.JFrame} may or may
020   not implement event listeners. If the {@link javax.swing.JFrame} does
021   implement event listeners, then the event listeners can make our
022   renderer interactive.
023<p>
024   Each instance of {@code FrameBufferPanel} has a reference to a
025   {@link FrameBuffer} object and the {@link FrameBuffer} object
026   determines the (preferred) dimensions of this {@link JPanel}.
027<p>
028   When a GUI event happens, any implemented event listener would update
029   this {@link JPanel} by modifying a {@link renderer.scene.Scene} object
030   appropriately and then having our renderer render the
031   {@link renderer.scene.Scene} object into the {@link FrameBuffer}.
032   When the renderer is done updating the {@link FrameBuffer}, the
033   event listener will call this objects {@link #update} method, which will
034   pass the {@link FrameBuffer}'s pixel data to the {@link java.awt.Image}
035   being drawn on the {@link java.awt.Graphics context of the
036   {@link FrameBufferPanel} (which is a {@link JPanel}). Then the event
037   listener will call the {@link javax.swing.JFrame}'s repaint() method
038   which will trigger this object's {@link #paintComponent} method. This
039   will display the {@link java.awt.Image} (that holds the
040   {@link FrameBuffer}'s contents) in the {@link JPanel} within this
041   {@link JFrame}'s window.
042<p>
043   This panel may be resizeable. When this panel resizes, its
044   {@link FrameBuffer} object will also need to resize. But
045   {@link FrameBuffer} objects cannot be resized. So each time this
046   panel resizes, the resize event handler should instantiate a new
047   {@link FrameBuffer} object with the appropriate dimensions and
048   then call this object's setFrameBuffer() method with a reference
049   to the new {@link FrameBuffer} object.
050*/
051@SuppressWarnings("serial")
052public class FrameBufferPanel extends JPanel
053{
054   private FrameBuffer fb;
055   private MemoryImageSource source;
056   private Image img;
057
058   /**
059      @param fb  {@link FrameBuffer} used by this {@link JPanel}
060   */
061   public FrameBufferPanel(FrameBuffer fb)
062   {
063      setFrameBuffer(fb);
064   }
065
066
067   @Override
068   public Dimension getPreferredSize()
069   {
070      return new Dimension(fb.getWidthFB(), fb.getHeightFB());
071   }
072
073
074   @Override
075   protected void paintComponent(Graphics g)
076   {
077      super.paintComponent(g);
078
079      Graphics2D g2 = (Graphics2D)g.create();
080      g2.drawImage(img, 0, 0, this);
081      g2.dispose();
082   }
083
084
085   /**
086      Accessor method for the {@link FrameBuffer} currently being used as
087      the source for the {@link java.awt.Image} painted on this {@link JPanel}.
088
089      @return a reference to the {@link FrameBuffer} owned by this {@link JPanel}
090   */
091   public FrameBuffer getFrameBuffer()
092   {
093      return fb;
094   }
095
096
097   /**
098      This method should be called when this {@code FrameBufferPanel}'s
099      {@link FrameBuffer} object has been updated by the renderer.
100   */
101   public void update()
102   {
103      // Send the new pixel data to the ImageConsumer.
104      this.source.newPixels();
105   }
106
107
108   /**
109      Change the {@link FrameBuffer} being used as the source for
110      the {@link java.awt.Image} painted on this {@link JPanel}.
111   <p>
112      This will usually be in response to a call to the
113      componentResized() event handler.
114
115      @param fb  new {@link FrameBuffer} object for this {@link JPanel}
116   */
117   public void setFrameBuffer(FrameBuffer fb)
118   {
119      this.fb = fb;
120
121      // Use the framebuffer as the source for an Image.
122      this.source = new MemoryImageSource(fb.getWidthFB(), fb.getHeightFB(),
123                                          fb.pixel_buffer,
124                                          0, fb.getWidthFB());
125      this.source.setAnimated(true);
126      this.img = createImage(this.source);
127   }
128}