Professional Documents
Culture Documents
Lecture Notes For Computer Games Programming 1
Lecture Notes For Computer Games Programming 1
Lecture Notes For Computer Games Programming 1
Jonathan G. Campbell
Department of Computing,
Letterkenny Institute of Technology,
Co. Donegal, Ireland.
1 Introduction 1
1.1 Purpose . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 1
1.2 The Course | Games Programming 1 . . . . . . . . . . . . . . . . . . . . . . . . 1
1.2.1 Module Aims . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 1
1.2.2 Module Learning Outcomes . . . . . . . . . . . . . . . . . . . . . . . . . 1
1.2.3 Syllabus Content . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 2
1.2.4 Assessment . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 2
1.3 Module Policies . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 2
1.3.1 Plagiarism . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 3
1.3.2 Reading List . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 3
1.4 Lectures, Learning . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 3
1.5 Suggested Reading . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 4
1.5.1 Mathematics . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 4
1.5.2 Computer Graphics . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 4
1.5.3 Games Programming APIs . . . . . . . . . . . . . . . . . . . . . . . . . . 5
1.5.4 Physics . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 5
1.5.5 General Books on Games . . . . . . . . . . . . . . . . . . . . . . . . . . . 5
2 What is Computer Programming all about? 1
2.1 Introduction . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 1
2.2 Simple Model of a Computer . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 1
2.3 Computer Programs . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 4
2.4 Assembly Code versus Java . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 7
2.4.1 Simple Program { add two integers . . . . . . . . . . . . . . . . . . . . . 7
2.4.2 If-then . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 8
2.4.3 If-then-else . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 8
2.4.4 Repetition . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 9
2.5 Back to the calculator program . . . . . . . . . . . . . . . . . . . . . . . . . . . . 10
2.6 Object-oriented Programming . . . . . . . . . . . . . . . . . . . . . . . . . . . . 10
2.6.1 Java versions of Student and ClassList . . . . . . . . . . . . . . . . . . . 11
2.7 Operating Systems . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 15
3 Overview of Games Programming 1
3.1 Introduction . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 1
3.2 Noughts and Crosses . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 1
3.3 More on object-oriented programming . . . . . . . . . . . . . . . . . . . . . . . . 3
3.4 Back to games . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 3
3.5 Some Detail on Games Programming . . . . . . . . . . . . . . . . . . . . . . . . 4
3.6 The Programming Language | Java . . . . . . . . . . . . . . . . . . . . . . . . 6
0{1
4 Simple Procedural Programming 1
4.1 Sequence . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 3
4.2 Repetition . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 4
4.2.1 Sequence of Repetitions . . . . . . . . . . . . . . . . . . . . . . . . . . . 4
4.2.2 Repetitions of Repetitions | Nested Loop . . . . . . . . . . . . . . . . . 6
4.2.3 Data Pattern = Program Pattern . . . . . . . . . . . . . . . . . . . . . . 7
4.3 Procedures | Methods, Subprograms, Functions . . . . . . . . . . . . . . . . . . 8
4.3.1 Procedures Without Parameters . . . . . . . . . . . . . . . . . . . . . . . 8
4.3.2 Subprograms with Parameters . . . . . . . . . . . . . . . . . . . . . . . . 9
4.4 Selection . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 16
4.5 Exercises . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 17
5 Threads 1
5.1 Introduction . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 1
5.2 An Example of the Advantages of Multitasking . . . . . . . . . . . . . . . . . . . 2
5.3 Brief Case Study { MS-DOS . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 4
5.3.1 Introduction . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 4
5.3.2 History . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 4
5.3.3 Structure . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 5
5.3.4 Processes in MS-DOS . . . . . . . . . . . . . . . . . . . . . . . . . . . . 5
5.4 Processes . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 8
5.4.1 Process Life cycle . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 8
5.4.2 Process Control Block (PCB) . . . . . . . . . . . . . . . . . . . . . . . . 9
5.4.3 Context Switch . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 9
5.5 The Kernel . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 9
5.5.1 Kernel Privileges . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 10
5.6 Thread Examples in Java . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 10
6 Images, Displays, Animation, Colour 1
6.1 Introduction . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 1
6.2 3D Graphics, Images, Animation . . . . . . . . . . . . . . . . . . . . . . . . . . . 1
6.3 Digital Images . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 1
6.3.1 Continuous/Analogue versus Discrete/Digital . . . . . . . . . . . . . . . . 1
6.3.2 Analogue to Digital Converters and Digital to Analogue Converters . . . . 3
6.3.3 Images and Digital Images . . . . . . . . . . . . . . . . . . . . . . . . . . 3
6.3.4 Anti-aliasing . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 9
6.3.5 Opacity, alpha . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 9
6.4 Displays and Factors Associated with them . . . . . . . . . . . . . . . . . . . . . 9
6.4.1 Display Hardware | CRTs, LCDs, Plasmas . . . . . . . . . . . . . . . . . 9
6.4.2 Flicker and Tearing . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 11
6.5 Visual Perception . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 12
6.6 A Model of a General Imaging System . . . . . . . . . . . . . . . . . . . . . . . . 14
6.6.1 Light and re
ection . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 15
6.6.2 Motivation . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 15
6.6.3 Uneven Illumination . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 16
6.6.4 Uneven Sensor Response . . . . . . . . . . . . . . . . . . . . . . . . . . . 16
6.6.5 Diuse and Specular Re
ection . . . . . . . . . . . . . . . . . . . . . . . 16
6.7 Colour . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 17
6.7.1 Electromagnetic Waves and the Electromagnetic Spectrum . . . . . . . . 17
0{2
6.7.2 The Visible Spectrum . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 19
6.7.3 Sensors . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 21
6.7.4 Spectral Selectivity and Colour . . . . . . . . . . . . . . . . . . . . . . . . 21
6.7.5 Spectral Responsivity . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 22
6.7.6 Colour Display . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 22
6.7.7 Additive Colour . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 23
6.7.8 Colour Re
ectance . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 23
6.7.9 Exercises . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 23
6.8 Cameras and Photographic Film . . . . . . . . . . . . . . . . . . . . . . . . . . . 24
6.9 More on Colour Images . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 24
7 Introduction to 2D Graphics 1
7.1 Introduction . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 1
7.2 JFrame Windows . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 1
7.3 Drawing Shapes . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 3
7.4 Y-axis pointing down? . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 5
7.5 Drawing with Dierent Shapes . . . . . . . . . . . . . . . . . . . . . . . . . . . . 8
7.6 Colour . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 11
8 More 2D Graphics 1
8.1 Introduction . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 1
8.2 The Framework . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 1
8.3 Some Graphics Using the Framework . . . . . . . . . . . . . . . . . . . . . . . . . 6
8.4 Shape and General Path . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 11
8.5 Drawing Images . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 13
9 Vectors and Vector transformations 1
9.1 Introduction . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 1
9.2 Vector Addition . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 3
9.3 Vector Rotation . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 3
9.3.1 Homogeneous Coordinates . . . . . . . . . . . . . . . . . . . . . . . . . . 7
9.4 Rotating Shapes . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 8
9.5 Scaling Shapes . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 12
9.6 Transformation using java.awt.AneTransform . . . . . . . . . . . . . . . . . . . 13
10 Programming Audio 1
10.1 Introduction . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 1
10.2 Audio Data and Sound in Computers . . . . . . . . . . . . . . . . . . . . . . . . . 1
10.2.1 Sound . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 2
10.2.2 Loudspeakers . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 2
10.2.3 Microphones . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 2
10.2.4 Analogue versus Digital . . . . . . . . . . . . . . . . . . . . . . . . . . . . 3
10.2.5 Electronic (or Electro-acoustic) Music . . . . . . . . . . . . . . . . . . . . 3
10.2.6 Electronic Instruments . . . . . . . . . . . . . . . . . . . . . . . . . . . . 3
10.2.7 Magnetic Recording . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 4
10.2.8 Data Compression . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 4
10.3 Java Sound API . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 5
10.3.1 Sampled Audio . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 5
10.3.2 MIDI | Musical Instrument Digital Interface . . . . . . . . . . . . . . . . 6
10.3.3 Java Sound Terminology . . . . . . . . . . . . . . . . . . . . . . . . . . . 7
0{3
10.4 Programs Using Java Sound API . . . . . . . . . . . . . . . . . . . . . . . . . . . 7
11 Brief Notes on the 2D Platform Game 1
11.1 Introduction . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 1
11.2 Selected parts of the code . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 1
0{4
Chapter 1
Introduction
1.1 Purpose
This document provides course notes for the module Games Programming 1 at Letterkenny Insti-
tute of Technology.
1. Describe the computer representation of digital images and the hardware and software used
for their display;
2. Outline the basic principles of computer graphics and animated graphics;
3. Describe in both qualitative and mathematical or programming language terms the computer
representation of 2D graphics and the hardware and software used for their reproduction;
4. Interpret and describe the operation of computer programs which implement techniques based
on learning outcomes 1 to 3;
5. Construct modications (including design and coding of program fragments) to demonstra-
tion programs (learning outcome 4) to alter their behaviour appreciably;
6. Interpret, describe and construct minor modications to the computer program implementa-
tion of a simple two dimensional tile and sprite based game.
1{1
1.2.3 Syllabus Content
Section A - Digital Representation of Images and Video (10%)
Sampling. Digitisation. Light; sensing of images; basics of cameras. Image displays. Animation.
Examples and software demonstrations.
Section B - Applications of Mathematics in 2D Computer Graphics (30%)
Trigonometry. Vectors. Matrix mathematics. Vector (linear) transformations. Ane transforma-
tions. Homogeneous coordinates. Practical work using a high-level language API and a matrix
calculator such as Matlab or Octave.
Section C. Brief Introduction to Mathematics for 3D Computer Graphics (5%)
3D Homogeneous coordinates. 3D Ane transformations. Modelling and viewing transformations.
Section D. Introduction to 2D Computer Graphics (30%)
Representation of graphics on a computer. Images; raster; vector. Characteristics (simple) of
graphics software (API view). 2D graphics. Computer program and mathematical representation
of common objects: points, lines, rectangles, circles. Vector versus raster. Programming via an
appropriate API. Inclusion of image data in graphics. Window to viewport transformation.
Section E. Creating a 2D Game (25%)
Tile-based platform games and their implementation; tiles, sprites. Implementation of velocity,
acceleration, gravity, collision detection, parallax scrolling.
1.2.4 Assessment
Marks Breakdown: Continuous Assessment (CA), 60%, Final Written Examination, 40%.
Continuous assessment will comprise four components.
1{2
1.3.1 Plagiarism
Answers should be your own work. When you take information from books, the web, notes or other
sources, do not copy verbatim | convert the ideas into your own words. Also, you should give a
reference for any source used.
Plagiarised work will receive zero marks and will be reported to the college authorities. The
student handbook gives a clear statement on the penalties for plagiarism. See also the Computing
Department Guidelines on this subject.
Take notes during lectures, rather than just following along with these notes. Make sure to
bring extra notepaper | these notes will quickly become cluttered if you try to superimpose
signicant additional notes on them; on the other hand, listening carefully and participating
may be more important than taking notes;
Do the exercises (I mean unassessed exercises). They, or problems similar to them, crop up
in exams;
Participate in the classes and practicals tutorials { by participate I mean attempt the exercises
and enter into discussion if the presented solution is dierent from yours; ask questions about
things that remain unclear to you. Don't forget, there are no stupid questions, just people
too stupid to ask them;
Form study groups; if you, individually, have a problem with the course, it's your problem,
but if it becomes clear that a good number of students have the same problem, then it can
become the lecturer's problem;
Read books and websites and magazine on the subject;
1{3
Spend a decent amount of time on the assignments and practicals | they are designed to
help you learn;
To be honest, learning to learn should probably be your major objective; if you work in the
computer industry for the next forty years, you're going to have to do a lot of learning new
things.
All that aside, I think this is a great opportunity to learn programming through doing things that
you enjoy.
In a third-level course, it is essential that you read around the courses. Here I make some sugges-
tions for year 1 and later.
1.5.1 Mathematics
Video games programming involves mathematics, in most cases a lot of mathematics. I'm not
saying you should leave now if you dislike mathematics, but, it's always a possibility . . .
Brackeen's book has a reasonable introduction to the mathematics of 2D and 3D graphics.
(Vince 2001) provides a very nice summary.
(vanVerth & Bishop 2004) is probably the best all round games mathematics book.
I will be handing out a set of notes on the relevant mathematics (Campbell 2007b).
1{4
1.5.2 Computer Graphics
In Year 2, we will use OpenGL, see (Shreiner, Woo, Neider & Davis 2006) (there's an earlier version
on the web that is still quite useful | see my website). My notes on Computer Graphics Using
OpenGL (Campbell 2007a) may be useful.
1.5.4 Physics
The best two books on game physics are (Millington 2007) and (Palmer 2005)
See also (Eberly 2004) (but dicult); (Bourg 2002) (easier). There's plenty of introductory physics
in Brackeen's book.
Feynman's Lectures on Physics are well regarded: (R. Feynman & Sands 1965a); (R. Feynman
& Sands 1965b); (R. Feynman & Sands 1965c). For light relief, Cartoon Physics: (Gonick &
Human 1990)
1{5
Bibliography
Akenine-Moeller, T. & Haines, E. (2002). Real-time Rendering, 2nd edn, Natick, MA: A.K. Peters.
Angel, E. (2005). Interactive Computer Graphics: a top-down approach using OpenGL, 4th edn,
Addison Wesley.
Astle, D. & Hawkins, K. (2004). Beginning OpenGL Game Programming, Premier Press / Thomp-
son Course Technology.
Barrass, R. (1995). Students Must Write, 2nd ed., Routledge.
Bourg, D. M. (2002). Physics for Game Developers, O'Reilly.
Brackeen, D., Barker, B. & Vanhelsuwe, L. (2004). Developing Games in Java, New Riders
Publishing (Pearson Education). ISBN: 1-5927-3005-1.
Budd, T. (1999a). C++ for Java Programmers, Addison Wesley.
Budd, T. (1999b). Understanding Object-oriented Programming with Java (updated for Java 2),
Addison-Wesley.
Buss, S. R. (2003). 3-D Computer Graphics: a mathematical introduction with OpenGL, Cam-
bridge University Press.
Campbell, J. (2007a). Lecture Notes on Computer Graphics using
OpenGL, Technical report, Letterkenny Institute of Technology. URL.
http://www.jgcampbell.com/graphics1/notes/graphics.pdf.
Campbell, J. (2007b). Notes on Mathematics for 2D and 3D Graph-
ics, Technical report, Letterkenny Institute of Technology. URL.
http://www.jgcampbell.com/bscgp1/notes/grmaths.pdf.
Castleman, K. (1996). Digital Image Processing, Prentice Hall.
Clingman, D., Kendall, S. & Mesdagh, S. (2004). Practical Java Game Programming, Charles
River Media.
Cormen, T., Leiserson, C. E., Rivest, R. & Stein, C. (2001). Introduction to Algorithms, 2nd edn,
MIT Press / McGraw Hill.
Dawson, M. (2004). Beginning C++ Game Programming, Thompson Course Technology. 1435,
pds 15.27, ISBN: 1-59200-206-6.
Dodge, C. & Jerse, T. (1997). Computer Music: synthesis, composition, and performance, New
York: Schirmer Books.
1{1
Eberly, D. H. (2004). Game Physics, Morgan Kaufmann.
Eberly, D. H. (2005). The 3D Game Engine Architecture: Engineering Real-time Applications with
Wild Magic, Morgan Kaufmann. ISBN: 0-12-229064-X.
Eberly, D. H. (2007). 3D Game Engine Design: a practical approach to real-time computer
graphics, 2nd edn, Morgan Kaufmann. ISBN: 0-12-229063-1.
Eckel, B. (2006). Thinking in Java, 4th edn, Prentice Hall.
(Editor), M. D. (2000a). Game Programming Gems, Charles River Media.
(Editor), M. D. (2001). Game Programming Gems 2, Charles River Media.
Editor), O. A. R. B. D. S. (2000b). OpenGL Reference Manual: The Ocial Reference Document
to OpenGL, Version 1.2, Addison Wesley.
et al, P. S. (2005). Fundamentals of Computer Graphics, 2nd edn, A.K. Peters. ISBN: 1-56881-
269-8.
Farin, G. & Hansford, D. (2005). Practical Linear Algebra: A Geometry Toolbox, A.K. Peters.
Flanagan, D. (2005). Java in a Nutshell, 5th edn, O'Reilly and Associates.
Foley, J., van Dam, A., Feiner, S. & Hughes, J. (1990). Computer Graphics: principles and
practice, 2nd edn, Addison Wesley. ISBN:0-201-12110-7.
Foley, J., van Dam, A., Feiner, S., Hughes, J. & Phillips, R. (1994). Introduction to Computer
Graphics, Addison Wesley. ISBN:0-201-60921-5.
Forsyth, D. & Ponce, J. (2002). Computer Vision: a modern approach, Prentice Hall.
Freeman, E. & Freeman, E. (2005). Head First Design Pat-
terns, O'Reilly and Associates. ISBN: 0596007124; see URL:
http://www.wickedlysmart.com/HeadFirst/HeadFirstDesignPatterns/.
Fries, B. (2005). Digital Audio Essentials: A Comprehensive Guide to Creating, Recording, Editing,
and Sharing Music and Other Audio, O'Reilly.
Gonick, L. & Human, A. (1990). The Cartoon Guide to Physics, Harper Perennial.
Gonzalez, R. & Woods, R. (2002). Digital Image Processing, 2nd edn, Prentice Hall.
Harris, A. (2007). Games Programming, The L Line, The Express Line to Learning, Wiley. ISBN:
978-0-470-06822-9.
Hartley, R. & Zisserman, A. (2004). Multiple View Geometry in Computer Vision, 2nd edn,
Cambridge University Press.
Hatcher, E. & Loughran, S. (2003). Java Development with Ant, Manning.
Hill(Jr), F. (2001). Computer Graphics Using OpenGL, 2nd edn, Prentice Hall.
Horstmann, C. (2005). Java Concepts, 4th edn, Wiley.
Horstmann, C. S. & Cornell, G. (2004a). Core Java 2 Volume 1, 7th edn, Prentice Hall.
1{2
Horstmann, C. S. & Cornell, G. (2004b). Core Java 2 Volume 2, 7th edn, Prentice Hall.
Koenig, A. & Moo, B. (2000). Accelerated C++, Addison-Wesley.
LaMothe, A. (2002). Tricks of the Windows Game Programming Gurus: Fundamentals of 2D and
3D Game Programming, 2nd edn, SAMS.
LaMothe, A. (2003). Tricks of the 3D Game Programming Gurus: Advanced 3D Graphics and
Rasterization, SAMS.
Lengyel, E. (2004). Mathematics for 3d Game Programming and Computer Graphics, 2nd edn,
Charles River Media.
Llopis, N. (2003). C++ for Game Programmers, Charles River Media.
McSharey, M. (2005). Game Programming Complete, 2nd edn, Paraglyph Press.
Millington, I. (2007). Game Physics Engine Development, Morgan Kaufmann. ISBN: 0-12-369471-
X.
Murdock, K. (2004). 3ds Max 6 Bible, Wiley.
Norman, D. (1993). Things that make us smart, Perseus Books.
Norman, D. (1998). The Invisible Computer, MIT Press.
O'Luanaigh, P. (2006). Game Design Complete, Paraglyph Press. ISBN: 1-93309700-0.
Palmer, G. (2005). Physics for Games Programmers, Apress. ISBN: 1-59059-472-X.
Parker, J. (2005). Start Your Engines: developing driving and racing games, Paraglyph Press.
Penton, R. (2003). Data Structures for Games Programmers, Premier Press / Thompson Course
Technology. ISBN: 1-931841-94-2.
Pohlmann, K. C. (2000). Principles of Digital Audio, 4th edn, McGraw-Hill.
Publications, S. T. (1996). Read Me First!: A Style Guide for the Computer Industry, Prentice
hall.
R. Boulanger, e. (2000). The Csound Book, MIT Press.
R. Feynman, R. L. & Sands, M. (1965a). The Feynman Lectures on Physics, vol. 1, Addison-
Wesley.
R. Feynman, R. L. & Sands, M. (1965b). The Feynman Lectures on Physics, vol. 2, Addison-
Wesley.
R. Feynman, R. L. & Sands, M. (1965c). The Feynman Lectures on Physics, vol. 3, Addison-
Wesley.
Roads, C. (1996). The Computer Music Tutorial, MIT Press.
Rollings, A. & Morris, D. (2004). Game Architecture and Design, 2nd edn, New Riders Publishing
(Pearson Education). ISBN: 1-7357-1363-4.
Rost, R. J. (2004). OpenGL Shading Language, Addison Wesley.
1{3
Sanger, G. (2003). The Fat Man on Game Audio: Tasty Morsels of Sonic Goodness, New Riders
Publishing (Pearson Education).
Schneider, P. J. & Eberly, D. H. (2003). Geometric Tools for Computer Graphics, Morgan Kauf-
mann.
Selman, D. (2002). Java 3D Programming, Manning.
Shreiner, D., Woo, M., Neider, J. & Davis, T. (2006). OpenGL Programming Guide: The
Ocial Guide to Learning OpenGL, Version 2 (The Red Book), 5th edn, Addison Wes-
ley. ISBN: 0-321-33573-2. Note that there is a very usable web version of Edition 1.1 at:
http://www.glprogramming.com/red/.
Sierra, K. & Bates, B. (2005). Head First Java, O'Reilly and Associates. ISBN: 0596009208.
Steiglitz, K. (1996). A Digital Signal Processing Primer - with applications to digital audio and
computer music, Addison-Wesley.
Tufte, E. (1990). Envisioning Information, Graphics Press.
Tufte, E. (1997). Visual Explanations, Graphics Press.
vanVerth, J. M. & Bishop, L. M. (2004). Essential mathematics for games and interactive appli-
cations, Morgan Kaufmann. ISBN: 155860863X.
Vince, J. (2001). Essential Mathematics For Computer Graphics Fast, Springer-Verlag. ISBN:
1852333804.
Watt, A. (2000). 3D Computer graphics, 3rd edn, Addison-Wesley.
Watt, A. & Policarpo, F. (2001). 3D Games, Vol.1, Addison-Wesley.
Wright, R. & Lipchak, B. (2004). OpenGL Superbible, 3rd edn, SAMS. ISBN: 0-672-32601-9.
Xiang, Z. & Plastock, R. (2000). Computer Graphics (Schaum's Outlines), 2nd edn, McGraw-Hill.
1{4
Chapter 2
2.1 Introduction
This course is about programming of computer games. In fact it is more specically about video
game programming, i.e. computer games in which the player sees a video representation of the
game world. Other sorts of games will occasionally be mentioned.
Since most games, and denitely video games, involve sound output, we will also cover programming
that involves audio data and its output.
So, we'd better say something about what is a computer program and something about what we
would expect a computer game program to do. And before that we'd better build up a simple
model of a computer and then say something about the operating system.
This says: (i) take the number in the cell labelled x, (ii) take the number in the cell labelled y, (iii)
add them, (iv) put the result in the cell labelled z.
2{1
Figure 2.1: Overview of a Computer: CPU and Memory
In a programming language, cells are called variables, variable names are easy to remember names
for memory cells: e.g. x at memory cell 0, y at 1, z at 2; therefore in Figure 2.1 the value in x is
22, in y, 33, and in z, 0.
Fetch P1.
Execute P1.
Fetch P2 . . . Execute P2.
. . . and keep on until it reaches a halt instruction.
This is the famous fetch-execute cycle that you'll hear a lot about in the Computer Architecture
module.
A CPU and memory aren't much use without a keyboard and screen, and a disk drive, i.e. a useful
computer is actually a computer system.
Figure 2.2 shows the organisation of a simple computer system with one CPU, memory and three
input-output (I/O) devices { peripherals: a disk and a keyboard & screen. As always, the compo-
nents are connected by a system bus { this is the same as the bus mentioned above; communication
with peripherals can be done in a manner similar to memory reading/writing.
2{2
Figure 2.2: Organisation of a Simple Computer System
Figure 2.3 shows main memory; it is essentially a collection of labelled cells (labels = addresses),
each of which, typically, can store eight binary digits | bits (BInary digiTs). Each bit is like a
sub-cell that can be `0' or `1'. Bits have much in common with light-bulbs: they are either on |
value 1, or o | value 0.
A collection of eight bits is called a byte.
Each cell has an address. Addresses run from 0 to N-1, where N is the size of the memory; on a
typical PC these days, N is 64 Mega(bytes). Mega = `million' | actually, 1048576 = 220 .
Numeric values Each bit is a single binary value: you can count only from 0 to 1 with it; however,
a collection of eight bits, properly interpreted, allows you to count from 0 up to 255; and 16 bits, 0
. . . 65535 (64K - 1). The byte shown in address 0 of Figure 2.3 contains binary 0001 0110 which
is decimal (base-10) 22, hexadecimal (base-16) 0x16.
Essentially, Figure 2.2 conforms to the so-called von Neumann computer architecture, which has
ve basic parts:
2{3
3. The memory.
4. Input equipment.
5. Output equipment.
2{4
Figure 2.4: Computer programs have much in common with recipes (recipes from B. Nilsson, The
Penguin Cookery Book)
2{5
One signicant dierence between instructions for computers and instructions for cooks is the
computer instructions must be absolutely precise and correct | to the nest detail; computers
know nothing other than what is in their programs, whereas humans can often ll in gaps and
correct obvious errors.
So, if had a (very dull and uninteresting) computer program which added numbers, we could write a
pseudo-code program as follows. (Pseudo-code is English-like instructions that are easily translated
to computer readable instructions.)
1. Initialise;
2. Prompt user to type two numbers;
3. Read in the two numbers and store them in memory, one in a cell called x, the other in y;
4. Add x and y and store the result in z; (as we have done before);
5. Write the value in z to the screen;
6. Go to instruction 2 (and repeat).
Apart from pseudo-code, another way of writing an outline of a program, that is without going
into the detail of the exact program, is a
ow chart, see Figure 2.5. Here the blocks indicate
do-something and the arrows show where to go to next. I mention
ow charts not because they
are all that much use these days for general programming, but because they do occasionally crop
up in games programming books.
2{6
This is all dreadfully dull; but we are not as far from a game program as you might think.
Let us take a glimpse at two types programming language: a high level language like Java; and a
low level language that the computer itself uses.
2{7
Label. Optional, only necessary if you need to jump to that instruction; can also be useful as
comment, e.g. above. Always followed by ':', otherwise assembler will try to interpret it as
an instruction.
Instruction mnemonic.
Operand I.e. address of thing to suer the operation. Either:
Symbolic name, e.g. above.
Symbolic label, or numeric address, to jump to.
Constant { for immediate addressing.
Comment Comments are even more important for assembly language programs than the are for
high-level language programs. Make your code maintainable by someone else!
2.4.2 If-then
High-level language
if(a0==a1) a2 = a2 + 1;
else next instructions...
Assembly language
If: LODD a0
SUBD a1
JZER Then
JUMP Next
Then: LOCO 1 /load constant 1
ADDD a2
STOD a2
EndThen: JUMP Next /Unnecessary
Next: ...
2.4.3 If-then-else
High-level language
if(a0==a1) a2 = a2 + 1;
else a2 = a2 + 2;
//next instructions...
2{8
Assembly language
If: LODD a0
SUBD a1
JZER Then
Else: LOCO 2
ADDD a2
STOD a2
JUMP Next
Then: LOCO 1
ADDD a2
STOD a2
EndThen: JUMP Next /Unnecessary
Next: ...
2.4.4 Repetition
High-level language
Assembly Language
init: LOCO 0
STOD sum
STOD i
loop: LODD i
SUBD n
JPOS loopend / if i-n>=0,
/ same as: if i>=n
/ same as: if NOT i<n
/otherwise continue with body of loop
loopbody:
LODD sum /load sum into accumulator
ADDD i /add i to it
STOD sum / and don't forget to store the result!
incr: LOCO 1
ADDD i
STOD i
JUMP loop
loopend: ...
2{9
Exercise. Draw a
owchart representing the program above.
It is straightforward to dene deterministic loops, for example,
in terms of do-while. Likewise do-until { the continuation test is merely carried out at the end
of the loop, instead of at the beginning for do-while.
2{10
Information is passed between objects via messages | at least that is what the information passing
is called in object-oriented programming.
In fact, message passing boils down to nothing more than an object X pressing certain buttons on
an object Y and/or passing data to object Y.
That's probably confusing you. Think of it as follows.
Instead of a computer, let us have a room with two administrative sta in it. For each new student
who comes to the top of a queue, clerk A takes out a blank Student form like Figure 2.7, gets the
details from the student and adds them to the form. The clerk has done the equivalent of creating
a Student object | the administrative system's model of a student. The example here is grossly
simplied, for obvious reasons.
The point is that by organising our programs into objects the programs become easier for program-
mers to think about; it is easier to split the programming task amongst programmers; programs
are easier to modify and it is easier to x errors in them. But not changes inside the computer,
our object-oriented programs are still translated into the same bunches of instructions and data as
we saw in section 2.5
Student Record Form
Last Name:_______________________________________________
First Name:______________________________________________
Clerk A now passes the completed form to clerk B, who places it into a box-le. The box-le is a
ClassList object.
2{11
import java.util.*;
public class Student{
private String firstName;
private String lastName;
private String id;
private int credits;
/**
* Create a new student with a given name and ID number.
*/
public Student(String lastN, String firstN, String studentId){
lastName = lastN; firstName = firstN;
id = studentId;
credits = 0;
}
/**
* Add some credit points to the student's accumulated credits.
*/
public void addCredits(int newCredPoints){
credits = credits + newCredPoints;
}
2{12
import java.io.*; import java.util.*;
public class ClassList{
private List<Student> theList = new ArrayList<Student>();
/**
* Create a new empty class list
*/
public ClassList(){
theList = new ArrayList<Student>();
}
while(!finished){
line= in.readLine();
if(line.equalsIgnoreCase("end") ){
finished= true; break;
}
Student s = new Student(line); addStudent(s);
}
in.close();
}
}
int i = 0;
while(!finished){
last= lastns[i];
if(last.equalsIgnoreCase("end") ){
finished= true;
break;
}
first= firstns[i];
id= "" + currentId;
currentId++;
System.exit(0);
}
The Operating System Executes all the Time | well, sort of I am tempted to say that, from
then on, the operating system (program) runs all the time until the the computer is switched o.
However, we all know that only one program can be running on a single processor at any time; and
most computers operate with just one processor. What about the applications we want to run |
our word processor, or spreadsheet, our games . . . See Chapter 5.
The Operating System is in charge of the computer We can revise that statement to say that
the operating system is in charge of the computer all of the time. To show how a simple program
(the operating system) can be in charge, or manages, the computer, yet relinquish the processor
to other programs, is one of the major objectives of this course. Note: I use the term in charge
because I want to reserve the term control; when we say transfer of control (to a program), we
mean that the instructions of this program begin to execute on the processor { and the operating
system (and other programs), for the moment, slide into the background.
The Operating System as a platform for executing software Another useful way of thinking
about the operating system is that it provides a platform or environment (a virtual machine) upon
which to run your application software and provides an interface with which you the user interact
with the machine. In this view, the operating system provides a layer that separates the application
software and the user from the hardware.
The Operating System provides services When an operating system is viewed as a platform
for executing software (and for interfacing with humans), we can see that it provides services. For
example: reading from, and saving to disks; sending data to a printer, etc.
2{15
Layers in the Operating System Figure 2.11 shows a layered view of an operating system and
the things it inter-operates with. The layers are:
In this diagram, arrows mean
ows of data and the blocks represent layers. Note carefully the
dierent meanings compared to
ow charts.
This diagram is an important one for games programmers. Previously, games programmers liked
to write their programs (application programs) to talk directly to the hardware, i.e. bypassing the
OS and using the programmers' own drivers. Modern operating systems don't allow this | for
many good reasons.
Q. Why might a games programmer want to bypass the OS | especially if it meant duplicating
services/software already provided by the OS? Hint: video games . . . speed.
Q. Why is it a good idea to keep device drivers in as low a layer as possible? Think of graphics cards
(or network interface cars for that matter). And then think of games (application programs). Would
it be a good idea for an application (program) to have to contain a driver for every conceivable
graphics card (or network card)? Or would it be nicer if the application could just ask the OS to
2{16
display that image, or play that sound, for it? If applications were to supply the drivers, think of
how many dierent applications would need to contain a particular driver? Duplication is bad; and
triplication worse! And multiplication even worse than that | especially if you have no calculator
:-)
The Operating System as police or government When modern operating systems (Windows
2000, XP, UNIX, Linux) go to the trouble of providing services they also force application programs
to avail of these services. For example, unlike on MS-DOS and early versions of Windows (3.1
and to an extent 95 and 98), application programs are barred from directly accessing hardware like
disks, network cards, etc.; they must use the appropriate operating system service. Since accessing
hardware directly is dicult and some application programs are written by programmers who are
less skilled than system programmers, directly accessing hardware was a common source of errors
and frequently resulted in the systems crashing.
Operating systems that adopt this more modern approach are therefore more reliable | there
are fewer occurrences of the blue screen of death. (The blue screen of death refers to the blue
screen that used to appear on early versions of Windows when the OS crashed and needed to be
rebooted.)
In this sense, the operating system can be seen as a police force or government. And just like
governments require you to pay taxes (for the services they claim to provide) the operating system
demands a certain amount of CPU time for itself.
2{17
Chapter 3
3.1 Introduction
Before, see section 2.5, we talked about a very boring little program that read two numbers, added
them, and displayed the result. We showed a
ow chart of it, and we hinted that we were not too
far away in structure from a games program.
| | o | | 0 |1 |2
--+--+-- --+--+-- --+--+--
|x | |x | 3 |4 |5
--+--+-- --+--+-- --+--+--
| | | | 6 |7 |8
3{1
3c. Check play in proper turn: c = x, o, x, o . . .
3d. If something wrong, go back to 2;
4a. Store c in cell n
4b. Check for: (i) a win, (ii) the cells are all occupied and hence the game is a draw; otherwise
(iii) continue;
5. Display the current state of the game;
6. Unless game ended, go to instruction 2 (and repeat).
3{2
It doesn't require much modication to make this program act also as one of the players | all you
need is the addition of a step 3e. which makes the computer's move. Incidentally, this step would
use what is called game AI | game Articial Intelligence. Hardly worthy of the term intelligence
but such algorithms are sometimes dignied with the name AI.
This is still boring, but we have identied many of the components and characteristics of computer
games. We have identied: (i) user input; (ii) internal representation; (iii) handling of user input,
including rules of the game; (iv) display. Another comment worth making is that the program
above is expressed in a procedural or imperative manner, i.e. as opposed to object-oriented.
3{3
Sounds like we need magic. No, what we need is event-driven programming. In event-driven
programming, the operating system collects all user input events | such as keyboard key presses,
mouse movements, mouse button presses and clicks, . . . . It places these in an event queue which
is readable by the application program. The application program must then (i) read the events
from the queue and (ii) for each event gure out what that even means, (iii) update the game
state accordingly, and, nally, display the updated game state.
Even-driven programming is how you must program Windows user interfaces.
The new game loop is shown in Figure 3.3, where we've shown also the display window and the
user input devices.
1. Initialise;
2. Read event(s) from queue;
3{4
3. Interpret events;
4. Respond to event(s) and update game state accordingly;
5. Display updated game state.
Initialise Initialise involves setting the state of the game to the beginning. For example, read
data from le; the hero is at the left of the screen facing right; enemies are far way, . . . This is
just initialising that internal representation. It is display at the bottom of the loop that paints the
picture corresponding to this initial state | or any later updated state.
Read event(s) from queue Not much to say. The OS and Java gives you a well dened way of
retrieving events from the queue.
Interpret events Deep down in the platform game in chapter 5 of Brackeen's book (Brackeen
et al. 2004), you will nd:
inputManager.mapToKey(moveLeft, KeyEvent.VK_LEFT);
inputManager.mapToKey(moveRight, KeyEvent.VK_RIGHT);
inputManager.mapToKey(jump, KeyEvent.VK_SPACE);
inputManager.mapToKey(exit, KeyEvent.VK_ESCAPE);
Ignoring detail, this means that there are just four possible events (I'm mixing up event with
response to event, but you see what I mean): (i) moveLeft; (ii) moveRight; (iii) jump; and (iv) exit.
VK_LEFT, VK_RIGHT, refer to presses of cursor keys, VK_SPACE is the space bar, and VK_ESCAPE
is the escape key up on the top left hand corner of the keyboard; escape is a reasonably standard
method of indicating exit/quit.
Respond to event(s) and update game state accordingly For example, if Hero is at (x = 25,
y = 0) and there has been a moveLeft event, we move him (her, it?) to (x = 24, y = 0); we set
the direction state to left so that he faces left; jump and we move him to (x = 24, y = 3); set
the jumping state to true | a jump action lasts a few display frames ( (x = 24, y = 3), (x = 24,
y = 6), (x = 24, y = 7), (x = 24, y = 8) and then falling down again, (x = 24, y = 7), (x = 24,
y = 5), . . . ).
But that's when the game is at a simple stage. When there are enemies around, or power-ups that
can be collected, we must perform collision detection | detect whether Hero has touched one of
those. How do you do that? Well, if we update the position of Hero and nd him at (x = 25, y =
7), we can inspect our list of enemies and see if any of them is at (x = 25, y = 7) or nearby, say,
at (x = 25+/- 2, y = 7+/-2).
If there is a collision, we must perform a collision response | and that depends on the type of
collision. It could be the Hero dying and the game ending, or the Hero increasing his health by
colliding with a power-up, etc.
3{5
Display updated game state Revise the display according to the current state.
In a noughts and crosses game it is just a matter of drawing something like Figure 3.1 (a) or (b)
on the screen.
If it is a 2D tile-based game, we repaint some parts of the picture and maybe scroll left or right
or up or down. (Note that we have not yet said anything about how to paint pictures; that is
deliberate, wait for chapter 6.)
If it is a 3D game, we might have to take the updated version of a complex 3D model and use
3D graphics techniques to determine what the viewer sees. In eect we operate a pretend camera
and see what will be projected from the 3D scene onto the 2D camera view. Then the 2D camera
view is painted on the screen.
Sound You could say that sound is part of the display | in the sense that display is how
the player gets feedback on the progress of the game. Many games have a background musical
accompaniment. Most will output a sound to correspond to a state of the game, for example a
bang when there is a collision.
I hope that gives you some hints at what is ahead | in Games Programming 1, and later in
year 2: Graphics and Physical Modelling and Games Programming 2, and then year 3: Games
Programming 3.
3{6
Chapter 4
This chapter has three main objective. First, to cause us to think a bit about procedural program-
ming and how you can analyse a problem and design a program to solve it. Second, it allows us
to do a bit of revision on Java programming. Third, we explore the ve program structures that
programmers use.
Although our Java programs will always be wrapped up in classes/objects (object-oriented), the
programs within the classes (methods | also variously called subprograms, procedures, functions)
are step-like, like recipes. This type of programming is called procedural programming.
In the sequence of programs that follow, we will explore the ve program structures that arise in
procedural programming. The ve are:
Sequence;
Selection;
Repetition;
Procedures (methods, subprograms, functions);
Procedures with parameters.
How are computer programs and algorithms designed? They do not spring fully formed from your
ngers!
Ex. 1. Write a program to display the following.
* *
* *
* *
* *
**
4{1
//----- OneStar.java ---------------------------------
// j.g.c. 2/3/99, 3/3/99, 2007-12-18
// prints single '*' on screen
//--------------------------------------------------
import java.io.*;
class OneStar{
public OneStar(){
PrintStream o= System.out; /* to shorten System.out.println
statements */
o.println(getClass().getName()+"\n"); /* always useful to display
the name of the program */
// the program
o.print('*');
o.print('\n');
}
4{2
4.1 Sequence
Now, print: *****
class FiveStars{
public FiveStars(){
PrintStream o= System.out;
o.println(getClass().getName()+"\n");
o.print('*');
o.print('*');
o.print('*');
o.print('*');
o.print('*');
o.print('\n');
}
public static void main(String args[]){
new FiveStars();
}
}
class FiveStars2{
public FiveStars2(){
PrintStream o= System.out;
o.println(getClass().getName()+"\n");
o.print('\n');
}
public static void main(String args[]){
new FiveStars2();
}
}
4{3
4.2 Repetition
//----- RepStars.java ---------------------------------
// j.g.c. 2/3/99, 3/3/99, 2007-12-18
// prints *s line on screen using repetition
//--------------------------------------------------
class RepStars{
public RepStars(int n){
width = n;
PrintStream o= System.out;
o.println(getClass().getName()+"\n");
class Triangle1{
4{4
public Triangle1(){
PrintStream o= System.out;
o.println(getClass().getName()+"\n");
int nStars= 1;
for(int i= 0; i< nStars; i++){
o.print('*');
}
o.print('\n');
nStars= 2;
for(int i= 0; i< nStars; i++){
o.print('*');
}
o.print('\n');
nStars= 3;
for(int i= 0; i< nStars; i++){
o.print('*');
}
o.print('\n');
nStars= 4;
for(int i= 0; i< nStars; i++){
o.print('*');
}
o.print('\n');
nStars= 5;
for(int i= 0; i< nStars; i++){
o.print('*');
}
o.print('\n');
}
public static void main(String args[]){
new Triangle1();
}
}
4{5
4.2.2 Repetitions of Repetitions | Nested Loop
We can improve a lot on Triangle1.java.
class Triangle1Rep{
public Triangle1Rep(int h){
height = h;
PrintStream o= System.out;
o.println(getClass().getName()+"\n");
4{6
4.2.3 Data Pattern = Program Pattern
//----- Triangle2.java ---------------------------------
// j.g.c. 2/3/99, 3/3/99, 2007-12-18
// prints filled triangle of '*' on screen
// can you see the program has the same pattern as the data
//--------------------------------------------------
import java.io.*;
class Triangle2{
public Triangle2(){
PrintStream o= System.out;
o.println(getClass().getName()+"\n");
o.print('*');
o.print('\n');
o.print('*'); o.print('*');
o.print('\n');
o.print('*'); o.print('*'); o.print('*');
o.print('\n');
o.print('*'); o.print('*'); o.print('*'); o.print('*');
o.print('\n');
o.print('*'); o.print('*'); o.print('*'); o.print('*'); o.print('*');
o.print('\n');
}
public static void main(String args[]){
new Triangle2();
}
}
4{7
4.3 Procedures | Methods, Subprograms, Functions
4.3.1 Procedures Without Parameters
//----- Triangle2Proc.java ---------------------------------
// j.g.c. 2/3/99, 3/3/99, 2007-12-18
// prints filled triangle of '*' on screen
// using procedures / methods
// here we take the sequences of instructions in
// Triangle2.java and pack them into methods/procedures
//--------------------------------------------------
class Triangle2Proc{
public Triangle2Proc(){
o= System.out;
o.println(getClass().getName()+"\n");
p1(); nl();
p2(); nl();
p3(); nl();
p4(); nl();
p5(); nl();
}
void p1(){
o.print('*');
}
void p2(){
o.print('*'); o.print('*');
}
void p3(){
o.print('*'); o.print('*'); o.print('*');
}
// etc. for p4 and p5
void nl(){
o.print('\n');
}
private PrintStream o;
}
Ex. What criteria should be taken into account when thinking of decomposing a program into
subprograms (procedures / methods)?
4{8
4.3.2 Subprograms with Parameters
//----- Triangle3Proc.java ---------------------------------
// j.g.c. 2/3/99, 3/3/99, 2007-12-18
// bsc1
// see Triangle1Rep.java for basis using repetition
// prints
//*
//**
//***
//****
//*****
// using repetition and procedures/methods
// Analysis:
// Stars
// Line 1: 1
// 2: 2
// 3: 3 etc.
// ---------------------
// i.e. generalising:
// Line j j
// and sequence
//--------------------------------------------------
import java.io.*;
class Triangle3Proc{
public Triangle3Proc(int h){
height = h;
o= System.out;
o.println(getClass().getName()+"\n");
4{9
void nl(){
o.print('\n');
}
private PrintStream o;
private int height;
}
4{10
Equipped with these procedures, we are now in business, and can create nearly any pattern in very
quick time.
class Triangle4{
public Triangle4(int h){
height = h;
o= System.out;
o.println(getClass().getName()+"\n");
4{11
void nl(){
o.print('\n');
}
private PrintStream o;
private int height;
}
4{12
Now, getting more dicult . . .
class Triangle5{
public Triangle5(int h){
height = h;
o= System.out;
o.println(getClass().getName()+"\n");
private PrintStream o;
private int height;
}
*****
****
***
**
*
4{13
//----- Triangle10.java ---------------------------------
// j.g.c. 5/3/99, 2007-12-18
// from Triangle5.java
// Pattern Analysis
//
// Sp St
//************ 0 12
// ********** 1 10
// ******** 2 8
// ****** 3 6
// **** 4 4
// ** 5 2
// Let's generalise (height= h) & count from 0
// Spaces Stars
// Line 1: 0 h*2
// 2: 1 (h-1)*2
// 3: 2 (h-2)*2 etc.
// ---------------------
// i.e.
// Line j: j-1 (h- (j -1) )*2
//--------------------------------------------------
import java.io.*;
class Triangle10{
public Triangle10(int h){
height = h;
o= System.out;
o.println(getClass().getName()+"\n");
private PrintStream o;
private int height;
}
4{14
//----- Triangle20.java ---------------------------------
// j.g.c. 5/3/99, 2007-12-18
// from Triangle10.java
// Pattern Analysis
// Sp1 St Sp2 St
//
//* * 0 1 8 1
// * * 1 1 6 1
// * * 2 1 4 1
// * * 3 1 2 1
// ** 4 1 0 1
class Triangle20{
public Triangle20(int h){
height = h;
o= System.out;
o.println(getClass().getName()+"\n");
private PrintStream o;
private int height;
}
4{15
4.4 Selection
//----- Triangle10Sel.java ---------------------------------
// j.g.c. 5/3/99, 2007-12-18
// from Triangle10.java
// as Triangle10.java, but selecting stars, stripes
//************
// ----------
// ********
// ------
// ****
// --
//--------------------------------------------------
import java.io.*;
class Triangle10Sel{
public Triangle10Sel(int h){
height = h;
o= System.out;
o.println(getClass().getName()+"\n");
void nl(){
o.print('\n');
}
4{16
}
private PrintStream o;
private int height;
}
4.5 Exercises
1. Write a Java program to display an arbitrary lled rectangle of *s (stars) | specied by h(eight)
and w(idth);
2. Write a Java program to display a rectangle outline, 5 5, of *s.
3. Write a Java method, printHexDigit(int n) which will print a Hexadecimal digit | 0, 1,
. . . 9, 10 (A), . . . 15 (F) as follows. Design your own font for 3 onwards.
4{17
Chapter 5
Threads
5.1 Introduction
In your programming so far, you will think of a program more or less as a sequence of instructions;
maybe the instructions are wrapped up in the constructor or other methods of an object, but they
are still instructions. When you execute the program, the computer steps through the program |
steps through the sequence of instructions. You may think that when you hit the run button, the
program starts at the beginning and runs right through to the end, without any interruptions.
The single uninterrupted
ow of execution is not exactly true. What about that Internet Explorer
program; what about the game that you are playing when nobody is watching, an email client,
playing mp3 les, etc. All apparently executing at the same time | the computer is multitasking
or executing taks concurrently.
Today's operating systems software all allow multitasking. The computer can execute a great
many programs at once. A program executing is called a process.
Processes The multiple programs (tasks) you see running on your Windows machine are called
processes; at any time, apart from processes created by programs that you are executing, there
may be fteen or twenty more that Windows is executing as part of the operating system.
Processes operate by having all their programs (and data) loaded into memory at once. The
operating system is a special process that can stop and start other processes (pre-empt them).
On a single processor machine, only once process can be using the CPU at any one time. But if
the operating system starts and stops each of them (in sequence, including itself) quickly enough,
it looks like they are all executing concurrently.
Threads If the computer (and the operating system) can execute many processes at once, could
we arrange our programs so that their execution splits into more than one process? Sounds crazy,
but it does make sense and Java has a program structure that makes it easy to program | a
thread.
The term thread refers to the thread of control, i.e. how the execution program counter threads
its way through memory as a program executes.
5{1
Thread versus Process You may have multiple threads within one process. For example, in
a word processor, you might have: (i) a thread handling input; (ii) one handling formatting for
the screen; (iii) one handling spell-checking; (iv) one handling periodic saves to le; etc. But
each operates on the same memory space. In contrast, separate processes have separate memory
spaces.
As we will see when working with Brackeen's game programs, threads are quite useful when it
comes to games programming.
Dual-core, Quad-core | multiple processors? Multitasking, processes and threads were on the
scene long before multiple processor machine became commonplace; even on a single processor
machine, they confer signicant advantages. However, when we have multiple processors (e.g.
dual-core, quad-core), we have the additional advantage that the operating system can truly allow
more than one thread to execute at the same time, as opposed to faking it with concurrent
programming.
A warning. Concurrent (or parallel) programming is dicult; hence it is going to be dicult to
harness multiple processors for general tasks. For a start, a lot of programs require that program
steps follow in exact succession; in many of the programs you will write, an instruction depends
on the results of a previous instruction. Another example where concurrency cannot help is data
communications; if you have a 10-Mbps connection and a process dedicated to reading data from
the connection, the no amount of concurrent processes will speed it up.
First, we give a demonstration of the eect of multitasking.
5{2
| Job A Job B Job C
|-----ooooo-----+-----ooooo----+-----ooooo-----|
|
+-----+----+----+----+----+----+-----+----+----+
0 10 20 30 40 50 60 70 80 90
Time millisec
(a)
|..........-----ooooo.....-----+ Job C
|
|.....-----ooooo-----| Job B
|
|-----ooooo..........-----| Job A
+-----+----+----+----+----+----+-----+----+----+
0 10 20 30 40 50 60 70 80 90
Time millisec
(b)
Figure 5.1: Illustration of multitasking (a) single user; (b) concurrent tasks
5{3
5.3 Brief Case Study { MS-DOS
5.3.1 Introduction
MS-DOS stands for Microsoft Disk Operating System. MS-DOS version 1.0 was developed for the
original IBM PC which was launched in August 1981. The IBM PC used a 16-bit microprocessor
from Intel called the 8088; in fact, the 8088 was a slightly cut-down version of the Intel 8086.
5.3.2 History
The 8086 was the beginning of the computer family we now know as the Pentium. The family
developed as follows: 8086 (16-bits); 80186 { 8086 with some additions to make it easier to use
for data communications; 80286 { a faster 8086 with additional addressing range { could address
16 Megabytes, and with some features to allow multitasking; 80386 { the start of true 32-bit
computing, actually, the only advance since the `386 has been some go faster parts; the 80386
was faster, but most signicantly its CPU was 32-bit, and it allowed 32-bit addressing (could now
address 4 Gigabytes of memory); 80486 { 80386 with some cache memory on the chip, and the
oating point arithmetic unit also on the chip; 80586 (called the Pentium) . . . You know the rest.
We better mention what came before the 8086. In 1971, Intel developed the rst microprocessor,
the 4-bit Intel 4004; soon after came the 4040. Then in 1973, came the 8-bit Intel 8008, followed
shortly after by the Intel 8080. The 8080 brought about the idea of a personal computer. Later,
a company called Zilog developed a more powerful copy of the 8080, the Z80.
Some reasonably powerful (for the day) microcomputer systems were built around the Z80 and
8080. A small operating system was developed for the 8080/Z80 { Digital Research's CP/M
(Control Program for Microprocessors). When the 16-bit 8086 came on the scene in 1979, initially,
industrial inertia prevented anyone leaving the Z80{CP/M bandwagon. It took a company with
the strength of IBM to introduce 16-bits to the personal computer arena.
Digital Research had started a development of a 16-bit version of CP/M { CP/M-86. When in
late 1980, IBM decided to develop the PC, they initially didn't think too much about the operating
system; eventually, the started to look around. They got in touch with Bill Gates at Microsoft,
who had developed a successful BASIC interpreter for the 8080. Gates agreed to supply a BASIC
compiler. But after some thought, IBM realised they needed some semblance of an operating
system too. Gates suggested Digital Research, but CP/M-86 was away behind schedule and, we
assume, Digital Research had no idea of what was about to happen to the world of computing.
So IBM go back to Gates | we're in trouble, please help us!. Incidentally, Microsoft had been
selling a version of UNIX under licence. UNIX might have done the job, only it needed a hard disk
and 100 Kbytes or more of memory. The IBM PC had just a single 160K
oppy disk, and 64 K of
memory. Gates found a local Seattle company (Seattle Computer Products) who had developed a
crude operating system for the 8086 (86-DOS). Seattle Computer Products agreed to sell 86-DOS
to Microsoft; Microsoft enhanced 86-DOS to produce MS-DOS. MS-DOS shipped with the rst
IBM PCs in August 1981.
5{4
5.3.3 Structure
MS-DOS has a structure along the lines of Figure 5.2. As you can see, MS-DOS allows application
programs to directly access the ROM BIOS or even the hardware itself. This freedom is not present
in Windows 2000 (or XP) or UNIX/Linux and we have already mentioned the advantages of a more
controlling operating system in section 2.7.
The memory layout that exists after booting has completed is shown in Figure 5.3. The total
memory addressable by the 8086, and MS-DOS, is 1 Megabyte (20 bits { 16 bits plus 4 additional
bits added by a bit of jiggery-pokery). Of this 1 MB, IBM decided to keep from 640K and above
for special use. At the time, this wasn't a big deal; the rst PCs had 64K of RAM. It was 1985
before PCs started to have the full 640K.
5{5
+-------------------------------------------------+
| |
| Application Program |
| and |
| shell -- 'command.com' |
| |
+------+-------------------------------+-----+----+
| | |
V | |
| | |
+------+---------------------------+ | |
| | | |
| MS-DOS 'Kernel' | | |
| | | |
+------------------------------+---+ | |
| | | |
V | V V
| | | |
+------+-------------------+ | | |
| | | | |
| MS-DOS Device Drivers | | | |
| | V | |
+--------------------------+ | | |
| | | |
V | | |
| | | |
+------+-----------------------+-------+-+ |
| | |
| ROM BIOS Device Drivers | |
| | |
+------+---------------------------------+ |
| |
V |
| |
+------+-------------------------------------+----+
| |
| Hardware |
| |
+-------------------------------------------------+
5{6
1M (1024K)
+----------------------+ \
| | } really part of OS
| ROM BIOS | }
| | }
+----------------------+ /
| | \
| Video RAM | } also can be considered part of OS
| | }
+----------------------+ 640K /
| |
| Unused |
| |
+. . . . . . . . . . . + program
| Space for |
| User Program |
| |
+----------------------+
| |
| MS-DOS Shell |
| command.com |
+----------------------+
| |
| MS-DOS Kernel |
| |
+----------------------+ OS
| |
| Special use, e.g. |
| interrupt vectors |
+----------------------+ 0
5{7
5.4 Processes
5.4.1 Process Life cycle
The concept of a process is central to multitasking. A rough denition of the term process is: a
program in execution. People have diculty comprehending the dierence between a program and
a process. A program is simply a list of instructions; it has no life. Consider the cookery recipe
example
During its life, a process goes through a series of discrete states, see section 5.4:
5{8
5.4.2 Process Control Block (PCB)
When a process makes the transition from running to either blocked or ready (in which case it
relinquishes the CPU), it is necessary to store some details, for example: just as in a subprogram
call, where it has got to (the program counter (PC)), but more. The process control block (PCB)
is a record containing important current information about the process, for example: current state
of the process, unique identication of the process, the process's priority, open les & IO devices,
use of main memory and backing store, other resources held, copies of the registers (see chapter
7).
interrupt handling;
process creation & destruction;
process state switching and scheduling;
interprocess communication;
manipulation of PCB;
5{9
support of IO activities;
support of memory allocation & deallocation;
support of the le system;
support of system accounting functions.
5{10
If you click Start, the program waits until the current ball nishes, and only then does it start the
next one; likewise, clicking Close has no eect until the program is nished what it is currently
doing. The program is executing in a single thread.
In contrast, the program in Figures 5.10, 5.11 and 5.12, creates a new thread for each click of
Start and you can have many balls bouncing at once; it also creates a thread that will take care
of the Close button | you do not have to wait until everything is nished.
5{11
/** Bounce.java
@version 1.30 2001-05-06 @author Cay Horstmann
*/
/**
Shows an animated bouncing ball.
*/
public class Bounce{
public static void main(String[] args)
{
JFrame frame = new BounceFrame();
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
frame.show();
}
}
/**
The frame with canvas and buttons.
*/
class BounceFrame extends JFrame{
/**
Constructs the frame with the canvas for showing the
bouncing ball and Start and Close buttons
*/
public BounceFrame(){
setSize(WIDTH, HEIGHT); setTitle("Bounce");
addButton(buttonPanel, "Close",
new ActionListener()
{
public void actionPerformed(ActionEvent evt)
{
System.exit(0);
}
});
contentPane.add(buttonPanel, BorderLayout.SOUTH);
}
/**
Adds a bouncing ball to the canvas and makes
it bounce 1,000 times.
*/
public void addBall(){
try
{
Ball b = new Ball(canvas);
canvas.add(b);
5{13
/**
The canvas that draws the balls.
*/
class BallCanvas extends JPanel{
/**
Add a ball to the canvas.
@param b the ball to add
*/
public void add(Ball b){
balls.add(b);
}
/**
A ball that moves and bounces off the edges of a
component
*/
class Ball{
/**
Constructs a ball in the upper left corner
@c the component in which the ball bounces
*/
public Ball(Component c) { canvas = c; }
/**
Draws the ball at its current position
@param g2 the graphics context
*/
public void draw(Graphics2D g2)
{
g2.fill(new Ellipse2D.Double(x, y, XSIZE, YSIZE));
}
5{14
/**
Moves the ball to the next position, reversing direction
if it hits one of the edges
*/
public void move()
{
x += dx;
y += dy;
if (x < 0)
{
x = 0;
dx = -dx;
}
if (x + XSIZE >= canvas.getWidth())
{
x = canvas.getWidth() - XSIZE;
dx = -dx;
}
if (y < 0)
{
y = 0;
dy = -dy;
}
if (y + YSIZE >= canvas.getHeight())
{
y = canvas.getHeight() - YSIZE;
dy = -dy;
}
canvas.paint(canvas.getGraphics());
}
5{15
/** BounceThread.java
@version 1.30 2001-05-06 @author Cay Horstmann
*/
/**
Shows an animated bouncing ball running in a separate thread
*/
public class BounceThread{
public static void main(String[] args)
{
JFrame frame = new BounceFrame();
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
frame.show();
}
}
/**
The frame with canvas and buttons.
*/
class BounceFrame extends JFrame{
/**
Constructs the frame with the canvas for showing the
bouncing ball and Start and Close buttons
*/
public BounceFrame(){
setSize(WIDTH, HEIGHT); setTitle("BounceThread");
addButton(buttonPanel, "Close",
new ActionListener(){
public void actionPerformed(ActionEvent evt){
System.exit(0);
}
});
contentPane.add(buttonPanel, BorderLayout.SOUTH);
}
5{16
/**
Adds a button to a container.
@param c the container
@param title the button title
@param listener the action listener for the button
*/
public void addButton(Container c, String title,
ActionListener listener){
JButton button = new JButton(title);
c.add(button);
button.addActionListener(listener);
}
/**
Adds a bouncing ball to the canvas and starts a thread
to make it bounce
*/
public void addBall(){
Ball b = new Ball(canvas); canvas.add(b);
BallThread thread = new BallThread(b);
thread.start();
}
/**
A ball that moves and bounces off the edges of a
component
*/
class Ball{ // same as previous
5{18
Chapter 6
6.1 Introduction
This chapter discusses the nature of images, human vision, cameras and other image sensors, the
nature of colour. We mention how colour images are represented in a computer.
Also, in discussing eyes and cameras, we prepare ourselves for three-dimensional (3D) graphics.
When we look at a 3D world scene with our eyes, or with a camera, we are collapsing that 3D
scene onto two dimensions (2D). In the 3D graphics part of a video game we create a virtual 3D
world, but to display it on a 2D screen requires the computer to perform (mathematically) the
same task as an eye or a camera does.
Some diagrams in this chapter are taken from Gonzalez and Woods (Gonzalez & Woods 2002),
chapters 2 and 6.
6{1
lengths, volumes, areas, masses, weights; that is until you get down to atomic sizes | as Max
Planck and Albert Einstein discovered when they came across the quantum theory of physics.
If you want to represent real world quantities in a computer you need to convert them to discrete
or digital versions; but apart from digital images taken with a digital camera, our computer game
virtual worlds will be digital from the start.
An image is some sort of representation of some part of the real world. A painting is an image;
a printed photograph is an image; both are continuous representations | meaning that you can
magnify a part of the image larger and larger and it still looks smooth.
Contrast digital images. These are made up of little blocks called pixels | short for picture
elements. An individual pixel has a xed colour. If you keep magnifying a digital image eventually
you will see that it is a joined up patchwork of pixels. But if the pixels are small enough | we say
that the image has high spatial resolution | your eye sees the image as continuous.
If the discrete blocks are small enough the whole lot looks continuous. High resolution.
Same for time and space.
Time is continuous. But in a clock it is represented as a digital quantity; in a normal ticking clock
such as a grandfather clock, it is digitised into seconds; in an electronic watch it is digitised into
whatever is the frequency of the vibrating crystal that drives it.
There are two parts to digitisation: (a) the chopping up into blocks (in the case of images) and
into time samples in the case of sound and video | this is sampling; (b) converting brightness, in
the case of images, and loudness, in the case of sounds, into numbers | this is digitisation. But
sometimes sampling and digitisation are lumped together as digitisation.
Real Numbers versus Integer Numbers First of all we have the natural numbers f0; 1; 2; : : :g;
these are the numbers we use when we count. Integers include the natural numbers together with
their negatives, f 1; : : : ; 2; 1; 0; 1; 2; : : : ; +1g.
Real numbers are an entirely dierent matter. When we measure things, e.g. the weight of a piece
of cheese, the length of a piece of string, we have a real number. You might say, the weight of
this piece of cheese is 25 grams. Not much dierence from a natural number, I hear you say. But,
almost certainly, in coming up with the 25, you merely took the nearest natural number. If you were
in a laboratory, using a very accurate instrument, you might have originally had 25.4124359267
grams. At home you might have got 25.4 grams. Which is correct, 25, 25.4, 25.4124359267
grams? Actually, none of them. If you wanted to be fully correct, you'd have to use thousands
and millions of digits; to be exact, innity of them. Real numbers form a continuum. Between any
two real numbers, no matter how close, there are an innite number of other real numbers. The
more precision you use in your measurement, the more digits you get.
In contrast, between 3 and 6, there are just two other integer numbers, 4 and 5. You cannot be
any more precise than counting the people in a classroom and stating, for example, there are 23
students present.
It is easy to represent integers in a computer; the only slight problem is that you cannot get to
+= 1, but you can get as close as you need.
Ex. (a) What are the largest negative and positive numbers possible in a C++ int variable? (b)
C++ short? (c) C++ byte? (d) What is the dierence between signed and unsigned
6{2
6.3.2 Analogue to Digital Converters and Digital to Analogue Converters
When you have an analogue signal and need to get it into a computer, you need an Analogue to
Digital Converter (ADC); an ADC performs two tasks: (a) samples in time and (b) converts to
numbers.
When you have an digital signal or a set of numbers in a computer and you want to send them to,
for example, a loudspeaker, you need an Digital to Analogue Converter (DAC); a DAC converts
to numbers to voltage or current. Because there may be stepiness or blockiness in the analogue
signal so produced, a DAC is often followed by a smoothing lter. Anti-aliasing, see below, is a
form of smoothing out of digital eects in image displays.
Back to images.
Monochrome versus colour Monochrome images are grey level images; they are sometimes
called black-and-white | but incorrectly, for black-and-white implies that there are just two values:
black, and white, and no in-between. - i.e. f (x ; y ) is a grey level.
In a colour image f (x ; y ) gives a colour. A colour image can be represented by three monochrome
images, each representing the intensity of a primary colour (red, green, blue). Thus,
fr (x ; y ); fg (x ; y ); fb (x ; y ).
Digital The monochrome image, f (x ; y ), mentioned above is still continuous, and in two senses:
(i) f (x ; y ) is a real (continuous valued) number, and, (ii) x, and y are real numbers. So, continuous
valued, and spatially continuous | like a photograph.
Thus, you can achieve innitesimally ne resolution in f (x ; y ), and in x , and y .
In computers we must use digital (or discrete) approximations. We approximate f (:; :) by restricting
it to a discrete set of grey levels; often an 8-bit integer 0 : : : 255, and, we sample f (:; :) at a discrete
lattice of points, xi ; i = 0 : : : n 1, and yj ; j = 0 : : : m 1; see Figure 6.1.
Thus, we arrive at a digital image, f (r; c ), where f can take on discrete values 0 : : : G 1 and r ,
0 : : : n 1, c , 0 : : : m 1.
f can now be viewed as a matrix (two-dimensional array) of numbers,
6{3
0 xmax 0 m-1
+--------------------> x +--------------------|> j (c -
| | column)
0 | . . 0 | f(1,1) f(1,2)
| x1,y1 x2,y1 |
| |
| . | f(j, i)
| xi,yj j |
| r - row|
| |
ymax| n-1- f(m-1, n-1)
V V
y
Continuous image: Discrete:
domain of f(,) is
[x = 0,xmax], [y = 0,ymax] {0..n-1}, {0..m-1}
an n-row X m-column
image (m X n)
(a) (b)
Also, we have the problem that computers like $r$ to grow \emph{down},
rather than as $y$, up, in the real world.
6{4
Ex. Eight bits (each) are adequate to represent colours, i.e. if you went to 12 or 16 bits there
would be no perceptible improvement. Why do many graphics cards use 32-bits per pixel? There
are at least two reasons.
Ex. (a) If you had to digitise a TV image broadcast by RTE or BBC, suggest suitable values of
m, n; (b) using the results of (a), and assuming 25 frames (images) per second, how much data
for a one hour lm ?
Raster scanning The image model given above corresponds to the image model used in raster
graphics, i.e. the image is formed by regular sampling of the x , and y axes.
Spatial Resolution Spatial resolution is high if the samples xi , yj are closely spaced, and is low
if they are widely spaced. Clearly, the closer the spacing, the more alike the digital image will be
to the original, i.e. we are always demanding higher resolution. On the other hand, the higher the
resolution, the larger are m, n | more data; data volume grows as the square of the resolution.
Another reason to restrict n and m to numbers like 768, 1024 is that displays, see section 6.4,
cannot handle any higher resolution.
Ex. Laser printers commonly work at 300 dots (pixels) per inch. How many pixels in an A4 page?
The eects of reducing spatial resolution are shown in Figure 6.2. The original image, upper left, is
256 256; the upper right image simulates the eects of reducing resolution and thereby reducing
the number of pixels to 128 128; similarly, the lower left simulates a 64 64 pixel image and the
lower right 32 32.
These days a cheap digital camera will give you about 3000 2000 pixels and the most expensive
ones about 4000 3000.
Grey Level Resolution With proper selection of the digitisation range, it is usually possible to
represent, without any humanly perceivable degradation, monochrome images using just 8-bits;
the psychologists tell us that humans can perceive no more than about 160 levels at once. Also,
in my experience, there appears to be some natural law that says that most image sensors cannot
deliver any useful higher grey-level / colour resolution.
Ex. Palette-based image representation works a bit dierently than using red, green, and blue
values for each pixel Explain. See Brackeen book, or do a web search.
6{5
Figure 6.2: Upper left: original image. Upper right: resolution reduced by a factor of 2. Lower left
and right: reduced by factors of 4 and 8.
6{6
The eects of reducing grey level resolution are shown in Figures 6.3 and 6.4. The original image
is the same one that is in the upper left of Figure 6.2.
Figure 6.3: Image quantised to 16 grey levels, top; eight levels, bottom.
After printing on a laser printer and then photocopying, the eects may not be too obvious; on a
computer screen, 16 levels (four bits) is indistinguishable from the original, at eight levels (three
bits) you start to notice the quantisation, at four levels (two bits) the quantisation is very obvious;
and then two levels (one bit). The fact that the image was noisy to start o reduces the eect a
little.
Ex. (a) Make sure you are comfortable with the correspondences: 16 levels, 4-bits; 8 levels, 3-bits;
4 levels, 2-bits; 2 levels, 1-bits; (b) what would a 0-bit image look like?
Ex. (a) We have seen that 16 grey levels (4-bits per pixel) might be enough in some cases; how
could this be used to reduce the size of an image le? (b) If the original image is 256 256 8
bits, how many bytes? (c) How many bytes in the 256 256 4 bits image?
Noise We said that the original in Figure 6.2 is noisy. The original was taken from one frame of
a video; a video camera has to grab image very fast, i.e. spends little time on each grab, hence
it has little time to smooth out random variations in the little sensors. This is noise. You get the
same sort of noise if you record sounds with a very cheap microphone.
Noise is little variations in the image pixels (or sound samples) that were not there in the scene
that the camera pointed at.
6{7
Figure 6.4: Image quantised to four levels, top; two levels, bottom.
6{8
6.3.4 Anti-aliasing
Pixels are little blocks of colour. When you display a line or text character or some object on top
of a background, but which contrasts with the background, the blockiness can be perceivable. We
can get rid of the blockiness (aliasing) by blending the object into its background. This spatial
blending is called anti-aliasing. Most graphics cards will handle anti-aliasing for you.
If you look again at the bottom left image in Figure 6.2 you will see blockiness or aliasing; if you
defocus your eyes, the blockiness will disappear and you will start to think that you see more detail
in the image. The blurring caused by defocussing the eyes is the equivalent of anti-aliasing.
// R G B
Color c = new Color(255, 0, 0); // pure red
But you can also specify the opacity (transparency) of the colour. The opacity is called alpha; so
now we have Red, Green, Blue, Alpha values:
// R G B A
Color c = new Color(255, 0, 0, 255); // pure red, completely opaque
6{9
as continuous. Thus you can easily change the resolution of the images that you send to it. Of
course, depending on the size and construction of the CRT, these is an upper limit, normally
something like 1600 1200 for a 17-inch CRT. If, in the operating systems settings, you set the
display to 640 480, and display on the latter CRT, you might see a bit of blockiness, but the
image would ll the screen.
A liquid crystal display (LCD) is truly digital; typical LCD screens are 1024 768 (15{17-inch) and
1280 1024 for 19-inch. If you you set the display to 640 480, and displayed on the one of the
latter LCDs, you would probably get a little image in the middle of the screen and blank around
the edges. Some LCD displays have the capability of resampling.
What follows is taken from a Usenet newsgroup sci.image.processing answer by Dave Martindale
(d|@cs.ubc.ca), to a question by me.
In the case of LCD screens, there is local memory in the LCD controller to remember the state
of every pixel in the screen. Because of this, there are two parts to "refreshing" an LCD screen:
getting the data from the computer frame buer (graphics card) to the LCD controller, and then
driving the LCD panel itself.
The rst part of the process is done as if the LCD was a raster device. The pixel data is sent from
the computer to the LCD controller in row/column raster order just as if it was a CRT. If you're
using an analog connection between computer and display, the graphics card actually generates
analog RGB and sync signals just as if it was driving a CRT - it has no way of knowing the display
is actually an LCD. Then the display controller generates local clock signals locked to the incoming
analog video, and converts the signal back into digital form before storing the pixel data in the
LCD controller memory. If the frame buer pixel clock and the LCD controller pixel clock are not
the same, you can end up with pixel jitter artifacts.
On the other hand, if you use a digital (DVI) connection between graphics card and display, the
pixel data is transferred in digital form, with no noise introduced by D/A and A/D conversion, and
without wasting time for horizontal and vertical sync and blanking periods. This is more ecient,
and avoids the need for the digitizing circuitry in the display.
Either way, once the pixel information is in the LCD controller, the controller then uses it to mod-
ulate individual pixel cells in the LCD panel itself. This happens at a frequency that is determined
by the controller and panel's needs, and it's not necessarily synchronized with the incoming video.
LCD screens have a native resolution, i.e. each screen pixel corresponds to a single indivisible
element. However, many LCD monitors contain internal resampling hardware that will accept
an incoming signal at a wide range of resolutions and then resample that to the actual display
resolution. The image tends to lose some crispness when you do this, so it's generally better to
operate at the native resolution.
Raster refresh and
icker and tearing The refresh is raster as described above.
The light output from an LCD is continuous; it doesn't come in bright pulses as the electron beam
sweeps over the phosphor like a CRT. This means that LCDs don't
icker if they are updated
slowly from the computer; 60 Hz refresh
ickers visibly on a CRT but not LCD.
On the other hand, tearing is caused when a single displayed image on screen comes from two
dierent points in time. To avoid this with a CRT, it's simply necessary to have the video con-
troller swap buers (between the previous and next rendered frame) during vertical retrace so each
6{10
displayed frame comes from a single point in time. With an LCD, there's the additional delay
between display controller update and screen update which can complicate things.
If 25{30 Hz is good enough for television or movies, why the need for 70{85 Hz refresh on
computer screens? With a
ickering light source, we can see
icker up to about 72 Hz when
the light is very bright, dropping below 50 Hz when the light is dim.
Television uses a 25 or 30 Hz complete frame rate, but the image is sent in interlaced mode: all the
even scanlines are sent in the rst 1/50 or 1/60 second "eld", followed by all the odd scanlines
in a second eld. CRTs display this signal in the same way, so the screen is actually refreshed at
50 or 60 Hz; it just isn't quite the same data each time. As long as there are no drastic changes
between two adjacent scanlines (and good TV is ltered so there is not), we don't see
icker.
Movies are shot at 24 FPS, but the projectors use a shutter that interrupts the light either 2 or
3 times per frame, so the actual
icker rate on screen is 48 or 72 Hz. 48 Hz is most common,
and works well in most theatres where even the brightest white in the image is not that bright in
absolute terms, and most of the image is much dimmer. It's common to see a little bit of
icker in
the brightest portion of the image only. 72 Hz shutters are better in small theatres with particularly
bright images; that pretty much eliminates visible
icker.
But computer screens aren't interlaced (anymore), and they are operated at high brightness, so
you need about 72 or 75 Hz refresh rate to avoid visible
icker.
LCD versus TFT versus Plasma TFT is just one LCD panel technology; it's not a separate type
of display. Plasma displays are likely very similar to LCDs when it comes to the computer-display
controller connection. Driving a plasma panel takes very dierent voltages and current from driving
an LCD panel. LCDs use very low voltage and current to change the polarization state of the liquid
crystals, while the light comes from a separate backlight and two polarizing sheets actually absorb
or pass light. Plasma panels emit light directly from each pixel cell.
6{11
6.5 Visual Perception
Here, brie
y, are some points about human visual perception:
the perceived image may dier from the actual light image (i.e. the perceived brightness
image is a considerably modied `copy' of the physical light intensity emanating from the
scene);
there are two types of light sensors on the retina { rods and cones;
rods are more sensitive than cones; rods are used for night (scotopic) vision; rods are largely
colour insensitive (e.g. no colour evident in moonlight);
cones are used for brighter light, cones can sense colour;
perceived (subjective) brightness (Bs ) is roughly a logarithmic function of light intensity (L):
thus, if you increase L by 10, Bs increases by only 1 unit, increase L by 100 Bs increases by
2 units, 1000 increases by 3 etc.
the visual system can handle a range of about 1010 (10 thousand million) in light intensity
(from the threshold of scotopic vision to the glare limit). (Question: how many bits is that?)
to handle this range, the pupil must adapt by opening and closing the pupil; opening the pupil
{ in darkness { lets more light in; closing it { in bright light { lets less light in;
the eye can handle only a range of about 160 levels at any one instant, i.e. where there is
no opening and closing of the pupil; of course, this explains why 8-bits (256 levels) usually
suce in a display memory.
Figure 6.5 (from (Gonzalez & Woods 2002)) shows a simplied cross section of a human eye.
Note the lens and the light sensitive retina | a cameras also has a lens and light sensitive sensors
or lm.
Figure 6.6 (from (Gonzalez & Woods 2002)) shows image formation in a a human eye. A camera
operates similarly, replacing the retina with light sensitive sensors or lm.
6{12
Figure 6.5: Cross section of the human eye.
6{13
6.6 A Model of a General Imaging System
Note: in this chapter we treat physical units somewhat informally | a later chapter give a little
more detail.
A general camera-based sensing arrangement is shown in Figure 6.7 ((Gonzalez & Woods 2002)).
The scene element, some distance from the camera lens, is projected onto the image plane. At
the image plane there is a mosaic of light sensitive sensors, see Figure 6.8; this mosaic has the
eect of transforming the two- dimensional continuous image lightness function, fi (y ; x ), into a
discrete function, f 0 [r; c ], where r (ow) and c (olumn) are the discrete spatial coordinates. Then, the
electrical voltage or current output from each sensor eventually, f 0 [:] gets digitised to yield a digital
image, f [r; c ]. Hence, we have two digitisations: rst spatial | a spatial chopping (sampling) into
rectangular pixels; next amplitude | conversion of analogue sensor output (voltage or current)
into numbers. The data are then ready for transferring to computer memory.
For colour, all we need are alternating red, green and blue sensors. Normally, the sensors will all
be the same, but will have red, green, or blue lters in front of them.
Figure 6.8: Continuous image (a) projected onto a sensor array; (b) sampled (spatially) and
quantised (in amplitude values).
6{14
Thus, we arrive at a digital image: f [r; c ] where f can take on discrete values [0; 1; : : : G 1] and
r 2 [0; 1::nRow s 1], c 2 [0; 1::nCol s 1]. And if the camera handles colour, we have three
images, fr ed ; fgr een ; fblue .
i (x ; y ) { the illumination of the scene, i.e. the amount of light falling on the scene, at (x ; y ),
r (x ; y ) { the re
ectance of the scene, i.e. the ratio of re
ected light intensity to incident
light.
f (x ; y ) = i (x ; y )r (x ; y ) (6.3)
Eqn. 6.3 is depicted in Figure 6.9; the amount of light falling on the surface is i ; r is the amount
of light that gets re
ected. r would be nearly 1 for a very white surface and nearly 0 for a black
surface, but, completely white (r = 1:0) and completely black (r = 0:0) are hard to achieve.
The table below gives some naturally occurring ranges of values of i and r :
6{15
Figure 6.9: Light re
ection.
fc (x ; y ) = Kf (x ; y ) (6.4)
If K = K (x ; y ), i.e. it varies across the image plane, then we have non-even sensitivity and if we
look very closely our image may look a little patchy.
6{16
Wavelength (m) Name Frequency (Hz)
10 15 1 femtometer (fm) gamma rays 3 1023 Hz
10 12 1 picameter X-rays 3 1020 Hz
10 9 1 nanometer X-rays 3 1017 Hz
10 8 10 nm Ultraviolet 3 1016 Hz
10 7 100 nm U-V
4 10 7 400 nm Visible light (violet)
7 10 7 700 nm Visible (red)
10 6 1 micrometer Infrared (near) 3 1014 Hz
10 5 10 micrometers Infrared 3 1013 Hz
Infrared (heat)
10 3 1 millimeter Infrared (heat) + 3 1011 Hz
microwaves (300 GigaHz)
10 1 0.1 meters microwaves 3 109 (3 GigaHz)
1 meter TV etc. (UHF) 3 108 (300 MegaHz)
FM radio is 100 Mhz (VHF)
10 meters radio (shortwave) 30 Mhz
100 meters radio (shortwave) 3 MHz
200 600 m radio (medium wave) 1.5 MHz to 500 KHz
1500 m (1 Km) radio (long wave) 200 KHz
Things get more complicated when we think about the angle at which the light hits the surface
and the angle of the eye or camera that is seeing the re
ected light.
There are two models which give a good approximation of re
ection from surfaces; these are
diuse, also called Lambertian, and specular.
Diuse re
ection corresponds to matte surfaces. Specular re
ection corresponds to shiny surfaces
(specular means mirror-like).
We will deal with these when we get to 3D graphics programming in Year 2.
6.7 Colour
6.7.1 Electromagnetic Waves and the Electromagnetic Spectrum
Light is a form of energy conveyed by waves of electromagnetic radiation. The radiation is char-
acterised by the length of its wavelength; the range of wavelengths is called the electromagnetic
(EM) spectrum. Visible light occupies a very small part of the spectrum.
Table 6.7.1 shows the EM spectrum: the left hand column gives the wavelength in meters, the
middle gives the name of the band, and the right gives the frequency of the radiation in Hertz
(cycles per second). Figure 6.10 (from (Gonzalez & Woods 2002)) shows another view of the EM
spectrum.
6{17
Figure 6.10: Electromagnetic spectrum.
6{18
Thus, roughly speaking, if you were to speed-up the frequency of vibration of a TV signal, you
would get microwaves, speed-up microwaves ! heat radiation, ! light ! UV ! X-rays, etc.
If you had a very small and light magnet suspended in a vacuum and brought it near to an RTE
TV transmitter, it might start to vibrate at around 600-MHz (600,000,000 times a second);
that corresponds to a wavelength of 0.5-metre; for more on UHF (ultra high frequency), see
http://en.wikipedia.org/wiki/Ultra_high_frequency.
Frequency, f , wavelength and speed of the waves (speed of light), c are related by equation 6.5,
f = c: (6.5)
f is measured in Hertz (Hz); is measure in metres (m), and c = 3 108 metres per second
(ms 1 .
Ex. What is the frequency of yellow light? Assume an average wavelength of 600-nm. Is blue light
faster or slower? Which has the smaller wavelength?
Ex. Which has the larger wavelength, a UHF TV signal (e.g. 600-MHz) or yellow light?
It is possible to use various parts of the EM spectrum for imaging: e.g. X-rays, microwaves, infrared
(near), and thermal infrared. Our major interest will be in visible light.
6{19
Figure 6.11: Eye overall sensitivity
Figure 6.12: Sensitivity of red, green, and blue cones in the human eye.
6{20
6.7.3 Sensors
A light sensor is likely to have a similar spectral response curve to Figure 6.11, though usually
atter and wider { i.e. more equally sensitive to wavelengths, and sensitive to UV and to near
infrared.
If Figure 6.11 was the spectral response of a sensor, then a blue light (see above), compared to a
green-yellow light of the same power, would produce a sensor output of 10% of the voltage of the
green-yellow.
6{21
6.7.5 Spectral Responsivity
The relative response of a sensor can be described as a function of wavelength (forget about (x ; y )
or (r; c ) for the present): d (), where denotes wavelength.
The light arriving through the lens can also be described as a function of : g (), and the overall
output is found by integration:
Z 1
voltage = d ()g ()d (6.6)
0
or,
Z 1
voltage = d ()g 0 ()d (6.9)
0
6{22
6.7.7 Additive Colour
If you add approximately equal measures (we are being very casual here, and not mentioning units
of measure) of blue light, green light and red light, you get white light. That's what happens on a
colour screen when you see bright white: each of the blue, green, and red spots are being excited
a lot, and equally. Bring down the level of excitation, but keep them equal, and you get varying
shades of grey.
Your intuition may lead you to think of subtractive colour; lters are subtractive: the more lters,
the darker; combine blue, green and red lters and you get black. However, with additive colour,
the more light added in, the brighter; the more mixture, the closer to grey { and eventually white.
i (; x ; y ) { the spectral illumination of the scene, i.e. the amount of light falling on the scene,
at (x ; y ), at wavelength ,
r (; x ; y ) { the re
ectance of the scene, i.e. the ratio of re
ected light intensity to incident
light
Why does an object look green (assuming it is being illuminated with white light)? Simply because
its r (; ::) function is high for in the green region (500-550-nm), and low elsewhere (again, see
Figure 6.13). Of course, illumination comes into the equation: a white card illuminated with green
light (in this case i (; ::) looks like Figure 6.11) will look green, etc.
6.7.9 Exercises
Ex. 1 A coloured card whose re
ectivity is r (; x ; y ) is illuminated with coloured light with a
spectrum i () (constant over spatial coordinates (x ; y ); this is sensed with a camera whose
CCD sensor has a responsivity d () (again constant over x ; y ); a lter with transmittance
t () is used. Show that the overall voltage output is
Z
v (x ; y ) = r (; x ; y )i ()t ()d ()d
Ex. 2 A blue card is illuminated with white light; explain the relative levels of output from a colour
camera for blue, green, red.
6{23
Ex. 3 A blue card is illuminated with red light; explain the relative levels of output from a colour
camera for blue, green, red.
Ex. 4 A blue card is illuminated with blue light; explain the relative levels of output from a colour
camera for blue, green, red. What, if any, will be the change from Ex. 2.5-4 ?
Ex. 5 A white card is illuminated with yellow light; explain the relative levels of output from a
colour camera for blue, green, red.
Ex. 6 A white card is illuminated with both blue and red lights; explain the relative levels of output
from a colour camera for blue, green, red.
Ex. 7 A blue card is illuminated with both blue and red lights; explain the relative levels of output
from a colour camera for blue, green, red; what, if any, will be the change from Ex. 5.
just like the eye, lm is limited in the range of illumination that it can handle;
a camera adapts by opening / closing the lens diaphragm, { or, by increasing or decreasing
exposure time.
6{24
Figure 6.14: Colour image, displayed as colour.
Figure 6.15: Red, green, and blue components of the colour image.
6{25
Next, Figures 6.16 to 6.19 show the cyan, magenta, yellow, and black representations of Fig-
ure 6.14; the black image gives the darkness, i.e. negative of the lightness.
Think colour photography negatives; cyan is sort of the negative of red, magenta the negative of
green, and yellow the negative of blue; and black is the equivalent of a monochrome negative.
6{26
Figure 6.18: Yellow component of the colour image.
Figure 6.19: Black component of the colour image, i.e. same as a monochrome negative
6{27
Instead of explicit colour components, there is another more useful way of representing colour,
again three components, Hue, Saturation, Intensity (HSI):
Figure 6.20 shows the hue, saturation, and intensity image representations of Figure 6.14. Note
that the right hand image in Figure 6.20 (intensity, or lightness) is the negative of Figure 6.19
(darkness).
Figure 6.20: Hue, saturation, and intensity; intensity is the same as a monochrome positive.
HSI, or a variation on it, is used in ordinary television transmission. Of course, when you want to
display on a CRT or LCD, you have to convert back to RGB.
HSI is useful when you want to do data compression. Our eyes are relatively insensitive to colour
variations both spatially and grey level; hence, use high grey level resolution (say 8-bits or 256
levels), and full spatial resolution, for the Intensity part; and use much decreased resolution, e.g.
four bits each in grey level, and maybe half spatial resolution, when transmitting the images or
storing them to le.
Ex. (a) Take a 256 256 colour image, three bytes per colour. How many bytes? (b) using the
scheme mentioned above, i.e. 8-bits for Intensity | how many bytes for the Intensity component?
(c) using the scheme mentioned above for Hue, i.e. 4-bits per pixel and spatial resolution halved
to yield an N M image; what are N and M? how many bytes for the Hue component? (d) repeat
(c) for Saturation; (e) how many bytes for the HSI image? (f) what percentage is the answer to
(e) of the answer to (a)?
There is a variation on HSI called YIQ that is used by the JPEG image format.
6{28
Chapter 7
Introduction to 2D Graphics
7.1 Introduction
This a an introduction to programming two-dimensional graphics in Java; it is almost entirely based
on Horstmann (Horstmann 2005) Chapter 5 and these notes are based on his HTML slides for the
chapter (available on the web).
What we will do:
1. How do you display a square frame with a title bar that reads "Hello, World!";
2. Change the program to display two frames at once.
7{1
import javax.swing.*; // Java eXtension, Swing, JFC
frame.setSize(FRAME_WIDTH, FRAME_HEIGHT);
frame.setTitle("An Empty Frame");
// what to do with program when someone kills the window
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
7{2
Answers
1. frame.setSize(300, 300);
frame.setTitle("Hello, World!");
2. public class EmptyFrameViewer2{
public static void main(String[] args){
JFrame frame1 = new JFrame();
JFrame frame2 = new JFrame();
frame1.setSize(FRAME_WIDTH, FRAME_HEIGHT);
frame2.setSize(400, 100);
frame2.setLocation(250, 150); // location on the screen
frame1.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
frame2.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
frame1.setVisible(true);
frame2.setVisible(true);
}
}
Dissection of RectangleComponent
1. RectangleComponent extends JComponent. What that means is that there is a class called
JComponent that the nice people at Sun have already written. JComponent has all of the
code necessary to enable it to be attached (added) to a JFrame and all of the code necessary
to allow it to act as a viewable component. All it is missing is the code to draw the stu in
it; this is provided by paintComponent(Graphics g).
Think of a JComponent as an MP3 player that you can buy in a shop. When you
get it, it has no music; you supply the music, just like you supply the drawings in
paintComponent(Graphics g).
7{3
2. RectangleComponent extends JComponent is called inheritance; you'll cover inheritance
at some stage in your Software Design series of modules. At present, it is enough to think of
inheritance as we have just explained: the JComponent code has almost everything needed
to be a component on a JFrame, we just have to provide the drawing part.
3. Here's another way of thinking about extends; you come in to the college as Person | you
can walk, talk, . . . , do all the things that Persons can do. You have a blank place somewhere
in your head called program-a-computer; it's blank to start o with | if we ask you to
program-a-computer, nothing happens. The purpose of this course is to put something useful
in that program-a-computer space. We could say Computer Programmer extends Person,
i.e. a Computer Programmer is a Person with something in the program-a-computer space.
4. Later we will come across extends in a games situation; we'll have a Sprite class whose
objects can move about the screen and provide an animation. But when we come to develop-
ing a game, we'll want to have a Creature class, class Creature extends Sprite; then
class Player extends Creature, class Fly extends Creature, all the time lling in
more details | or replacing details.
5. Whenever a JFrame is made visible, and JComponent that is attached to it executes its
paintComponent method and the drawings appear.
6. paintComponent(Graphics g) takes a parameter Graphics g; Graphics g is provided by
Java Swing.
7. Graphics g is an object which represents the graphics context.
8. Actually, instead Graphics g, the current version of Swing passes a Graphics2D ob-
ject; Graphics2D objects can do a lot more than old style Graphics objects, but
for backwards compatibility we have paintComponent(Graphics g). However, because
Graphics2D extends Graphics we can relabel Graphics g to Graphics2D g2.
Think of the latter as you visiting a local software company; you are a Person. But because
the company knows where you came from, they say \are you a Computer-Programmer?";
you say \yes", so they say \sit down there and write us some programs". You entered as
a Person, but they recognised you as a Computer-Programmer and they relabelled you as
Computer-Programmer.
Graphics2D g2 = (Graphics2D) g;
Person p;
Computer-Programmer cp = (Computer-Programmer) p;
Of course, you are still a Person, also | you have all the attributes of a Person, but, in
addition, your program-computers space has been lled.
9. The following constructs a Rectangle2D.Double object whose top-left corner is at x =
60; y = 70 and whose width (x ) is 40 and height (y ) is 50.
7{4
10. Then we set the drawing Color g2.setPaint(Color.red); Had we not done that, the
Color would have been black, the default. g2.setPaint is the same as g2.setColor,
which you may notice is some programs.
11. And nally we draw it onto g2
g2.draw(r1);
12. Now we make another Rectangle and this time we draw it lled.
Rectangle2D.Double r2 =
new Rectangle2D.Double(160.0, 170.0, 50.0, 80.0);
g2.setPaint(Color.blue);
g2.fill(r2);
(ii) We go even more object oriented by putting all the active code in the construc-
tor of RectangleViewer. Then all that is in main is an instruction to construct a
RectangleViewer; the act of construction executes the relevant code.
7{5
import javax.swing.JFrame;
import java.awt.Graphics;import java.awt.Graphics2D;
import java.awt.geom.Rectangle2D; import java.awt.Color;
import javax.swing.JPanel;import javax.swing.JComponent;
frame.setSize(FRAME_WIDTH, FRAME_HEIGHT);
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
/**
A component that draws two rectangles.
*/
class RectangleComponent extends JComponent{
public void paintComponent(Graphics g){
// Recover Graphics2D
Graphics2D g2 = (Graphics2D) g;
7{6
Figure 7.3: Drawing shapes in a JComponent.
Figure 7.4: Drawing shapes in a JComponent.
7{7
7.5 Drawing with Dierent Shapes
The simple car drawings in Figure 7.5 are produced by the code in Figures 7.6 and 7.7.
7{8
import javax.swing.JFrame;
import java.awt.Graphics;
import java.awt.Graphics2D;
import javax.swing.JComponent;
import java.awt.Rectangle;
import java.awt.geom.Ellipse2D;
import java.awt.geom.Line2D;
import java.awt.geom.Point2D;
frame.setSize(FRAME_WIDTH, FRAME_HEIGHT);
frame.setTitle(getClass().getName());
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
/**
This component draws two car shapes.
*/
class CarComponent extends JComponent{
public void paintComponent(Graphics g){
Graphics2D g2 = (Graphics2D) g;
// position at top left corner
Car car1 = new Car(0, 0);
car1.draw(g2);
car2.draw(g2);
}
} ... continued
7{9
/**
A car shape that can be positioned anywhere on the screen.
*/
class Car{
/**
Constructs a car with a given top left corner
@param x the x coordinate of the top left corner
@param y the y coordinate of the top left corner
*/
public Car(int x, int y){
xLeft = x; yTop = y;
}
/**
Draws the car.
@param g2 the graphics context
*/
public void draw(Graphics2D g2){
Rectangle body
= new Rectangle(xLeft, yTop + 10, 60, 10);
Ellipse2D.Double frontTire
= new Ellipse2D.Double(xLeft + 10, yTop + 20, 10, 10);
Ellipse2D.Double rearTire
= new Ellipse2D.Double(xLeft + 40, yTop + 20, 10, 10);
public static int WIDTH = 60; public static int HEIGHT = 30;
private int xLeft; private int yTop;
}
1. Here, in order to draw the second car at the bottom left hand corner of the JComponent,
we need to nd out where that is. getWidth() and getHeight() allow us to ask the
JComponent its dimensions.
3. Ellipse2D.Double works just like Rectangle2D.Double, the rst two parameters of its
constructor give (x ; y ) of top-left corner, second two parameters give width and height.
4. Point2D.Double needs just position (x ; y ).
5. Line2D.Double's constructor take two Point2D.Double parameters, the beginning and end
points of the line.
6. Actually, there is another Line2D.Double constructor which takes four doubles, (x ; y ) of
line start and (x ; y ) of line end.
7.6 Colour
We have already said plenty about colour in Chapter 6. Refer back to section 6.3.5.
Any colour can be represented using three components: red, green, blue;
Java Graphics2D stores red, green, blue as three eight-bit bytes (we should not equate
eight-bits with byte, but nearly everybody does; the proper name is octet, but we'll use byte.
An eight-bit byte allows numbers in the range [0::255]; 0 means fully o, 255 means colour
fully on.
(r = 255; g = 0; b = 0) is bright red.
(r = 0; g = 255; b = 0) is bright green.
(r = 0; g = 0; b = 0) is black, i.e. no colours at all present; all are fully o.
(r = 255; g = 255; b = 255) is white, i.e. all colours are fully on.
7{11
There is a fourth attribute that you can specify, namely alpha; alpha is the opacity, or
opaqueness, of the colour. opacity is the opposite to transparency.
al pha = 255 means totally opaque; al pha = 0 means totally transparent.
// R G B
Color c = new Color(255, 0, 0); // pure red
The float constructor is sometimes more intuitive, 1:0 is fully on, 0:0 is fully o, 0:5 is
halfway. However, 1:0 will become 255 in the computer memory, 0:5 will become 128 etc.
The Color will always be store as a byte.
But you can also specify the opacity (transparency) of the colour. The opacity is called
alpha; so now we have Red, Green, Blue, Alpha values:
// R G B A
Color c = new Color(255, 0, 0, 255); // pure red, completely opaque
Figure 7.8 is shows some experiments with colour (Color); the paintComponent of the code is
shown Figure 7.9.
You will notice that the last (blue) ellipse is transparent | you can see what is behind it.
r g b a
newColor = new Color(0, 0, 255, 100);
If you change to
r g b a
newColor = new Color(0, 0, 255, 255);
you will have a completely opaque blue, and you will not see behind it.
Notice that you can use drawString to write text on the graphics.
7{12
Figure 7.8: Use of Color, including alpha.
7{13
public void paintComponent(Graphics gr){
Graphics2D g2 = (Graphics2D) gr;
int r = fillColor.getRed();
int g = fillColor.getGreen();
int b = fillColor.getBlue();
int a = fillColor.getAlpha();
String s = "rgba = (" + r + ", "+ g + ", "+ b + ", "+ a+ ")";
g2.drawString(s, x, y-5);
g2.setColor(newColor);
g2.fill(sq2);
r = newColor.getRed(); g = newColor.getGreen();
b = newColor.getBlue(); a = newColor.getAlpha();
s = "rgba = (" + r + ", "+ g + ", "+ b + ", "+ a+ ")";
g2.drawString(s, x, y -5);
y = y + 30; // again
newColor = new Color(0, 0, 255, 100);
g2.setColor(newColor);
Ellipse2D.Double e = new Ellipse2D.Double(x, y, xLen+20, yLen);
g2.fill(e);
r = newColor.getRed(); g = newColor.getGreen();
b = newColor.getBlue(); a = newColor.getAlpha();
s = "rgba = (" + r + ", "+ g + ", "+ b + ", "+ a+ ")";
y = y + yTrans; // keeping track of y
g2.drawString(s, x, y -5);
}
7{14
Chapter 8
More 2D Graphics
8.1 Introduction
Following the introduction in Chapter 7, we introduce a framework which has labelled axes and in
which the y-axis points up. We then show some graphics developed in that framework. In the next
chapter, Chapter 9 we do aome programming involving vectors and vector transformations using
the same framework.
Flipping the y-axis We
ip the y-axis so that it points up using the AffineTransform class. As
well as
ipping the y-axis, we also want the origin to be in the middle of the frame.
First, we create an AffineTransform, then we add a translate (move) to that to get us to the
proper origin.
Then we apply a scale of 1 to the y-axis | this does the
ipping.
Finally, we apply the transformation to the graphics context.
Here is the code:
8{1
We note that me must un
ip any time we want to draw text, otherwise the text will be upside
down.
All this is a little bit messy, but once we have the framework created, you need not worry about it
and from then on you can think of the y-axis pointing up. Also, the beginning points for Rectangles
and Ellipses is no longer the top-left, but is now the bottom-right.
8{2
import java.awt.*; import java.awt.geom.*; import javax.swing.*;
frame.setSize(FRAME_WIDTH, FRAME_HEIGHT);
frame.setTitle(getClass().getName());
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
Container cp = frame.getContentPane();
cp.setBackground(Color.white);
frame.add(component);
frame.setVisible(true);
}
public static void main(String args[]){
new Framework2D();
}
}
/**
A component that draws axes and content.
*/
class AxesCompt extends JComponent{
private Axes axes;
8{3
class Axes{
private int xLo; private int xHi;
private int yLo; private int yHi;
private int x0; private int y0;
private int winHeight;
public Axes(int xl, int xh, int yl, int yh, int xx0, int yy0, int wh){
xLo= xl; xHi= xh; yLo= yl; yHi= yh;
x0= xx0; y0= yy0;
winHeight = wh;
}
8{4
int lineStep = 10, arrowLen= 6;
Color cDark = lightenColor(c, 60);
Color cMid = lightenColor(cDark, 60);
Color cLight = lightenColor(cMid, 60);
8{6
public class Rects2D{
public Rects2D(){
// same as FrameWork2D
frame.add(component);
frame.setVisible(true);
}
public static void main(String args[]){
new Rects2D();
}
}
/**
A component that draws axes and content.
*/
class AxesCompt extends JComponent{
private Axes axes;
Rectangle2D.Double r1 =
new Rectangle2D.Double(-250, -200, 100, 150);
g2.setPaint(Color.red);
g2.fill(r1);
Rectangle2D.Double r2 =
new Rectangle2D.Double(-250, 200, 100, 150);
g2.setPaint(Color.green);
g2.fill(r2);
Rectangle2D.Double r3 =
new Rectangle2D.Double(250, 200, 100, 150);
g2.setPaint(Color.blue);
g2.fill(r3);
Rectangle2D.Double r4 =
new Rectangle2D.Double(250, -200, 100, 150);
g2.setPaint(Color.orange);
g2.fill(r4);
}
}
8{7
Figure 8.7 shows an amended version of the Car program that we saw in Chapter 7. Figures 8.8
and 8.9 show the relevant parts of the code.
8{8
/**
A car shape that can be positioned anywhere on the screen.
*/
public class Car{
/**
Constructs a car with a given top left corner
@param x the x coordinate of the bottom left corner
@param y the y coordinate of the bottom left corner
@param h full height
@param w full width
*/
public Car(double x, double y, double w, double h){
x0 = x;
y0 = y;
width = w;
height = h;
}
/**
Draws the car.
@param g2 the graphics context
*/
public void draw(Graphics2D g2){
//System.out.println("Car.draw");
double wheelRadius = height/5.0;
double xFront = x0 + width;
double yBodyBase = y0 + height/5.0;
double hBody = height*2.0/5.0;
double hRoof = height*2.0/5.0;
Point2D.Double centreRearWheel =
new Point2D.Double(x0 + 2.0*wheelRadius, yBodyBase);
Ellipse2D rearWheel =
createCircle(centreRearWheel, wheelRadius);
g2.setPaint(Color.darkGray);
g2.fill(rearWheel);
Point2D.Double centreFrontWheel =
new Point2D.Double(xFront - 2.0*wheelRadius, yBodyBase);
Ellipse2D frontWheel =
createCircle(centreFrontWheel, wheelRadius);
g2.fill(frontWheel);
8{9
Rectangle.Double body =
new Rectangle.Double(x0, yBodyBase, width, hBody);
g2.setPaint(Color.red); g2.fill(body);
Line2D.Double frontWindshield
= new Line2D.Double(p1, p2);
Line2D.Double roofTop
= new Line2D.Double(p2, p4);
Line2D.Double rearWindshield
= new Line2D.Double(p4, p3);
g2.draw(frontWindshield);
g2.draw(roofTop);
g2.draw(rearWindshield);
}
8{10
8.4 Shape and General Path
The way we drew the roof of the car above is alright as long as we only want to draw the outline
of the roof. What if we want to ll the area above the body, with, say, a tinted glass colour?
That is where Shape and GeneralPath come in. You can creat a path of line drawing and the ll
it.
Figure 8.10 shows an amended version of the above Car program that; unfortunately, moveTo and
lineTo take float arguments, so me had to change some doubles to floats.
Figures 8.11 shows the relevant parts of the code.
8{11
// same as above
8{12
8.5 Drawing Images
In our tile game, we will have to draw images of the tiles and of sprites.
Figure 8.12 displays all the tiles and sprites from Chapter 5 of Brackeen's book.
Figure 8.13 shows how we load the tiles images into an ArrayList<Image> tiles and compute
the position of the tile and place it in an ArrayList<Point2D> pts.
Figure 8.14 shows how we display the list of tiles at their relevant positions.
8{13
/**
A component that draws axes and displays tiles
*/
class TileCompt extends JComponent{
private Axes axes;
private ArrayList<Image> tiles;
private ArrayList<Point2D> pts;
String[] files = {
"tile_A.png", "tile_B.png", "tile_C.png", "tile_D.png",
"tile_E.png", "tile_F.png", "tile_G.png", "tile_H.png",
"tile_I.png",
"star1.png", "star2.png", "star3.png", "star4.png",
"powerup1.png", "powerup2.png", "powerup3.png", "powerup4.png",
"player1.png", "player2.png", "player3.png",
"music1.png", "music2.png", "music3.png",
"heart1.png", "heart2.png", "heart3.png",
"fly1.png", "fly2.png", "fly3.png",
"grub1.png", "grub2.png"};
8{14
public void paintComponent(Graphics g){
Graphics2D g2 = (Graphics2D) g;
axes.draw(Color.darkGray, g2);
Point2D pt;
int x, y;
AffineTransform at = new AffineTransform();
at.scale(1.0, -1.0);
g2.transform(at);
for(int i = 0; i< tiles.size(); ++i){
Image im = tiles.get(i);
pt= pts.get(i);
x= (int)pt.getX();
y= (int)pt.getY();
System.out.println("x, y = " + x +", "+ y);
g2.drawImage(im, x, y, null);
Rectangle rect = new Rectangle(x, y, 2, 2);
g2.setPaint(Color.black);
g2.draw(rect);
}
g2.transform(at);
}
}
8{15
Chapter 9
9.1 Introduction
Following the introductions in Chapters 7 and 8 we now explore the role of vectors vector trans-
formations in computer graphics. All this is covered in more detail in (Campbell 2007b), but here
we look at it from a programming point of view.
We rst examine the programming of vectors vector transformations using our own Vector2D and
Transform2D software. Then, we introduce Java's AffineTransform class.
One aspect of vectors and points that we attempt to highlight in this section is that points and
vectors are dierent entities; what can be confusing is that they are similar enough for there to be
situations where they can be used interchangeably. That makes it all the more confusing when we
arrive at situations where their dierence is important.
As we indicate in Chapter 5.4 of our Maths. notes (Campbell 2007b), in the context of computer
graphics, the distinctions are as follows.
9{1
Points and Vectors
A point is a position;
A vector is a displacement (description of a movement from one position to another);
The latter is the same as saying that a vector has magnitude and direction;
If we are working in a Cartesian (rectangular) coordinate system, the origin (O) is a point;
The potential interchangeability of points and vectors comes from the fact that a general
point (P ) at (x ; y ) may be thought of as a displacement from O, i.e. we add a vector
v = (x ; y ) to O = (0; 0) and get a new point P = (x ; y );
You can add a vector to a point to get a new point; that is, move from the rst point to
the new point;
We note also that vectors have no position, but when we want to display a vector, we need to
position it somewhere; if we draw the vector as an arrow on a rectangular coordinate system,
we sometimes place its start (tail) at the origin O;
When we rotate a vector, all that changes is its direction | its angle;
Quite often, it is useful to represent a vector not as v = (x ; y ), but as magnitude (also called
length), for which we use kvk and angle, in mathematics, called its argument arg v;
The latter representation is p
called polar: v = (r; ), where r = kvk and = arg v, see
Figure 9.1. Note that kvk = x 2 + y 2 .
9{2
9.2 Vector Addition
Figure 9.2 shows a graphical demonstration of vector addition. Figure 9.3 shows the relevant part
of the code.
9{3
private class AxesCompt extends JComponent{
private Axes axes;
9{4
Figure 9.4: Graphical display of vector rotation.
9{5
public void paintComponent(Graphics g){
Graphics2D g2 = (Graphics2D) g;
axes.draw(Color.darkGray, g2);
9{6
When we print the transform and the polar version of the rotated vector, we get get following:
v = [200.0, 30.0]
v = [200.0, 60.0]
v = [200.0, 90.0]
v = [200.0, 120.0]
v = [200.0, 150.0]
v = [200.0, 180.0]
v = [200.0, 210.0]
v = [200.0, 240.0]
v = [200.0, 270.0]
v = [200.0, 300.0]
v = [200.0, 330.0]
v = [200.0, 0.0]
v = [200.0, 30.0]
Notice that the length (magnitude) of the vector does not change, only its angle. Notice also that
when we rotate the vector by 30 twelve (12) times, we arrive back at the original. Why?.
Ex. Explain the contents of the matrix in the transform t . What are 0:866, 0:500, 0:500?
vx
vx
!
vy
vy : (9.1)
vw
vx a11 a12 tx ux
vy = a21 a22 ty uy : (9.2)
vw 0 0 1 uw
Since the bottom row of the ane transformation matrix is always (0 0 1), we do not bother to
print it.
9{7
9.4 Rotating Shapes
Figure 9.6 shows a graphical demonstration of rotation of a house shape. Figure 9.8 shows the
relevant part of the code and Figure 9.9 shows the code that creates the key points that make up
the house. To meke it clearer, Figure 9.7 shows the house without the vectors.
I hope that displaying the points as vectors will help you see why rotation has the eect it has; the
vector displacements from the origin are rotated, this means that all rotation is wit respect to the
origin | the house does not rotate about its centre or any other part of itself.
If you want the house to rotate about some other point, you have to translate (move) the house
to that point, rotate, and then translate back. However, there mathematics allows us to do all
three in one operation, see (Campbell 2007b) and we will do a programming exercise on this.
9{8
Figure 9.7: Rotation of a house shape.
9{9
public void paintComponent(Graphics g){
Graphics2D g2 = (Graphics2D) g;
g2.setBackground(Color.white);
axes.draw(Color.darkGray, g2);
double x0 = 50.0, y0 = 50.0, width = 200.0,
wallHt = 100.0, roofHt= 200.0;
VectorHouse aHouse =
new VectorHouse(x0, y0, width, wallHt, roofHt);
aHouse.drawAsPoints(g2, Color.green);
aHouse.drawAsLines(g2, Color.red);
aHouse.drawAsVectors(g2, Color.darkGray);
aHouse.rotate(Math.toRadians(60.0));
aHouse.drawAsPoints(g2, Color.green);
aHouse.drawAsLines(g2, Color.black);
aHouse.drawAsVectors(g2, Color.darkGray);
aHouse.rotate(Math.toRadians(90.0));
aHouse.drawAsPoints(g2, Color.green);
aHouse.drawAsLines(g2, Color.black);
aHouse.drawAsVectors(g2, Color.darkGray);
aHouse.rotate(Math.toRadians(120.0));
aHouse.drawAsPoints(g2, Color.green);
aHouse.drawAsLines(g2, Color.black);
aHouse.drawAsVectors(g2, Color.darkGray);
}
9{10
public VectorHouse(double x0, double y0, double width,
double wallHt, double roofHt) {
v0 = new Vector2D(x0, y0);
vecs = new ArrayList<Vector2D>();
// door
vecs.add(new Vector2D(width/2.0, 0.0));
vecs.add(new Vector2D(width/2.0, wallHt/2.0));
vecs.add(new Vector2D(width*3.0/4.0, wallHt/2.0));
vecs.add(new Vector2D(width*3.0/4.0, 0.0));
9{12
9.6 Transformation using java.awt.AneTransform
Figure 9.11 shows the results of rotating the house shape using java.awt.AffineTransform.
The relevant part of the code is shown in Figure 9.12.
//A
9{13
public void paintComponent(Graphics g){
Graphics2D g2 = (Graphics2D) g;
g2.setBackground(Color.white);
axes.draw(Color.darkGray, g2);
double x0 = 50.0, y0 = 50.0, width = 200.0,
wallHt = 100.0, roofHt= 200.0;
VectorHouse aHouse =
new VectorHouse(x0, y0, width, wallHt, roofHt);
aHouse.drawAsLines(g2, Color.red);
at = new AffineTransform();
at.rotate(Math.toRadians(90.0)); //B1
g2.transform(at);
System.out.println(at); //B2
aHouse.drawAsLines(g2, Color.magenta);
at = new AffineTransform();
at.rotate(Math.toRadians(120.0)); //C1
g2.transform(at);
System.out.println(at); //C2
aHouse.drawAsLines(g2, Color.black);
}
9{14
AffineTransform[[0.5, -0.866025403784439, 0.0],
[0.866025403784439, 0.5, 0.0]]
//B
AffineTransform[[0.0, -1.0, 0.0],
[1.0, -0.0, 0.0]]
//C
AffineTransform[[-0.5, -0.866025403784439, 0.0],
[0.866025403784439, -0.5, 0.0]]
9{15
Chapter 10
Programming Audio
10.1 Introduction
The purpose of this chapter is to give a brief introduction to the part of the Java Sound API that
matter to us | and I'm glad to say that it is a very small part.
There is a fairly decent guide to the Java Sound API at:
http://java.sun.com/j2se/1.5.0/docs/guide/sound/programmer_guide/.
It says that it was last updated in 2001, but that must be wrong, since it refers to Java 5.0 (aka
Java 1.5) which was released only in 2005.
Also, chapter 4 of Brackeen gives an adequate introduction.
I know there are people in the class with a special interest in audio. The following books make be
of interest, but are in no way necessary for this course.
Ken C. Pohlmann, Principles of Digital Audio, McGraw-Hill, 4th ed., 2000. Large and expensive
(60 Euro) (Pohlmann 2000).
Bruce Fries, Digital Audio Essentials: A Comprehensive Guide to Creating, Recording, Editing, and
Sharing Music and Other Audio, O'Reilly, 2005. Lighter and less expensive (30 Euro) (Fries 2005).
First, we give an introduction to the physics of sound and how sound gets in and out of computers.
10{1
Figure 10.1: Audio data on a computer.
10.2.1 Sound
Sound is produced by air vibrating; by that we mean rapid changes in air pressure. If you go to a
really loud disco, you will be able to feel the loudspeakers pushing the air at you.
When the string of a guitar is plucked, or the string of a violin bowed, the string vibrates. That,
in turn, causes the air to vibrate. Those vibrations, just like the waves when you drop a stone in
a lake, travel outwards. Eventually, if you are nearby, the vibrations reach your eardrum and cause
the sensation of sound.
If the vibrations are very slow, slower than about 20 vibrations per second, the eardrum will not
receive any sensation { but, like in the disco, you may feel you body being shaken by them.
Likewise, if the vibrations are faster than about 16,000 times per second, you will not hear them
{ but dogs and other animals will.
Human voices produce sound by vibrating the vocal chords. Wind instruments produce sound by
air vibrating in the instrument tube. The rate of vibration can be governed by the length of the
tube and this is done by lengthening and shortening the tube { as in a trombone, or by pressing
your ngers over holes in the tube { as in a
ute or whistle.
10.2.2 Loudspeakers
Loudspeakers (or headphones) are electrically controlled sources of vibration or pressure. If you
pass a voltage wave (vibrating voltage) to a loudspeaker, the core of the loudspeaker vibrates in
sympathy with the voltage. When the loudspeaker core pushes out, you get positive pressure { the
air is pushed at you; when the core moves back, you get negative pressure { the air is sucked away
from you.
10.2.3 Microphones
Microphones are like loudspeakers in reverse; in fact, you can use loudspeakers or headphones as
microphones. When the air near a microphone vibrates (i.e. there is sound), the microphone
produces a voltage at its electrical outputs.
Therefore, we can convert from sound to electricity (voltage) using a microphone. And we can
convert from electricity to sound using a microphone.
10{2
10.2.4 Analogue versus Digital
Radios, TVs and cassette tape recorders handle sound as electricity (voltage and current); this is
called analogue { the voltage is analogous to the sound. If you drew a graph of the intensity of
the air pressure that causes the sound, and another graph of the intensity of the electrical voltage,
the two graphs would be the same shape.
Computers use numbers (digits { digital) instead of voltage. Thus, when we need to get sound
into a computer, we have to convert the pressure (sound, vibrations) into numbers.
When you want to get sound into a computer, rst you convert the sound to electrical voltage
using a microphone. Next, read the voltage at rapid intervals (about 44,100 times per second for
Compact Disc (CD)) and convert the reading into a number. This conversion into numbers is
done by an electronic circuit called an Analogue-to-Digital Converter (ADC). Now, the sound can
be stored on a computer, and on its disk, and in its memory, and copied onto CD.
Eventually, when you want to hear the digital sounds again, we must convert from numbers back
to voltages, and then, using a loudspeaker, back to air pressure.
The conversion from numbers to voltage is done by an electronic circuit called a Digital-to-Analogue
Converter (DAC), see section 6.3.2. Most of a Sound Blaster card is taken up with its Digital-
to-Analogue Converter. A Sound Blaster also has Analogue-to-Digital Converter, to which you
connect a microphone or other input source.
10{3
10.2.7 Magnetic Recording
See Operating Systems, chapter on disks and le systems.
Lossy. Used for audio (e.g. MP3) and images, where the data are eventually going to be
converted into an analogue form to be listened to or viewed by a person. Here, loss of the
odd bit may not make any dierence.
Lossless. Used where the data are, and always will remain, digital; where each bit is crucial.
E.g. the ASCII string 74 68 65 20 63 61 74 20 73 63 61 20 6F 6E 20 74 68 65 20 6D 61
74 2E reads: "the cat sat on the mat".
If I decide to remove all the least-signicant bits (reasonable for lossy, but not here), I get:
74 68 64 20 62 60 74 20 72 62 60 20 6E 6E 20 74 68 64 20 6C 60 74 2E, which reads:
"thd b't rb' nn thd l't." Not much use!
10{4
Dierential coding. Let's say the following sequence of numbers appear in a digital recording
of a voice: 32,001 32,015, 32,020 32,010 32,005 . . . . As it is, we require 16 bits per number.
However, let's send the rst, and send only dierences for the remainder: 32,001 14 5 -10
-5. For the dierences, we can get away with ve bits. Can be lossless.
Recall that we started o at 176,400 bytes per second, that is 1.4 Mbits per second. MP3 com-
pression can compress music to 128-Kbits per second (around 10%) and still be quite acceptable.
javax.sound.sampled;
javax.sound.midi.
8 bits; signed -128 { +127; unsigned 0 { 255; telephony and low quality audio;
16 bits; signed -32768 { +32767; unsigned 0 { 65535; CD quality.
10{5
Figure 10.2: Sampled sound.
Compression If you examined a .wav le, you would be able to nd the numbers that represent
the sound; and if you made a graph of them with time on the horizontal axis, you would end up
with something that looks like Figure 10.2.
Compressed les like MP3s are dierent; if you looked at the data in an MP3 le they would look
like nothing on earth; that is until you pushed them through an MP3 decoder; after the decoder
the data look just the same as those in a .wav le. At least you hope they do!
DPCM (Dierential Pulse Code Modulation) can achieve modest compression rates.
PCM | Pulse Code Modulation I have no idea how the term PCM persists; it was introduced
at a time when digital data equaled pulses. In the audio context, PCM means raw encode numbers.
Mu-Law, A-Law etc. It is found that we can save bits by making the digitisation steps larger for
small values of sound. This is done by a scheme called companding { applied before the analogue-
to-digital converter (ADC); the opposite to companding is then done after the digital-to-analogue
converter (DAC). Mu-Law and A-Law are useful when trying to get the most out of the eight bit
samples used in telephony.
If you are interested, I can draw a diagram on this in class; but in general, don't worry about it.
10{6
Remember what we said in section 10.2 about electronic instruments | or synthesisers. A partic-
ular note might look (and sound) like Figure 10.2 (you'll get a chance to hear that in a practical),
so, when the instruction to play that note appears, the program or sound card can pump that data
out to the output port. The sound (from a soundbank, see below) might be recorded from a real
instrument.
As Brackeen (p. 212) says \... the Java Sound API synthesises MIDI music through the use of a
soundbank..."; he then mentions that the soundbank is available in the SDK (J2SDK), and not in
the runtime (J2RE); actually, he means the Windows runtime. In any case, we use the SDK, so we
are okay; by runtime, he means the Java interpreter that exists on non-development computers.
By soundbank, he means a collection of dierent lists of numbers like those shown in Figure 10.2.
Later Brackeen says that if no soundbank exists, the MIDI port on the sound card is used; he
appears to think that this option is inferior.
Finally, he points to higher quality soundbanks available at:
http://java.sun.com/products/java-media/sound/soundbanks.html.
Synthesiser The term synthesiser means that the sound is synthesised (made up). On the other
hand, sampled sound comes ready to push into the digital-to-analogue converter (DAC) on the
sound card.
Synthesis is the sound equivalent of rendering | of images or video.
import java.io.*;
import javax.sound.sampled.*;
/**
The SimpleSoundPlayer encapsulates a sound that can be opened
from the file system and later played.
*/
10{7
public class SimpleSoundPlayer {
public static void main(String[] args) {
// load a sound
SimpleSoundPlayer sound =
new SimpleSoundPlayer("../sounds/voice.wav");
// create the stream to play
InputStream stream =
new ByteArrayInputStream(sound.getSamples());
// play the sound
sound.play(stream);
// exit
System.exit(0);
}
private AudioFormat format;
private byte[] samples;
/**
Opens a sound from a file.
*/
public SimpleSoundPlayer(String filename) {
try {
// open the audio input stream
AudioInputStream stream =
AudioSystem.getAudioInputStream(new File(filename));
format = stream.getFormat();
System.out.println(format);
// get the audio samples
samples = getSamples(stream);
}
catch (UnsupportedAudioFileException ex) {
ex.printStackTrace();
}
catch (IOException ex) {
ex.printStackTrace();
}
}
/**
Gets the samples of this sound as a byte array.
*/
public byte[] getSamples() {
return samples;
}
/**
Gets the samples from an AudioInputStream as an array
of bytes.
*/
private byte[] getSamples(AudioInputStream audioStream) {
// get the number of bytes to read
int length = (int)(audioStream.getFrameLength() *
format.getFrameSize());
10{8
// read the entire stream
byte[] samples = new byte[length];
DataInputStream is = new DataInputStream(audioStream);
try {
is.readFully(samples);
}
catch (IOException ex) {
ex.printStackTrace();
}
// return the samples
return samples;
}
/**
Plays a stream. This method blocks (doesn't return) until
the sound is finished playing.
*/
public void play(InputStream source) {
10{9
ex.printStackTrace();
}
// wait until all data is played, then close the line
line.drain();
line.close();
}
}
Dissection
SimpleSoundPlayer sound =
new SimpleSoundPlayer("../sounds/voice.wav");
2. Get the sampled data from the SimpleSoundPlayer object sound and create a
ByteArrayInputStream with it; there is not a pile of dierence between using a
ByteArrayInputStream and just an array. ByteArrayInputStream behaves a bit like a
le | but you don't know about les, so that is not much use to you.
Byte? Does not mean that the data samples are 8-bits; could be 16-bit { two bytes per
sample.
InputStream stream =
new ByteArrayInputStream(sound.getSamples());
3. Use SimpleSoundPlayer.play() to read the data from the stream and push it out to the
sound card; play is described later.
sound.play(stream);
4. Data members.
The AudioFormat format object contains details like (below is a printout of one):
In PCM, a frame is a sample, but in a compressed format, frame and sample mey be quite
dierent.
An AudioInputStream stream knows all about formats and stream.getFormat(); gets
the format.
Why do we need the format? We need it when we want to open a Line out through which
we play the data; in other words we pass on details of the format to the sound card, so that
the card knows how to handle the data that we push at it.
10{10
5. Reading the samples from AudioInputStream audioStream
try, catch are to do with exceptions; let's say there was a le error (somebody disconnects
the hard disk, say), an exception (a special program signal) will be generated; the fact that
is.readFully(samples); is in a try section means that ex.printStackTrace(); will be
executed to tell the user that something bad happened, and some further explanation.
7. Play the sound (play). This is complicated by the fact that Brackeen sends the sound out
in 101 th of a second chunks.
8. We need to create a Line out through which we send the data | a bit like the line-out or
the headphone outputs in your hi- or MP3 player. First we create a DataLine.Info object
that we inform about the format (see above).
We then get (create) a SourceDataLine line; I nd the name odd, the SourceDataLine
is actually a Line that receives data for playing.
We open the SourceDataLine; oddly enough, we again specify the format.
SourceDataLine line;
try {
DataLine.Info info =
new DataLine.Info(SourceDataLine.class, format);
line = (SourceDataLine)AudioSystem.getLine(info);
line.open(format, bufferSize);
}
catch (LineUnavailableException ex) {
ex.printStackTrace();
return;
}
10{11
int numBytesRead = 0;
while (numBytesRead != -1) {
numBytesRead =
source.read(buffer, 0, buffer.length);
if (numBytesRead != -1) {
line.write(buffer, 0, numBytesRead);
}
}
That will have to do for an introduction, and I'm in a hurry to get these notes printed.
Other things that will need to be brie
y touched on are:
10{12
Chapter 11
11.1 Introduction
The purpose of this chapter is to pick through certain parts of Brackeen's chapter 5 (Brackeen
et al. 2004) and show how you can make some modications to, for example, the behaviour of
Player.
11{1
package com.brackeen.javagamebook.graphics;
import java.awt.Image;
/**
Gets this Sprite's width, based on the size of the
current image.
*/
public int getWidth() {
return anim.getImage().getWidth(null);
}
11{2
/**
Gets this Sprite's height, based on the size of the
current image.
*/
public int getHeight() {
return anim.getImage().getHeight(null);
}
/**
Gets the horizontal velocity of this Sprite in pixels
per millisecond.
*/
public float getVelocityX() {
return dx;
}
/**
Gets the vertical velocity of this Sprite in pixels
per millisecond.
*/
public float getVelocityY() {
return dy;
}
/**
Sets the horizontal velocity of this Sprite in pixels
per millisecond.
*/
public void setVelocityX(float dx) {
this.dx = dx;
}
/**
Sets the vertical velocity of this Sprite in pixels
per millisecond.
*/
public void setVelocityY(float dy) {
this.dy = dy;
}
/**
Gets this Sprite's current image.
*/
public Image getImage() {
return anim.getImage();
}
/**
Clones this Sprite. Does not clone position or velocity
info.
*/
public Object clone() {
return new Sprite(anim);
}
}
/**
Creates a duplicate of this animation. The list of frames
are shared between the two Animations, but each Animation
can be animated independently.
*/
public Object clone() {
return new Animation(frames, totalDuration);
}
/**
Adds an image to the animation with the specified
duration (time to display the image).
*/
public synchronized void addFrame(Image image,
long duration) {
totalDuration += duration;
frames.add(new AnimFrame(image, totalDuration));
}
/**
Starts this animation over from the beginning.
*/
public synchronized void start() {
animTime = 0;
currFrameIndex = 0;
} ... continued
/**
Gets this Animation's current image. Returns null if this
animation has no images.
*/
public synchronized Image getImage() {
if (frames.size() == 0) {
return null;
}
else {
return getFrame(currFrameIndex).image;
}
}
Image image;
long endTime;
/**
Amount of time to go from STATE_DYING to STATE_DEAD.
*/
private static final int DIE_TIME = 1000;
/**
Creates a new Creature with the specified Animations.
*/
public Creature(Animation left, Animation right,
Animation deadLeft, Animation deadRight) {
super(right);
this.left = left;
this.right = right;
this.deadLeft = deadLeft;
this.deadRight = deadRight;
state = STATE_NORMAL;
}
/**
Gets the maximum speed of this Creature.
*/
public float getMaxSpeed() {
return 0;
}
/**
Wakes up the creature when the Creature first appears
on screen. Normally, the creature starts moving left.
*/
public void wakeUp() {
if (getState() == STATE_NORMAL && getVelocityX() == 0) {
setVelocityX(-getMaxSpeed());
}
} ... continued
11{6
Figure 11.6: Creature.java, part 1.
/** ... continued
Gets the state of this Creature. The state is either
STATE_NORMAL, STATE_DYING, or STATE_DEAD.
*/
public int getState() {
return state;
}
/**
Sets the state of this Creature to STATE_NORMAL,
STATE_DYING, or STATE_DEAD.
*/
public void setState(int state) {
if (this.state != state) {
this.state = state;
stateTime = 0;
if (state == STATE_DYING) {
setVelocityX(0);
setVelocityY(0);
}
}
}
/**
Checks if this creature is alive.
*/
public boolean isAlive() {
return (state == STATE_NORMAL);
}
/**
Checks if this creature is flying.
*/
public boolean isFlying() {
return false;
}
/**
Called before update() if the creature collided with a
tile horizontally.
*/
public void collideHorizontal() {
setVelocityX(-getVelocityX());
}
/**
Called before update() if the creature collided with a
tile vertically.
*/
public void collideVertical() {
setVelocityY(0);
} ... continued
11{7
Figure 11.7: Creature.java, part 2.
/** ... continued
Updates the animation for this creature.
*/
public void update(long elapsedTime) {
// select the correct Animation
Animation newAnim = anim;
if (getVelocityX() < 0) {
newAnim = left;
}
else if (getVelocityX() > 0) {
newAnim = right;
}
if (state == STATE_DYING && newAnim == left) {
newAnim = deadLeft;
}
else if (state == STATE_DYING && newAnim == right) {
newAnim = deadRight;
}
11{8
public class Player extends Creature {
private static final float JUMP_SPEED = -0.95f;
private boolean onGround;
private float jumpSpeed; // added
/**
Makes the player jump if the player is on the ground or
if forceJump is true.*/
public void jump(boolean forceJump) {
if (onGround || forceJump) {
onGround = false;
setVelocityY(jumpSpeed);
}
}
11{9
Figure 11.9: Player.java.
private int health;
11{10
/**
Checks for Player collision with other Sprites. If
canKill is true, collisions with Creatures will kill
them.
*/
public void checkPlayerCollision(Player player,
boolean canKill)
{
if (!player.isAlive()) {
return;
}
}
else {
player.addHealth(-2);
displayHealth(player);
if(player.getHealth()<0){
player.setState(Creature.STATE_DYING);
}
}
}
}
Figure 11.11: Code added to GameManager.java for Adding or Losing Health after Collisions.
11{11
// draw the visible tiles
int firstTileX = pixelsToTiles(-offsetX);
int lastTileX = firstTileX +
pixelsToTiles(screenWidth) + 1;
for (int y=0; y<map.getHeight(); y++) {
for (int x=firstTileX; x <= lastTileX; x++) {
Image image = map.getTile(x, y);
if (image != null) {
g.drawImage(image,
tilesToPixels(x) + offsetX,
tilesToPixels(y) + offsetY, null);
}
}
}
g.drawImage(player.getImage(),
Math.round(player.getX()) + offsetX,
Math.round(player.getY()) + offsetY,
null);
int h= player.getHealth();
if(h>0){
String s= "h= "+h;
g.drawString(s, px, py);
System.out.println("h= "+h);
}
//**************************************
// draw sprites
Iterator i = map.getSprites();
while (i.hasNext()) {
Sprite sprite = (Sprite)i.next();
int x = Math.round(sprite.getX()) + offsetX;
int y = Math.round(sprite.getY()) + offsetY;
g.drawImage(sprite.getImage(), x, y, null);
// wake up the creature when it's on screen
if (sprite instanceof Creature &&
x >= 0 && x < screenWidth)
{
((Creature)sprite).wakeUp();
}
}
}
}
11{12
Figure 11.12: Health display code added to TileMapRenderer.java
# Map file for tile-based game
# (Lines that start with '#' are comments)
# The tiles are:
# (Space) Empty tile
# A..Z Tiles A through Z
# o Star
# ! Music Note
# * Goal
# 1 Bad Guy 1 (grub)
# 2 Bad Guy 2 (fly)
o o
o o o
o o o o o o o o o
IIIIIII IIIIIII o o 2
o 2
2 2EF
EF EGD
EF 1 CD 1 1 EGAD *
BBBBBBBBGHBBBBBBBGHBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBGAAHBBBBBBBBBBB
11{13
private TileMap loadMap(String filename)
throws IOException
{
ArrayList lines = new ArrayList();
int width = 0;
int height = 0;
11{14
// check if the char represents a sprite
else if (ch == 'o') {
addSprite(newMap, coinSprite, x, y);
}
else if (ch == '!') {
addSprite(newMap, musicSprite, x, y);
}
else if (ch == '*') {
addSprite(newMap, goalSprite, x, y);
}
else if (ch == '1') {
addSprite(newMap, grubSprite, x, y);
}
else if (ch == '2') {
addSprite(newMap, flySprite, x, y);
}
}
}
// add the player to the map
Sprite player = (Sprite)playerSprite.clone();
player.setX(TileMapRenderer.tilesToPixels(3));
player.setY(0);
newMap.setPlayer(player);
return newMap;
}
private void addSprite(TileMap map,
Sprite hostSprite, int tileX, int tileY) {
if (hostSprite != null) {
// clone the sprite from the "host"
Sprite sprite = (Sprite)hostSprite.clone();
11{15