630 likes | 1.07k Views
CS2. Module 41 Category: CS Concepts Topic: Graphics 1 Objectives Hardware Basic concepts Advanced Concepts. CS 2. Introduction to Object Oriented Programming Module 41 CS Concepts Graphics 1. Computer Graphics. Defined
E N D
CS2 • Module 41 • Category: CS Concepts • Topic: Graphics 1 • Objectives • Hardware • Basic concepts • Advanced Concepts
CS 2 Introduction to Object Oriented Programming Module 41 CS Concepts Graphics 1
Computer Graphics • Defined • Computer graphics involves the creation, storage, manipulation • and display of models and images of objects. • Sources for models include abstractions of physical, mathematical, engineering, architectural and conceptual structures. • Origins • Early: small specialized CRT displays and hardcopy plotting. • 1980s: desktop raster graphics with Apple Macintosh (and later, IBM PCs and clones). • Today: common interactive graphics (e.g., desktop and window managers).
Computer Graphics:Terminology Desktop computers use bitmap graphics: rectangular array of ones and zeros representing of array of points. These points constitute picture elements, or pixels or pels for short. A raster is a rectangular array of pixels. A scanline is an individual row of pixels Video raster devices display images by drawing pixels in sequence
Computer Graphics: Some Hardware Cathode Ray Tube (CRT) Monitors contain a filament that, when heated, emits electrons. The resulting beam of electrons is manipulated with electromagnets to target a specific point on a phosphor-coated screen. The screen’s phosphor dots glow briefly when struck. Note: These slides based on materials from Larry F. Hodges, who teaches an excellent course in Computer Graphics!
Computer Graphics:More Hardware Color CRTs have electron guns for Red, Blue and Green. The phosphor screen has triads of dots that emit R, B or G when struck: Triads might overlap; there are usually around 2.3 to 2.5 triads per pixel
More Hardware:Shadow Masks Convergence point A shadow mask is screen with a hole for each phosphor triad. The mask is precisely aligned so the 3 electron beams hit only one phosphor dot in the triad.
Hardware: Scanning Screen images are reduced to a raster, and drawn ("scanned") one scanline at a time. The drawing must be refreshed rapidly (usually 60x per second). Interlaced: Alternating even and odd rows are scanned at a lower rate (usually 30x per second). The alternating scan rows reduces flicker.
Hardware: Frame Buffers A frame buffer organizes computer memory into a 2D array. Each element corresponds to a pixel. Bit planes or bit depth describe the number of bits used to represent each pixel Example: 640 x 480 x 8 == 640 pixels wide, 480 pixels high, with one byte (8 bits) used to describe the color of each pixel. True color: 24 bitplanes with 8 bits per color. (2^24 = 16,777,216 unique colors)
Double Buffering 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 • Normally the monitor and computer are not synchronized • The computer puts things in the graphics buffer when it wants to and the graphics card sends the video image out as needed by the monitor Portion of memory Image produced
Double Buffering 0 0 0 0 0 0 0 0 0 1 1 1 1 1 1 0 0 1 0 0 0 0 1 0 0 1 0 0 0 0 1 0 0 1 1 1 1 1 1 0 0 0 0 0 0 0 0 0 • If we change the contents of the memory the image on the monitor changes Portion of memory Image produced
Double Buffering 0 0 0 0 0 0 0 0 0 1 1 1 1 1 1 0 0 1 0 0 0 0 1 0 0 1 0 0 0 0 1 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 • If the monitor were to need an image half way through changing memory we get an image based on what is in memory Portion of memory Image produced
The "bad" effect Initially the screen looks like this This shows up for a fraction of a second and causes an annoying flicker effect We want to change it to this
Solution: Double Buffering 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 STARTADDR Initially we use the top half of the buffer to form the image
Solution: Double Buffering 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 1 0 1 0 0 1 1 0 0 1 1 0 0 0 0 0 1 0 0 0 0 0 0 0 0 0 0 1 0 0 0 0 1 0 0 0 0 0 0 0 0 0 0 1 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 STARTADDR We make all the changes we want to the bottom portion and the user sees no "bad" effects
Solution: Double Buffering 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 1 1 0 0 1 1 0 1 0 0 1 0 0 0 0 1 0 0 0 0 0 0 0 0 0 1 0 0 0 0 0 0 1 0 0 0 0 0 0 0 0 0 1 0 0 0 0 1 0 0 1 1 0 0 1 0 1 1 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 STARTADDR When ready we just change the location that the graphics hardware uses to create the image
Java Color • Java includes several color encoding models: • RGB (red, blue, green), • HSV (hue, saturation, intensity), etc • for representing color. Typically the RGB model is followed • and uses a single int to describe the color of a pixel. This • single int has within the values for red, blue, and green • portions of the color. Alpha (8 bits) Red (8 bits) Green (8 bits) Blue (8 bits) 32 Bits (int)
Java Color Java has methods to retrieve the individual red, blue, and green components should one want them. public int getRed() public int getBlue() public int getGreen() Naturally there are many constructors; here are a few: public Color(int r, int g, int b) // creates an opaque color public Color(int r, int g, int b, int a) // given r, g, b, a 0..255 public Color(int rgb) Red component in bits 16-23, green bits 8-15, and blue in bits 0-7.
Java Color Methods are provided to convert back and forth between the R, G, B color model (Hardware oriented) and the H, S, V color model (User oriented) public static float[ ] RGBtoHSB(int r, int g, int b, float[ ] hsbvals) public static int HSBtoRGB(float hue, float saturation, float brightness)
Java Graphics • Java supports raster displays in objects • Each Component has an associated Graphics object. • We can draw on the Graphics object, changing the object’s appearance. • There are numerous java.awt.Graphics methods, • e.g.,: • drawLine(int xStart, int yStart, int xEnd, int yEnd); • drawRect(int xLoc, int yLoc, int width, int height); • fillRect(int x, int y, int width, int height); • // note "fill*" methods use the "current color" • How can I set the current color? • setColor(Color color); • // remains in effect until you change it again!
Java Graphics • Obtaining the Graphics object in the first place: • 1. Call getGraphics() on the Component, e.g.: • Graphics g = myButton.getGraphics( ); • g.setColor(Color.blue); • g.fillOval(100, 100, 200, 50); • g.setColor(Color.black); • g.fillRect(100, 100, 200, 50); • OR • 2. Override component’s paint method • public void paint( Graphics g ) { /* easier! */ • g.drawLine(10, 20, 30, 40); • // draws line from pixel 10, 20 to pixel 30, 40 • }
FIRE! import java.awt.*; // includes the Color // and Graphics classes public class DotButton extends Button { private int radius, diameter; /* not shown here, but need accessors/modifiers for these! */ public DotButton() { super ("FIRE!"); radius = 10; diameter = 2* radius; } // constructor public void paint (Graphics g) { int w = getSize().width; int h = getSize().height; g.setColor(255, 0, 0, 120); //r,g,b,alpha g.fillOval (w/2 - radius, h/2 - radius, diameter, diameter); } // paint }// DotButton Adds a red dot to a text button Note: raster drawings begin at top left of object; hence " - radius"
Translation Basic transformations: (for simplicity, 2D) Translation: x' = x + Dx y' = y + Dy where Dx is relative distance in x dimension, Dy is relative distance in y dimension, prime indicates new point in space. Computation: [x' y'] = [x y] + [Dx Dy] P' = P + T
Translation Each point gets translated [x' y'] = [x y] + [Dx Dy]
Scaling Scaling: x' = x * Sx y' = y * Sy where Sx is scale factor for x dimension, Sy is scale factor for y dimension, prime indicates new point in space. Computation: defining S as [ Sx 0 ] [ 0 Sy ] [x' y'] = [x y] * [ Sx 0 ] [ 0 Sy ] P' = P * S
Scaling [x' y'] = [x y] * [ Sx 0 ] [ 0 Sy ] (What about stretching unequally in two dimensions?)
Rotation Rotation: x' = xcos - ysin y' = xsin + ycos where is angle of rotation and prime indicates new point in space. Computation: [x' y'] = [x y] * [ cos sin ] [-sin cos ] P' = P * R Note: positive angles are counter-clockwise from x toward y; for negative angles (clockwise) use identities: cos(- ) = cos , and sin(- ) = -sin
Rotation [x' y'] = [x y] * [ cos sin ] [-sin cos ]
Rotation--Around Fixed Point • Notes on Rotation: • big difference between: • "rotation around center point of object" • and • "rotation around origin of Cartesian world" • For example: • imagine a ball on a tether mounted to pole • do you want the ball itself to spin around on the end of the tether? • or do you want the ball-and-tether to rotate around the pole? • To rotate an object about its own center point: • first translate object to origin, • then do rotation • then translate back
Basic Animation • With successive, rapid repaintings, a Java component may appear to be animated. Other Java packages support more complex media; however, we can create our own simple animations by timing calls to repaint(). • Techniques include: • calling repaint() inside the paint() or paintComponent() methods. This schedules a prompt call to redraw the object. (Do NOT recursively call paint again.) • creating a timer to call paint; • can be useful to spawn execution threads to manage repainting (advanced topic not covered here.)
Basic Animation Our algorithm for painting would include: 1) update the items being animated. (Stateful changes.) 2) erase the entire drawing area. (We might later refine this to only erase those areas that need updating.) 3) draw the updated items 4) repeat
import java.awt.*; import java.awt.event.*; import javax.swing.*; public class Bouncer extends JPanel implements ActionListener{ Timer timer; int ballX = 50, ballY = 50; int dx = 1, dy = 1; int diameter = 50; public void fire(){ timer = new Timer(5, this); timer.setCoalesce(true); // combine queued repaints timer.start(); } public void actionPerformed(ActionEvent e) { updateMovements(); checkCollisions(); repaint(); } public void updateMovements(){ ballY += dy; ballX += dx; }
public void checkCollisions(){ if (ballX + diameter > getSize().width || ballX < 0) dx*=-1; if (ballY + diameter > getSize().height || ballY < 0) dy *=-1; } public void paint(Graphics g){ g.setColor(Color.darkGray); g.fillRect(0,0, getSize().width, getSize().height); g.setColor(Color.red); g.fillOval(ballX, ballY, diameter, diameter); } To improve performance, investigate clipping areas: java.awt.Graphics.setClip(Rectangle);
Stop sending events when the window is iconified public void pause(){ timer.stop(); } public void resume(){ timer.restart(); } public static void main(String[] args) { JFrame frame = new JFrame("Bounce Test"); frame.setSize(400,400); final Bouncer bounce = new Bouncer(); frame.addWindowListener (new WindowAdapter() { public void windowClosing(WindowEvent e) { System.exit(0);} public void windowDeiconified(WindowEvent e){ bounce.resume(); } public void windowIconified(WindowEvent e) { bounce.pause(); }}); frame.getContentPane().setLayout(new BorderLayout()); frame.getContentPane().add(bounce); frame.show(); bounce.fire();} } // Bouncer
The timer allows us to note the passage of time, and periodically update our objects. We might also allow for other user driven events, perhaps to create an interactive real time program. Beyond simple 2D "pong games," however, we will need to identify techniques for efficiently rendering graphics . . .
Hypnotic Squares Example import java.awt.*; import javax.swing.*; import java.awt.event.*; public class Squares extends JPanel implements ActionListener { double p = 0.8; double q = 0.2; int cellSize; Timer t; int maxSquares = 15; int globalCount; int delta=-1; public Squares () { globalCount = maxSquares; t = new Timer(50, this); t.start(); } public void actionPerformed(ActionEvent e){ globalCount+=delta; if (globalCount < 2 || globalCount > maxSquares) delta*=-1; repaint(); }
private void swapOffsets(){ double t = p; p = q; q = t; } public void paintComponent(Graphics g){ g.setColor(Color.white); g.fillRect(0,0,getSize().width, getSize().height); g.setColor(Color.blue); cellSize = Math.min (getSize().width, getSize().height)/8; for (int i=0; i<8; i++) { for (int k=0; k<8; k++){ drawBoxes (g, i*cellSize, k*cellSize, i*cellSize+cellSize, k*cellSize, i*cellSize+cellSize, k*cellSize+cellSize, i*cellSize, k*cellSize+cellSize, globalCount); swapOffsets(); } swapOffsets(); } } public int iX(double x){ return (int)Math.round(x);} public int iY(double y){ return (int)Math.round(y);}
public void drawBoxes(Graphics g, double ax, double ay, double bx, double by, double cx, double cy, double dx, double dy, int count){ if (count!=0){ Polygon poly = new Polygon(); poly.addPoint(iX(ax), iY(ay)); poly.addPoint(iX(bx), iX(by)); poly.addPoint(iX(cx), iX(cy)); poly.addPoint(iX(dx), iX(dy)); poly.addPoint(iX(ax), iY(ay)); g.drawPolygon(poly); drawBoxes(g, p*ax+q*bx, p*ay+q*by, p*bx+q*cx, p*by+q*cy, p*cx+q*dx, p*cy+q*dy, p*dx+q*ax, p*dy+q*ay, --count); } }
public static void main(String[] args) { JFrame f = new JFrame(); f.addWindowListener(new WindowAdapter() { public void windowClosing(WindowEvent e) { System.exit(0); } }); int w = 600, h = 600; f.setSize(w,h); f.getContentPane() .setLayout (new BorderLayout()); f.getContentPane() .add(new Squares()); Dimension d = Toolkit .getDefaultToolkit() .getScreenSize(); f.setLocation ( (d.width -w)/2, (d.height-h)/2); f.show(); }} // Squares
The paint(Graphics g) method is common to all components and containers. • The paint(Graphics g) method does the actual painting/drawing on the Graphics object for the current component/container (applet, canvas, button, etc.) • How does the paint(Graphics g) method get called? • It is calledautomatically by Java whenever the component or container has been damaged or invalidated (e.g., window resized) and thus needs to be redrawn. • Note: It requires knowledge about both what is to be redrawn and where it is to be redrawn. Typically a programmer would rather not have to deal with tracking down this info! • You can call it via a special method repaint() Java Graphics -- paint(Graphics g)
Java Graphics paint(Graphics g) • The repaint method: • Java provides programmer support via the repaint() method to handle this for you. • The repaint() method accomplishes three things: • 1. It locates the information needed by paint() (so you don’t have to). • 2. It calls update(Graphics g), which writes over the old drawing in background color (thus erasing it). • 3. It then calls paint(Graphics g) to do the drawing.
A few situations in which Java calls repaint( ): • A window is created. • A window is uncovered. • A window is resized. • A window is moved. • A component is ‘validated’ or positioned by • a layout manager Java Graphics: paint(Graphics g)
import java.awt.*; import java.awt.event.*; import javax.swing.*; public class Scribbler extends JFrame implements ActionListener, WindowListener { private ScribblePanel sp; private JButton reset; private JButton red; private JButton yellow; private JButton green; private JButton blue; private JButton black;
public Scribbler() { getContentPane().setLayout (new BorderLayout ()); sp = new ScribblePanel (); getContentPane().add (sp, BorderLayout.CENTER); JPanel bp = new JPanel (); bp.setLayout (new FlowLayout ()); reset = new JButton ("reset"); reset.addActionListener (this); bp.add (reset); getContentPane().add (bp, BorderLayout.NORTH); JPanel cp = new JPanel (); cp.setLayout (new FlowLayout ());
// public Scribbler() continued red = new JButton ("Red"); red.addActionListener (this); cp.add (red); yellow = new JButton ("Yellow"); yellow.addActionListener (this); cp.add (yellow); green = new JButton ("Green"); green.addActionListener (this); cp.add (green); blue = new JButton ("Blue"); blue.addActionListener (this); cp.add (blue); black = new JButton ("Black"); black.addActionListener (this); cp.add (black);
// public Scribbler() continued getContentPane().add (cp, BorderLayout.SOUTH); addWindowListener (this); setSize (400, 300); setTitle ("Scribbler"); setVisible (true); } public void actionPerformed (ActionEvent e) { if (e.getSource () == reset) { sp.clear (); } else if (e.getSource () == red) { sp.setScribbleColor (Color.red); } else if (e.getSource () == yellow) { sp.setScribbleColor (Color.yellow); }
// public Scribbler() continued else if (e.getSource () == green) { sp.setScribbleColor (Color.green); } else if (e.getSource () == blue) { sp.setScribbleColor (Color.blue); } else if (e.getSource () == black) { sp.setScribbleColor (Color.black); } } // WindowListener methods public void windowClosing(WindowEvent e) { System.exit(0); }