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}