gats · pdf fileintroduction section 1 ©1991 – 2016 garth santor & trinh hān...
TRANSCRIPT
GATS Encyclopaedia
Garth Santor & Trinh Hān © 1991 – 2016
Introduction Section 1
©1991 – 2016 Garth Santor & Trinh Hān GATS Encyclopaedia 2 of 278
Introduction
Contents
Introduction ................................................................................................................................................................................................. 2
AI .............................................................................................................................................................................................................. 12 Neural Networks ................................................................................................................................................................................... 12
Algorithms ................................................................................................................................................................................................ 13
Algorithm vs. Formula .......................................................................................................................................................................... 13 Algorithm vs. Heuristic ......................................................................................................................................................................... 14
Analysis of Algorithms ......................................................................................................................................................................... 14 Counting ................................................................................................................................................................................................ 16 Numerical .............................................................................................................................................................................................. 16 Printing .................................................................................................................................................................................................. 20 Searching............................................................................................................................................................................................... 21 Sorting ................................................................................................................................................................................................... 23
Applications .............................................................................................................................................................................................. 42 UML Tools............................................................................................................................................................................................ 42
Audio Programming.................................................................................................................................................................................. 43 Compact Disc ........................................................................................................................................................................................ 43
Audio Engines ....................................................................................................................................................................................... 43 Music..................................................................................................................................................................................................... 48
C++ Programming .................................................................................................................................................................................... 50 Assertions .............................................................................................................................................................................................. 50 Best Practices ........................................................................................................................................................................................ 51
Bit Manipulation ................................................................................................................................................................................... 68 Boost ..................................................................................................................................................................................................... 70
Classes................................................................................................................................................................................................... 77 Coding Devices and Idioms .................................................................................................................................................................. 79 Dangerous Coding Practices ................................................................................................................................................................. 90
Memory Management ........................................................................................................................................................................... 91 Preprocessor .......................................................................................................................................................................................... 95
STL ....................................................................................................................................................................................................... 97 Templates .............................................................................................................................................................................................. 97
Database .................................................................................................................................................................................................... 99 Data Normalization ............................................................................................................................................................................... 99
Data Structures ........................................................................................................................................................................................ 106
Introduction Section 1
©1991 – 2016 Garth Santor & Trinh Hān GATS Encyclopaedia 3 of 278
Set ....................................................................................................................................................................................................... 106 Design Patterns ....................................................................................................................................................................................... 111
Implementation Patterns ..................................................................................................................................................................... 112 Game Programming ................................................................................................................................................................................ 115
Game Architecture .............................................................................................................................................................................. 115
Input .................................................................................................................................................................................................... 123 Logic / AI ............................................................................................................................................................................................ 123
Networking ......................................................................................................................................................................................... 124 Graphics .................................................................................................................................................................................................. 130
Concepts .............................................................................................................................................................................................. 130
Direct3D 9.0 Programming ................................................................................................................................................................. 137 Direct3D 10.0 Programming ............................................................................................................................................................... 153
File Formats ........................................................................................................................................................................................ 155 Hardware ............................................................................................................................................................................................. 183 Terrain ................................................................................................................................................................................................. 186
History..................................................................................................................................................................................................... 192 Mathematics ............................................................................................................................................................................................ 195
General ................................................................................................................................................................................................ 195 Algebra ................................................................................................................................................................................................ 198 2D/3D Algebra .................................................................................................................................................................................... 200
Calculus............................................................................................................................................................................................... 208
Geometry............................................................................................................................................................................................. 209 Graphs ................................................................................................................................................................................................. 225
Logic & Boolean Algebra ................................................................................................................................................................... 233 Number Systems ................................................................................................................................................................................. 238 Statistics .............................................................................................................................................................................................. 238 Trigonometry ...................................................................................................................................................................................... 241
Operating Systems .................................................................................................................................................................................. 244
Windows Vista .................................................................................................................................................................................... 244 Physics .................................................................................................................................................................................................... 245
General ................................................................................................................................................................................................ 245
Game ................................................................................................................................................................................................... 251 Metric .................................................................................................................................................................................................. 252
Programming Concepts ........................................................................................................................................................................... 254 Concurrent Programming.................................................................................................................................................................... 254 Development Process .......................................................................................................................................................................... 256 Errors................................................................................................................................................................................................... 258 Exception Handling ............................................................................................................................................................................ 262
Introduction Section 1
©1991 – 2016 Garth Santor & Trinh Hān GATS Encyclopaedia 4 of 278
Generic Programming ......................................................................................................................................................................... 265 Object-Oriented Programming............................................................................................................................................................ 267
Testing & Reliability........................................................................................................................................................................... 269 Appendices .............................................................................................................................................................................................. 276
Introduction Section 1
©1991 – 2016 Garth Santor & Trinh Hān GATS Encyclopaedia 5 of 278
Detailed Contents Introduction ................................................................................................................................................................................................. 2 AI .............................................................................................................................................................................................................. 12
Neural Networks ................................................................................................................................................................................... 12
Back Propagation Learning............................................................................................................................................................... 12 Algorithms ................................................................................................................................................................................................ 13
Pseudo-code Style ............................................................................................................................................................................. 13 Algorithm vs. Formula .......................................................................................................................................................................... 13
Algorithm vs. Heuristic ......................................................................................................................................................................... 14 Analysis of Algorithms ......................................................................................................................................................................... 14
Asymptotic Analysis ......................................................................................................................................................................... 14
Big-Oh Notation (theta & omega) .................................................................................................................................................... 15 Ram Model of Computation ............................................................................................................................................................. 15
Counting ................................................................................................................................................................................................ 16 Digits ................................................................................................................................................................................................. 16
Numerical .............................................................................................................................................................................................. 16
Greatest Common Divisor ................................................................................................................................................................ 16 Highest Common Factor ................................................................................................................................................................... 16
Multiplication – Russian Peasant Algorithm .................................................................................................................................... 17 Sieve of Eratosthenes ........................................................................................................................................................................ 17
Printing .................................................................................................................................................................................................. 20
Natural Numbers ............................................................................................................................................................................... 20 Searching............................................................................................................................................................................................... 21
Binary ................................................................................................................................................................................................ 21
Linear ................................................................................................................................................................................................ 22 Remove from Sequence .................................................................................................................................................................... 22 Splay Trees........................................................................................................................................................................................ 23
Sorting ................................................................................................................................................................................................... 23
Introduction ....................................................................................................................................................................................... 23
Bogo Sort .......................................................................................................................................................................................... 25
Cocktail-shaker ................................................................................................................................................................................. 27
Comb Sort ......................................................................................................................................................................................... 29 Count Sort ......................................................................................................................................................................................... 30 Heap Sort .......................................................................................................................................................................................... 30 Insertion Sort ..................................................................................................................................................................................... 32 Merge Sort ........................................................................................................................................................................................ 33 Ordersort ........................................................................................................................................................................................... 36
Introduction Section 1
©1991 – 2016 Garth Santor & Trinh Hān GATS Encyclopaedia 6 of 278
Permutation Sort ............................................................................................................................................................................... 37 Pigeonhole Sort ................................................................................................................................................................................. 37
Quick sort .......................................................................................................................................................................................... 37 Selection Sort .................................................................................................................................................................................... 39
Shell’s Sort ........................................................................................................................................................................................ 41
Applications .............................................................................................................................................................................................. 42 UML Tools............................................................................................................................................................................................ 42
Argo UML ........................................................................................................................................................................................ 42 Audio Programming.................................................................................................................................................................................. 43
Storage Requirements ....................................................................................................................................................................... 43
Compact Disc ........................................................................................................................................................................................ 43 Sampling Rate ................................................................................................................................................................................... 43
Audio Engines ....................................................................................................................................................................................... 43 FMOD 4+ .......................................................................................................................................................................................... 44 FMOD 3.74 ....................................................................................................................................................................................... 46
Music..................................................................................................................................................................................................... 48 Sound Frequencies ............................................................................................................................................................................ 48
C++ Programming .................................................................................................................................................................................... 50 Assertions .............................................................................................................................................................................................. 50
Run-time Assertions.......................................................................................................................................................................... 50
Compile-time Assertions .................................................................................................................................................................. 50
Best Practices ........................................................................................................................................................................................ 51 BOOST ............................................................................................................................................................................................. 51
Coding Style...................................................................................................................................................................................... 55 Compiler / Environment ................................................................................................................................................................... 56 Design ............................................................................................................................................................................................... 56 Functions and Operators ................................................................................................................................................................... 57
Class Design and Inheritance ............................................................................................................................................................ 58
Construction, Destruction and Copying ............................................................................................................................................ 61 Namespaces and Modules ................................................................................................................................................................. 62 Templates and Genericity ................................................................................................................................................................. 62
Error Handling and Exceptions ......................................................................................................................................................... 63 STL Containers ................................................................................................................................................................................. 65 STL Algorithms ................................................................................................................................................................................ 66 Type Safety ....................................................................................................................................................................................... 67 OpenMP ............................................................................................................................................................................................ 68 String Manipulation .......................................................................................................................................................................... 68
Bit Manipulation ................................................................................................................................................................................... 68
Introduction Section 1
©1991 – 2016 Garth Santor & Trinh Hān GATS Encyclopaedia 7 of 278
Boost ..................................................................................................................................................................................................... 70 Classes................................................................................................................................................................................................... 77
Access Specifiers .............................................................................................................................................................................. 77 Slurping and Binding ........................................................................................................................................................................ 78
Coding Devices and Idioms .................................................................................................................................................................. 79
I/O Stream Pattern............................................................................................................................................................................. 79 Curiously Recurring Template Pattern (CRTP) ................................................................................................................................ 82
Delegates ........................................................................................................................................................................................... 82 Duff’s Device .................................................................................................................................................................................... 87 Functors............................................................................................................................................................................................. 88
Transactional Programming .............................................................................................................................................................. 89 Dangerous Coding Practices ................................................................................................................................................................. 90
operator T* ........................................................................................................................................................................................ 90 Raw Pointers ..................................................................................................................................................................................... 90
Memory Management ........................................................................................................................................................................... 91
Memory Layout ................................................................................................................................................................................ 91 Memory Leaks .................................................................................................................................................................................. 91
Microsoft’s CRTDBG Library .......................................................................................................................................................... 94 Preprocessor .......................................................................................................................................................................................... 95
Macros............................................................................................................................................................................................... 95
STL ....................................................................................................................................................................................................... 97
Which container do I use? ................................................................................................................................................................. 97 Templates .............................................................................................................................................................................................. 97
Template Programming Techniques ................................................................................................................................................. 97 Database .................................................................................................................................................................................................... 99
Data Normalization ............................................................................................................................................................................... 99 First Normal Form (1NF).................................................................................................................................................................. 99
Second Normal Form (2NF) ........................................................................................................................................................... 101
Third Normal Form (3NF) .............................................................................................................................................................. 103 Forth Normal Form (4NF) .............................................................................................................................................................. 104
Data Structures ........................................................................................................................................................................................ 106
Set ....................................................................................................................................................................................................... 106 Design Patterns ....................................................................................................................................................................................... 111
Bridge .............................................................................................................................................................................................. 111 Delegate .......................................................................................................................................................................................... 111
Implementation Patterns ..................................................................................................................................................................... 112 Double Check Locking Pattern (DCLP) ......................................................................................................................................... 112 Producer-Consumer ........................................................................................................................................................................ 112
Introduction Section 1
©1991 – 2016 Garth Santor & Trinh Hān GATS Encyclopaedia 8 of 278
Game Programming ................................................................................................................................................................................ 115 Game Architecture .............................................................................................................................................................................. 115
Direct3D and the Win32 Message Pump ........................................................................................................................................ 115 Game Loops .................................................................................................................................................................................... 120
Input .................................................................................................................................................................................................... 123
Thumbing Styles ............................................................................................................................................................................. 123 Logic / AI ............................................................................................................................................................................................ 123
Feedback Loops .............................................................................................................................................................................. 123 Networking ......................................................................................................................................................................................... 124
DirectPlay ....................................................................................................................................................................................... 124
Networking Issues ........................................................................................................................................................................... 126 Threading Issues ............................................................................................................................................................................. 128
Graphics .................................................................................................................................................................................................. 130 Concepts .............................................................................................................................................................................................. 130
Blit................................................................................................................................................................................................... 130
Camera ............................................................................................................................................................................................ 130 Culling, Backface ............................................................................................................................................................................ 133
Mouse Look .................................................................................................................................................................................... 134 Picking ............................................................................................................................................................................................ 135 Sprite ............................................................................................................................................................................................... 135
Texel ............................................................................................................................................................................................... 135
Vertex Buffer .................................................................................................................................................................................. 136 Vertex Winding ............................................................................................................................................................................... 136
Direct3D 9.0 Programming ................................................................................................................................................................. 137 Blitting Surface to Back Buffer ...................................................................................................................................................... 137 CopyRect......................................................................................................................................................................................... 137 Direct3D9 Pipeline.......................................................................................................................................................................... 137
Flexible Vertex Format ................................................................................................................................................................... 139
Fog .................................................................................................................................................................................................. 140 Images ............................................................................................................................................................................................. 141 Lighting, Direct3D Types ............................................................................................................................................................... 141
Meshes ............................................................................................................................................................................................ 144 Primitives ........................................................................................................................................................................................ 147 Sprites – ID3DXSprite .................................................................................................................................................................... 151 Surfaces – Direct writes to the back-buffer DirectX 9.0 .............................................................................................................. 152 Tuning Tips (Optimization) ............................................................................................................................................................ 153
Direct3D 10.0 Programming ............................................................................................................................................................... 153 API Differences between Direct3D 9 and Direct3D 10 .................................................................................................................. 153
Introduction Section 1
©1991 – 2016 Garth Santor & Trinh Hān GATS Encyclopaedia 9 of 278
File Formats ........................................................................................................................................................................................ 155 RAW ............................................................................................................................................................................................... 155
X-file Direct3D .......................................................................................................................................................................... 156 Sample Framework DX-SDK 9.0c.............................................................................................................................................. 163
Sample Framework DX-SDK < 9.0c ........................................................................................................................................... 168
TextHelper Object SDK 9.0c ....................................................................................................................................................... 179 Texture Mapping ............................................................................................................................................................................. 180
Two-dimensional Rendering ........................................................................................................................................................... 183 Hardware ............................................................................................................................................................................................. 183
Adapters .......................................................................................................................................................................................... 183
Terrain ................................................................................................................................................................................................. 186 Height Maps .................................................................................................................................................................................... 186
Lighting, Static ................................................................................................................................................................................ 188 Skyboxes (sky-domes) .................................................................................................................................................................... 189
History..................................................................................................................................................................................................... 192
DirectX ............................................................................................................................................................................................ 192 Mathematics ............................................................................................................................................................................................ 195
General ................................................................................................................................................................................................ 195 Factorial .......................................................................................................................................................................................... 195 Fibonacci Numbers ......................................................................................................................................................................... 195
Golden Ratio ................................................................................................................................................................................... 196
Logarithms ...................................................................................................................................................................................... 197 Numbers .......................................................................................................................................................................................... 197
Pi ..................................................................................................................................................................................................... 197 Algebra ................................................................................................................................................................................................ 198
Binomial Coefficient ....................................................................................................................................................................... 198 Permutation ..................................................................................................................................................................................... 199
Sum of Natural Numbers ................................................................................................................................................................ 199
2D/3D Algebra .................................................................................................................................................................................... 200 Coordinate Transforms ................................................................................................................................................................... 200 Quaternion....................................................................................................................................................................................... 202
Transformations .............................................................................................................................................................................. 205 Vector (geometric) .......................................................................................................................................................................... 207
Calculus............................................................................................................................................................................................... 208 Euler’s Constant – e ........................................................................................................................................................................ 208
Geometry............................................................................................................................................................................................. 209 Euler Angles.................................................................................................................................................................................... 209 Lines – 2D ....................................................................................................................................................................................... 209
Introduction Section 1
©1991 – 2016 Garth Santor & Trinh Hān GATS Encyclopaedia 10 of 278
Polyhedra ........................................................................................................................................................................................ 211 Polyhedra – Regular ........................................................................................................................................................................ 211
Tait-Bryan Angles ........................................................................................................................................................................... 224 Graphs ................................................................................................................................................................................................. 225
Representations ............................................................................................................................................................................... 225
Path-finding..................................................................................................................................................................................... 229 Logic & Boolean Algebra ................................................................................................................................................................... 233
Mathematical Induction .................................................................................................................................................................. 233 Propositional Logic ......................................................................................................................................................................... 234
Number Systems ................................................................................................................................................................................. 238
Two’s Complement ......................................................................................................................................................................... 238 Statistics .............................................................................................................................................................................................. 238
Arithmetic Mean ............................................................................................................................................................................. 238 Frequency distribution .................................................................................................................................................................... 238 Histogram ........................................................................................................................................................................................ 239
Mode ............................................................................................................................................................................................... 239 Standard Deviation & Variance ...................................................................................................................................................... 239
Statistical Median............................................................................................................................................................................ 240 Trigonometry ...................................................................................................................................................................................... 241
Operating Systems .................................................................................................................................................................................. 244
Windows Vista .................................................................................................................................................................................... 244
Automatic Log In ............................................................................................................................................................................ 244 Physics .................................................................................................................................................................................................... 245
General ................................................................................................................................................................................................ 245 Bounce ............................................................................................................................................................................................ 245 Gravity ............................................................................................................................................................................................ 245 Material Properties .......................................................................................................................................................................... 246
Game ................................................................................................................................................................................................... 251
Collision Detection ......................................................................................................................................................................... 251 Metric .................................................................................................................................................................................................. 252
Prefixes ........................................................................................................................................................................................... 252
Programming Concepts ........................................................................................................................................................................... 254 Concurrent Programming.................................................................................................................................................................... 254
Best Practices .................................................................................................................................................................................. 254 Internal vs. External Locking .......................................................................................................................................................... 255 Zombie Process ............................................................................................................................................................................... 256
Development Process .......................................................................................................................................................................... 256 Code Changes – Big/Little .............................................................................................................................................................. 256
Introduction Section 1
©1991 – 2016 Garth Santor & Trinh Hān GATS Encyclopaedia 11 of 278
GOF – Gang of Four ....................................................................................................................................................................... 256 Reuse ............................................................................................................................................................................................... 257
Errors................................................................................................................................................................................................... 258 Bug .................................................................................................................................................................................................. 262
Exception Handling ............................................................................................................................................................................ 262
Benefits of exception handling ....................................................................................................................................................... 262 Software Design Issues ................................................................................................................................................................... 263
Why do so many people dislike exceptions? .................................................................................................................................. 264 Generic Programming ......................................................................................................................................................................... 265
Generic Programming Techniques ................................................................................................................................................. 265
Traits Classes .................................................................................................................................................................................. 266 Object-Oriented Programming............................................................................................................................................................ 267
Class Invariants ............................................................................................................................................................................... 267 Contract Classes .............................................................................................................................................................................. 267 Functor Classes ............................................................................................................................................................................... 268
Terminator Class ............................................................................................................................................................................. 269 Zombie Object ................................................................................................................................................................................ 269
Testing & Reliability........................................................................................................................................................................... 269 Test Doubles ................................................................................................................................................................................... 271 Testing Styles .................................................................................................................................................................................. 272
Transactional Programming Style................................................................................................................................................... 272
Invariants......................................................................................................................................................................................... 274 Appendices .............................................................................................................................................................................................. 276
Acronyms ........................................................................................................................................................................................ 276 References ....................................................................................................................................................................................... 276 Index ............................................................................................................................................................................................... 277
AI Section 2
©1991 – 2016 Garth Santor & Trinh Hān GATS Encyclopaedia 12 of 278
AI
Neural Networks
Back Propagation Learning A LAYER is a vector of nodes
A NODE is a structure containing a vector of incoming link-weights (w), an incoming signal (in), an outgoing signal (out) and an error delta ( ).
function BACK-PROP-LEARNING( examples, network ) returns a neural network
inputs: examples, a set of examples, each with input vector (input) and output vector (output)
network, a vector of layers, activation function g
repeat
for each e in examples do
for each node in do
for i = 2 to size{layers} do
for each node in ilayers do
for each node in the output layer do
for i = L – 1 downto 1 do
for each node in ilayers do
for each in do
until some stopping criterion is satisfied
return NEURAL-NET-HYPOTHESIS( network )
1layers
i iin node w node input e out node g in node
1[ ]j j iin node w node out node layers
out node g in node
{ }offset nodenode g in node output e out node
1j j inode g in node w node node layers
node 1ilayers
node nodew node w node out node node
Algorithms Section 3
©1991 – 2016 Garth Santor & Trinh Hān GATS Encyclopaedia 13 of 278
Algorithms Algorithms are step-by-step problem solving procedures that produce their results in a finite number of steps. They produce the exact result, in a
predictable amount of time. The best case time can differ from the worst case time, but the worst case time is finite.
Example: Binary Search locates information in a sorted list in no more than n2log searches.
Algorithms are so valuable to the computing sciences because they can be studied in a language-independent and machine independent manner.
As a result of these attributes, algorithms have a durability and importance matched by few other topics in computing. The language-independent
nature of algorithms presents a unique problem for computer scientists – how do we compare the relative performance of algorithms without
implementing them? The two most important methods of comparison are (1) the HTURAM model of computation and (2) HTUasymptotic analysis of
worst-case complexity.
The RAM Model of Computation can identify algorithm performance on a specific input set. The asymptotic analysis or HTUbig-ohUTH notation is more
complex but can yield performance information over all input sets.
Pseudo-code Style The style used in this book for pseudo code is derived from the pseudo code conventions published in MIT’s Introduction to Algorithms [IA-90].
1. Indentation indicates block structure.
2. The looping constructs while, for and repeat/until and the conditional structures if, then, else have the same interpretation as in Pascal.
3. The symbol ← indicates assignment. Multiple assignment i ← j ← k assigns the value of k to both i and j.
4. Variables are local to the given procedure.
5. Array elements are accessed by specifying the array name followed by square brackets. Arrays are assumed to be zero-based, therefore the first
element of an array is located at offset 0, and the last element is located at offset length{A} – 1.
6. Attributes of objects are accessed by naming the attribute followed by the object name wrapped in brace brackets. (e.g. length{A} provides the
length of array A measured in elements.)
7. Parameters are passed to procedures by value unless specified otherwise.
Algorithm vs. Formula A formula is a statement of a rule, principle, or other factual relationship.
Often problems can be solved more directly with formula than they can with algorithms.
Algorithms Section 3
©1991 – 2016 Garth Santor & Trinh Hān GATS Encyclopaedia 14 of 278
Example
The sum of the natural numbers from 1 to n:
n
i
ixsum1
can be calculated using the following algorithm:
function SUM-NATURAL( n ) returns natural number
sum ← 0
for i ← 1 to n do
sum ← sum + i
return sum
This algorithm will require n addition operations, n assignment operations, and n increment operations. O(3n). The same value can be computed
with the following formula.
2
1
nnsum
This calculation only requires a single multiply, a single divide and a single add. O(3).
Algorithm vs. Heuristic ‘Heuriskein’ the Greek word meaning ‘to find’.
Heuristics are like algorithms but they do not have the algorithm’s guarantee of completing in finite time. They will bring us closer and closer to a
better solution with each iteration, but may never produce the exact answer.
Analysis of Algorithms
Asymptotic Analysis Asymptotic analysis is a method of analyzing the complexity of algorithms expressing their performance relative to an input size of the data. Our
assumption is that the specific input values do not matter, just the size of the input data set. With this assumption we define three functions:
Best-case complexity of the algorithm is the function defined by the minimum number of operations taken on an input set of size n.
Average-case complexity of the algorithm is the function defined by the average number of operations taken on an input set of size n.
Worst-case complexity of the algorithm is the function defined by the maximum number of operations taken on an input set of size n.
In practice, the formula that specifically describes the performance can be quite complex and may obscure the important governing terms of the
equation that it most indicative of the algorithm’s overall performance. To highlight these important terms we use HTUbig-ohUTH, theta, and omega
notations.
Algorithms Section 3
©1991 – 2016 Garth Santor & Trinh Hān GATS Encyclopaedia 15 of 278
Big-Oh Notation (theta & omega) Big-Oh notation is used to highlight the important terms in HTUasymptotic analysis of algorithms. The actual functions produced by an asymptotic
analysis of an algorithm can be quite complex yielding performance graphs with many subtle changes, peaks and troughs. These subtleties can
obscure the overall shape of the performance graph and hide key performance characteristic that allows us to compare the algorithm with another.
Big-Oh notation (Theta notation and Omega notation) provide a method of isolating that critical term that governs the overall time complexity of
the algorithm.
Big-Oh notation: ngOnf means ngc is an upper bound on nf . Thus there exists some constant c such that nf is always ngc
, for a sufficiently large enough n.
Omega notation: ngnf means ngc is a lower bound on nf . Thus there exists some constant c such that nf is always ngc ,
for a sufficiently large enough n.
Theta notation: ngnf means ngc 1 is an upper bound on nf and ngc 2
is a lower bound on nf . Thus there exists some constant
c such that nf is always ngc , for a sufficiently large enough n. Thus there exists constants 1c and
2c such that ngcnf 1 and
ngcnf 2. This is a tightly bound function.
Ram Model of Computation The RAM Model of Computation is a method of assessing the performance of an algorithm in a manner that is independent of language and
machine. This model assumes the existence of a hypothetical computer called the Random Access Machine or RAM. The performance properties
of this machine are:
Each simple operation (+, *, =, if, function call, etc.) takes exactly 1 clock cycle.
Each memory access takes exactly 1 clock cycle.
The total amount of memory is unlimited.
Loops and subroutines take a number of clock cycles equal to the sum of component parts.
The most significant complaint about this model is that the simple operations tend to take different amounts of time. Integer addition typically
takes less time than floating-point division. Conditional statements consume different amounts of time to execute the true path than the false path
on a pipelined processor. Branch-prediction further confuses the issue. Memory access times tend to degrade in large data sets due to the
decreasing frequency of cache hits and the swapping of virtual memory.
Despite its shortcomings, the RAM model of computation is reliable enough for scoring the one algorithm against another.
Algorithms Section 3
©1991 – 2016 Garth Santor & Trinh Hān GATS Encyclopaedia 16 of 278
Counting
Digits The number of digits in an integer can be counted by successive divisions by the base (usually 10). When the quotient reaches zero – stop
counting.
function NUMBER-OF-DIGITS( n, base ) returns integer
digitCount 0
repeat
n n div base
digitCount digitCount + 1
until n = 0
return digitCount
Numerical
Greatest Common Divisor See Highest Common Factor.
Highest Common Factor Perhaps the oldest non-trivial algorithm (circa 300 B.C.E.), Euclid’s algorithm calculates the value of the greatest common divisor of two integers.
It is most easily conceived as a recursive algorithm.
The underlying theory from which the algorithm is derived is that: babhcfbahcf mod,, .
Also known as Euclid’s Algorithm and Greatest Common Divisor.
function HCF( a, b ) returns natural number
if b = 0
then return a
else return HCF( b, a mod b )
Note:
a and b are natural numbers.
Passing the large of the numbers as the ‘a’ parameter minimizes the depth of the recursion.
Algorithms Section 3
©1991 – 2016 Garth Santor & Trinh Hān GATS Encyclopaedia 17 of 278
Multiplication – Russian Peasant Algorithm The “Russian Peasant Algorithm” was named by an English mathematician travelling through Russia in the 19th century. He was surprised by the
method of multiplication taught to peasants in schools. The algorithm itself is much older, perhaps the oldest known algorithm, dating back some
4,000 years to ancient Egypt.
The Algorithm
1. Write two numbers side by side.
2. Record below:
a. The first number, the quotient of the first number divided by two. Any remainder is discarded.
b. The second number, the product of the second number multiplied by two.
c. Repeat until the number in the first column is a one.
3. Cross out all of the rows in which the number in the first column is even.
4. Add all the numbers in the second column that are not crossed out. The sum is the product of the first two numbers.
function MULTIPLY( a, b ) returns integer
acc ← 0
loop
if a is odd
then acc ← acc + b
if a = 1
then return acc
2
aa
2b b
Endloop
Sieve of Eratosthenes The process used by Eratosthenes (276-196 BCE) to find prime numbers.
Algorithm
1. Write down contiguously and in order a list of all the natural numbers starting with 2 and ending with n.
2. Start with the first number in the list.
3. Cross out all of the multiples of that number.
4. Locate the next number in the list that is not crossed out.
5. Repeat steps 3 & 4 until there are only crossed out number remaining in the list.
Algorithms Section 3
©1991 – 2016 Garth Santor & Trinh Hān GATS Encyclopaedia 18 of 278
Example
Coding - Naïve C++
typedef unsigned natural_type;
typedef std::vector<natural_type> primes_type;
// load sieve
primes_type primes;
for( natural_type i = 2; i <= MAX; ++i )
primes.push_back( i );
// mark sieve
primes_type::size_type nextPrimePos = 0;
while( nextPrimePos < primes.size() ) {
natural_type nextPrimeValue = primes[nextPrimePos];
for( primes_type::size_type pos = nextPrimePos + nextPrimeValue;
pos < primes.size(); pos += nextPrimeValue )
primes[pos] = 0;
do {
++nextPrimePos;
} while( nextPrimePos < primes.size() && primes[nextPrimePos] == 0 );
}
// remove zeros
for( primes_type::size_type i = 0; i < primes.size(); )
if( primes[i] == 0 )
primes.erase( primes.begin() + i );
else
++i;
8 7 6 5 4 3 2 16 15 14 13 12 11 10 9 24 23 22 21 20 19 18 17
8 7 6 5 4 3 2 16 15 14 13 12 11 10 9 24 23 22 21 20 19 18 17
8 7 6 5 4 3 2 16 15 14 13 12 11 10 9 24 23 22 21 20 19 18 17
8 7 6 5 4 3 2 16 15 14 13 12 11 10 9 24 23 22 21 20 19 18 17
Algorithms Section 3
©1991 – 2016 Garth Santor & Trinh Hān GATS Encyclopaedia 19 of 278
Coding – Swap and Trim
Although it works, the runtime performance of this code is terrible owing to the cost of the erase method calls which are O(n). This produces an
overall algorithm time complexity of O(n2). We need to fix the remove zeros portion of the algorithm.
// remove zeros
primes_type::size_type iNonPrime = 2;
primes_type::size_type iPrime = 3;
while( iPrime < primes.size(); ) {
swap( primes[iNonPrime], primes[iPrime] );
++iNonPrime;
do {
++iPrime;
} while( iPrime < primes.size() && primes[iPrime] == 0 );
}
primes.resize( iNonPrime );
Coding – Tweaking the cleanup
Two improvements can be made: replacing the swap with a direct assignment (since each location is only visited once), and searching for the next
prime number in increments of two (since there are no prime numbers that are multiplies of 2).
// remove zeros
primes_type::size_type iNonPrime = 2;
primes_type::size_type iPrime = 3;
while( iPrime < primes.size(); ) {
primes[iNonPrime] = primes[iPrime];
++iNonPrime;
do {
iPrime += 2;
} while( iPrime < primes.size() && primes[iPrime] == 0 );
}
primes.resize( iNonPrime );
Coding – Tweaking the sieve
The sieve can be improved by starting each iteration of the sieve not at the first multiple of the prime to be removed but at the square of the prime
to be removed. This works because any multiples for the prime less than the square of the prime would have already been eliminated by a multiple
of one of the previous primes.
// mark sieve
primes_type::size_type nextPrimePos = 0;
while( nextPrimePos < primes.size() ) {
natural_type nextPrimeValue = primes[nextPrimePos];
for( primes_type::size_type pos = nextPrimeValue * nextPrimeValue - 2;
pos < primes.size(); pos += nextPrimeValue )
Algorithms Section 3
©1991 – 2016 Garth Santor & Trinh Hān GATS Encyclopaedia 20 of 278
primes[pos] = 0;
do {
++nextPrimePos;
} while( nextPrimePos < primes.size() && primes[nextPrimePos] == 0 );
}
Euler Sieve
Leonard Euler created a version of the Sieve of Eratosthenes that marks each non-prime only once. Euler’s method remove (for each prime
located) all of the products of the prime and the numbers remaining on the list.
Coding – Euler’s Sieve
// mark sieve
primes_type::size_type nextPrimePos = 0;
while( nextPrimePos < primes.size() ) {
natural_type nextPrimeValue = primes[nextPrimePos];
primes_type::size_type topValue = MAX / nextPrimeValue + 1;
while( topValue > nextPrimeValue ) {
while( primes[ --topValue – 2 ] == 0 );
primes[ topValue * nextPrimeValue – 2 ] = 0;
do {
++nextPrimePos;
} while( nextPrimePos < primes.size() && primes[nextPrimePos] == 0 );
}
Printing
Natural Numbers The topic of printing numbers includes the conversion of a number’s internal representations to sequences of digits of a specific base.
Implementation – Recursive
function TO-STRING( n, base ) returns string
digits ← “0123456789ABCDEF”
if n < base
then return digits[ n ]
else return TO-STRING( n div base, base ) + digits[ n mod base ]
Algorithms Section 3
©1991 – 2016 Garth Santor & Trinh Hān GATS Encyclopaedia 21 of 278
This algorithm lacks robustness in that a call to this function with a base of 1 would result in an infinite recursion. The standard solution would be
to use a driver function that asserts a base value greater than 1.
Searching
Binary
Binary search runs in O( logB2Bn ) time on sorted data sets. An unsuccessful search requires 1log N iterations of the loop or calls to the
function.
Implementation – Array, Recursive
This implementation returns the index of the target element if found, or the size of the vector if not.
function BINARY-SEARCH( A, key, low, high ) returns a natural number
if low ≤ high
then middle ← (low + high) div 2
if key = A[middle] then return middle
else if key < A[middle] then return BINARY-SEARCH( A, key, low, middle – 1 )
else return BINARY-SEARCH( A, key, middle + 1, high )
else return length{A}
Implementation – Array, Iterative
This implementation returns the index of the target element if found, or the size of the vector if not.
function BINARY-SEARCh( A, key, low, high ) returns a natural number
while low ≤ high do
middle ← (low + high) div 2
if key = A[middle] then return middle
else if key < A[middle] then high ← middle – 1
else low ← middle + 1
return length{A}
Implementation – Array, Iterative
A potential speed improvement can be found by reducing the amount of branching inside the loop. In this version we always search down to a
sub-list of size one, then test to see if the remaining element is the key.
Algorithms Section 3
©1991 – 2016 Garth Santor & Trinh Hān GATS Encyclopaedia 22 of 278
function BINARY-SEARCH( A, key, low, high ) returns a natural number
while low < high do
middle ← (low + high) div 2
if A[middle] < key
then low ← middle + 1
else high ← middle – 1
if low = high and A[ low ] = key
then return low
else return length{A}
Linear The simplest search algorithm is the linear search; which starts at one end of the data structure and through brute force, tests each element in turn
until the target has been found.
Implementation – Array
This implementation returns the index of the target element if found, or the size of the vector if not.
function LINEAR-SEARCH( A, key ) returns a natural number
for i ← 1 to length{A} – 1 do
if A[i] = key
then return i
return length{A}
Implementation – Pointer
This implementation returns the index of the target element if found, or the size of the vector if not.
function LINEAR-SEARCH( beg, end, key ) returns a pointer
current ← beg
while current ≠ end do
if value{current} = key
then return current
return end
Remove from Sequence Presented here are two algorithms that remove all instances of an item from the given sequence. The first algorithm performs better on contiguous
sequences, the second performs better on non-contiguous sequences such as linked lists.
Algorithms Section 3
©1991 – 2016 Garth Santor & Trinh Hān GATS Encyclopaedia 23 of 278
procedure REMOVE-FROM-SEQUENCE( S, item )
front ← first{S}
back ← first{S}
while front ≠ end{S} and value{front} ≠ item do
front ← next{front}
back ← next{back}
while front ≠ end{S} do
repeat front ← next{S}
until front = end{S} or value{front} ≠ item
while front ≠ end{S} and front ≠ item do
value{back} ← value{front}
back ← next{back}
front ← next{front}
ERASE( S, back, end )
procedure REMOVE-FROM-SEQUENCE( S, item )
p ← first{S}
while p ≠ end{S} do
if value{p} = item then
p ← ERASE( S, p )
else
p ← next{p}
Splay Trees
References
C/C++ Users Journal (September 2005)
Sorting
Introduction Sorting is an operation that places things into some natural order.
Sorts are said to be stable if the elements with the same key value appear in the output collection in the same order that they appear in the input
collection. Sort stability is important when sorting a collection several times, each time by a different key. (E.g. firstly by day, secondly by month,
lastly by year)
Name, best, average, worst, memory, stable, method, comparison, notes
Name Best Average Worst Memory Stable Method Comparison Notes
Bogosort ( )O n ( !)O n n unbounded (1)O No n/a Yes
Algorithms Section 3
©1991 – 2016 Garth Santor & Trinh Hān GATS Encyclopaedia 24 of 278
Bubble ( )O n — 2
( )O n (1)O Yes Exchanging Yes Short-circuit variant
Cocktail ( )O n — 2
( )O n (1)O Yes Exchanging Yes
Comb ( log )O n n ( log )O n n ( log )O n n (1)O No Exchanging Yes
Heapsort ( log )O n n ( log )O n n ( log )O n n (1)O No Selection Yes
Insertion ( )O n 2
( )O n 2
( )O n (1)O Yes Insertion Yes Can be performed on serialized input
Merge ( log )O n n ( log )O n n ( log )O n n ( )O n Yes Merging Yes Can be implemented for external sorting
Permutation ( )O n ( !)O n n ( !)O n n (1)O No Selection No
Pigeonhole ( 2 )k
O n ( 2 )k
O n ( 2 )k
O n (2 )k
O Yes Tabulation No Assumes = 2k
n
Quicksort ( log )O n n ( log )O n n 2( )O n (log )O n No Partitioning Yes
Selection 2( )O n
2( )O n
2( )O n (1)O No Selection Yes
Shell’s — — 1.5( )O n (1)O No Insertion Yes
Is-Sorted – random-access container ‘IS-SORTED’ determines if a collection is sorted. The first algorithm is implemented for a random-access collection.
function IS-SORTED( A ) returns a Boolean
for i ← 1 to length{A} – 1 do
if A[i] < A[i – 1] then
return false
return true
Is-Sorted – forward iterators function IS-SORTED( beg, end ) returns a Boolean
if beg = end
then return true previous ← beg
current ← successor{beg}
while current ≠ end do
if value{current} < value{previous}
then return false previous ← current
current ← successor {current}
return true
Algorithms Section 3
©1991 – 2016 Garth Santor & Trinh Hān GATS Encyclopaedia 25 of 278
Bogo Sort ‘BOGO-SORT’ randomly shuffles the elements of the collection until satisfies ‘IS-SORTED’.
procedure BOGO-SORT( A )
while not IS-SORTED( A )
RANDOMIZE( A )
Is this the worst sorting algorithm of all time? Perhaps its not even an algorithm but is more likely an heuristic, and a bad one.
References
http://en.wikipedia.org/wiki/Bogosort
Bubble Sort
‘Bubble-Sort’ is the worst sorting algorithm in common use. It is both move intensive and comparison intensive. However, its lack-lustre
performance has never severely deterred novices from using it.
… in fact, the Bubblesort has hardly anything to recommend it except its catchy name. (Wirth, 1976)
Algorithm
1. repeat for as many times as there are elements less one;
2. for each element pair;
3. compare KBiB with KBi+1B, interchanging RBiB with RBi+1B if the keys are out of order.
Where K represents keys and R represents records.
Implementation – random-access container (brute force) This first implementation is a brute-force translation of the algorithm for a random-access container.
procedure BUBBLE-SORT( A )
for pass ← 1 to length{A} – 1 do
for idxPair ← 1 to length{A} – 1 do
if A[idxPair] < A[idxPair – 1]
then exchange A[idxPair] ↔ A[idxPair – 1]
This can easily be improved upon by recognizing that each pass places a minimum of one element into its sorted place, (i.e. the sorted portion
grows from the end to the beginning). Any further testing of those elements is redundant.
Implementation – random-access container (standard) This second implementation removes those extra comparisons.
Algorithms Section 3
©1991 – 2016 Garth Santor & Trinh Hān GATS Encyclopaedia 26 of 278
procedure BUBBLE-SORT( A )
for pass ← 1 to length{A} – 1 do
for idxPair ← 1 to length{A} – pass do
if A[idxPair] < A[idxPair – 1]
then exchange A[idxPair] ↔ A[idxPair – 1]
The next refinement removes the calculation within the inner loop’s termination condition.
procedure BUBBLE-SORT( A )
for idxEndOfPass ← length{A} – 1 downto 1 do
for idxPair ← 1 to idxEndOfPass do
if A[idxPair] < A[idxPair – 1]
then exchange A[idxPair] ↔ A[idxPair – 1]
Implementation – bi-directional iterators Now we can write the equivalent implementation for bi-directional iterators.
procedure BUBBLE-SORT( beg, end )
firstPair ← successor{beg}
while firstPair end do
previous ← beg
current ← firstPair
while current end do
if value{current} < value{previous}
then exchange value{current} ↔ value{previous}
previous ← current
current ← successor{current}
end ← predecessor{end}
Bubble sort’s performance on sorted and partially sorted lists can be dramatically improved by tracking the occurrences of exchanges in each pass.
If no exchanges occur, the then the list is already sorted and the algorithm could immediately be terminated.
This algorithm performs particularly poorly on reversed lists, since every element pair is swapped on every pass. The tests simply add overhead.
Implementation – random-access container (short-circuit) procedure BUBBLE-SORT( A )
for idxEndOfPass ← length{A} – 1 downto 1 do
hasSwapped ← false
for idxPair ← 1 to idxEndOfPass do
if A[idxPair] < A[idxPair – 1]
then exchange A[idxPair] ↔ A[idxPair – 1]
hasSwapped ← true
if hasSwapped is false
then return
Algorithms Section 3
©1991 – 2016 Garth Santor & Trinh Hān GATS Encyclopaedia 27 of 278
Implementation – bi-directional iterators (short-circuit) The bi-directional iterator implementation:
procedure BUBBLE-SORT( beg, end )
firstPair ← successor{beg}
hasSwapped ← true
while firstPair end and hasSwapped do
hasSwapped ← false
previous ← beg
current ← firstPair
while current end do
if value{current} < value{previous}
then exchange value{current} ↔ value{previous}
hasSwapped ← true
previous ← current
current ← successor{current}
end ← predecessor{end}
References
http://en.wikipedia.org/wiki/Bubble_sort
Cocktail-shaker The cocktail-shaker sort is a variation of the bubble sort. The difference is that the bubble passes are performed in both directions as opposed to
bubble sort’s forward only passes.
Algorithm
1. while the unsorted range is greater than 1
2. for each element pair in the unsorted range;
3. compare KBiB with KBi+1B, interchanging RBiB with RBi+1B if the keys are out of order.
4. for each element pair in the unsorted range;
5. compare KBiB with KBi-1B, interchanging R BiB with RBi-1B if the keys are out of order.
6. reduce the unsorted range by 1 at each end
Where K represents keys and R represents records.
Implementation – random-access container (naïve) The first implementation is the direct translation of the algorithm.
Algorithms Section 3
©1991 – 2016 Garth Santor & Trinh Hān GATS Encyclopaedia 28 of 278
procedure COCKTAIL-SHAKER-SORT( A )
idxFirstUnsorted ← 0
idxLastUnsorted ← length{A} – 1
idxCurrent ← idxFirstUnsorted
while idxFirstUnsorted < idxLastUnsorted do
while idxCurrent < idxLastUnsorted do
if A[idxCurrent + 1] < A[idxCurrent]
then exchange A[idxCurrent + 1] ↔ A[idxCurrent]
idxCurrent ← idxCurrent + 1
idxLastUnsorted ← idxLastUnsorted – 1
while idxCurrent > idxFirstUnsorted do
if A[idxCurrent – 1] > A[idxCurrent]
then exchange A[idxCurrent – 1] ↔ A[idxCurrent]
idxCurrent ← idxCurrent – 1
idxFirstUnsorted ← idxFirstUnsorted + 1
In the case of an empty container, idxLastUnsorted is initialized to –1. However, if the index type is unsigned, numeric underflow occurs causing
to be initialized to std::numeric_limits<unsigned>::max() – a clearly invalid location. The algorithm must either be implemented using a signed
range type or be rewritten.
Implementation – random-access container (safe) procedure COCKTAIL-SHAKER-SORT( A )
idxFirstUnsorted ← 0
idxEnd ← length{A}
idxCurrent ← idxFirstUnsorted
while idxFirstUnsorted < idxEnd do
idxCurrent ← idxCurrent + 1
while idxCurrent < idxEnd do
if A[idxCurrent – 1] < A[idxCurrent]
then exchange A[idxCurrent – 1] ↔ A[idxCurrent]
idxCurrent ← idxCurrent + 1
idxEnd ← idxEnd – 1
idxCurrent ← idxCurrent – 1
while idxCurrent > idxFirstUnsorted do
if A[idxCurrent – 1] > A[idxCurrent]
then exchange A[idxCurrent – 1] ↔ A[idxCurrent]
idxCurrent ← idxCurrent – 1
idxFirstUnsorted ← idxFirstUnsorted + 1
Algorithms Section 3
©1991 – 2016 Garth Santor & Trinh Hān GATS Encyclopaedia 29 of 278
Implementation – bi-directional iterators procedure COCKTAIL-SHAKER-SORT( beg, end )
if beg = end then
return
previous ← beg
next ← successor{beg}
while next ≠ end do
while next ≠ end do
if value{previous} > value{next}
then exchange value{previous} ↔ value{next}
previous ← successor{previous}
next ← successor{next}
previous ← predecessor{previous}
next ← predecessor{next}
end ← predecessor{end}
if previous = beg
then return
repeat
previous ← predecessor{previous}
next ← predecessor{next}
if value{previous} > value{next}
then exchange value{previous} ↔ value{next}
until previous = beg
previous ← successor{previous}
next ← successor{next}
beg ← successor{beg}
References
http://en.wikipedia.org/wiki/Cocktail_sort
Comb Sort The comb sort is a variation of the HTUbubble sortUTH first published in Byte by Steven Lacy and Richard Box (Stephen Lacy and Richard Box, "A Fast,
Easy Sort", Byte, April 1991, p.315). Comb sort can also be thought of as a variation of Shell’s sort. It uses Shell’s idea of enhancing the
performance of the insert by inserting in steps or shells of a magnitude greater than 1. The comb sort uses bubble passes that compare non-
contiguous elements; thereby moving an element closer to its correct resting spot in fewer moves. Lacy and Box investigated the gap reduction
factor and found that shrink factor of 1.3 was ideal and that further performance gains occur in the gap values of 9 and 10 are exchanged for 11.
Algorithms Section 3
©1991 – 2016 Garth Santor & Trinh Hān GATS Encyclopaedia 30 of 278
Implementation – random-access container
procedure COMB-SORT( A )
gap ← length{A}
loop
if gap = 9 or gap = 10
then gap ← 11
else if gap < 1
then gap ← 1
swapped ← false
for i ← 0 to length{A} – gap – 1 do
j ← i + gap
if A[ i ] > A[ j ]
then exchange A[ i ] ↔ A[ j ]
swapped ← true
if gap = 1 and not swapped
then return
Note that the container can not be empty if the range type is unsigned.
References
http://en.wikipedia.org/wiki/Comb_sort
Count Sort See ‘Pigeonhole Sort’
Heap Sort ‘Heap sort’ is what you would call a ‘good performer’. Its sorts in ( log )O n n time – always!
The heap sort works by first arranging all of the elements of the container into a heap. A heap is binary tree in which the key values of the child
nodes are both less than the key value of the parent node.
A binary tree structure can be implemented in a 1-base array by employing the relationship of left-child-index is double the parent-index, right-
child-index is one greater than the left-child-index.
Once formed, the heap can be converted to a sorted list by swapping the element at the top of the heap with the last element in the heap; shrinking
the heap by one; then fixing the heap by recursively adjusting the top element until the heap has been restored.
1.3gap gap
Algorithms Section 3
©1991 – 2016 Garth Santor & Trinh Hān GATS Encyclopaedia 31 of 278
Implementation – random-access container (iterative) procedure HEAP-SORT( A )
heapSize ← length{A}
for parentNode ← heapSize div 2 downto 1 do
HEAPIFY( A, parentNode, heapSize )
for idx ← length{A} – 1 downto 1 do
exchange A[0] ↔ A[idx]
heapSize ← heapSize – 1
HEAPIFY( A, 1, heapSize )
procedure HEAPIFY( A, parentNode, heapSize )
loop
leftNode ← parentNode × 2
if leftNode > heapSize
then return if A[leftNode – 1] > A[parentNode – 1]
then largestNode ← leftNode
else largestNode ← parentNode
rightNode ← leftNode + 1
if rightNode ≤ heapSize and A[rightNode – 1] > A[largestNode – 1]
then largestNode ← rightNode
if largestNode ≠ parentNode
then exchange A[largestNode – 1] ↔ A[parentNode – 1]
parentNode ← largestNode
else return
Limited Heap Sort
In web search engines we often want only the k best results presented in a sorted list, where there may have been as many as n > k results. There is
no point in storing all n results, sorting them all then throwing away the n – k excess elements.
A limited heap sort, sorts the k highest elements of a set of n elements. We first feed k elements into the heap and build an ascending order heap
(the lowest value at the top of the heap). For the remaining elements we compare the new element to the top element of the heap replacing the top
element if the new element is larger – then heapify. Once all elements have been tested and inserted into the heap, we complete the heap sort
producing an ascending order list.
We can then reverse the list to produce a descending order list if necessary.
References
http://en.wikipedia.org/wiki/Heapsort
Algorithms Section 3
©1991 – 2016 Garth Santor & Trinh Hān GATS Encyclopaedia 32 of 278
Insertion Sort Insertion sort is an attempt to minimize the number of comparisons performed during a sort by shifting through sorted space when positioning an
element.
Algorithm 1. for each element EBiB in the array;
2. we assume that the preceding elements EB1B, …, EBi-1B have already been sorted;
3. we insert EBiB, into its proper place among the sorted records
where E represents keys
Implementation – random-access container Here is an implementation for a random-access container.
procedure INSERTION-SORT( A )
for idxFirstUnsorted ← 1 to length{A} – 1 do
idx ← idxFirstUnsorted
while idx > 0 and A[idx] < A[idx – 1] do
exchange A[idx] ↔ A[idx – 1]
idx ← idx – 1
Notes For empty arrays the first line of the algorithm results in an index being created that has a negative value (i.e. –1). If your implementing
language’s index type is an unsigned type this statement would produce numeric underflow.
Implementation – bi-directional iterators procedure INSERTION-SORT( beg, end )
if beg = end then
return
firstUnsorted ← beg
loop
firstUnsorted ← successor{firstUnsorted}
if firstUnsorted = end
then return
element ← firstUnsorted
previous ← predecessor{element}
while element ≠ beg and value{element} < value{previous} do
exchange value{element} ↔ value{previous}
element ← predecessor{element}
previous ← predecessor{previous}
This implementation does present a challenge when converted to code since many modern implementations of iterators have ‘safe’ debug versions
that test to see that the iterators stay within bounds. This algorithm violates that rule on the final line.
Algorithms Section 3
©1991 – 2016 Garth Santor & Trinh Hān GATS Encyclopaedia 33 of 278
Implementation – bi-directional iterators (safe) procedure INSERTION-SORT( beg, end )
if beg = end then
return
firstUnsorted ← beg
loop
firstUnsorted ← successor{firstUnsorted}
if firstUnsorted = end
then return
element ← firstUnsorted
previous ← element
while element ≠ beg do
previous ← predecessor{previous}
if value{element} ≥ value{previous}
then break exchange value{element} ↔ value{previous}
element ← predecessor{element}
This is adjustment produces some ugly code, but languages that permit assignment inside loop conditions can significantly clean up the
implementation:
Implementation – bi-directional iterators (elegant) procedure INSERTION-SORT( beg, end )
if beg = end then
return
firstUnsorted ← beg
loop
firstUnsorted ← successor{firstUnsorted}
if firstUnsorted = end
then return
previous ← element ← firstUnsorted
while element ≠ beg and value{element} < value{ previous ← predecessor{previous} } do
exchange value{element} ↔ value{previous}
element ← predecessor{element}
References
http://en.wikipedia.org/wiki/Insertion_sort
Merge Sort Merge sort is the original divide and conquer sort. It executes in O(n logB2B n) time whether sorting vectors, linked lists or files. The vector and file
implementations require additional storage of equal size to process the merge; the linked list version does not.
Algorithms Section 3
©1991 – 2016 Garth Santor & Trinh Hān GATS Encyclopaedia 34 of 278
Merge sort can be processed using recursion or iteration. The recursive version is not easily adapted to files while the iterative version adapts
easily to all data types and stores.
Algorithm
1. If the list size is 0 or 1, return.
2. Split the list into 2 equal parts.
3. Merge-Sort each half-list separately.
4. Merge the two sorted lists into a single list.
Implementation – Random-access Container Using Recursion
procedure MERGE-SORT( A, beg, end )
if end – beg > 1 then
split ← (beg + end) div 2
MERGE-SORT( A, beg, split )
MERGE-SORT( A, split, end )
MERGE( A, beg, split, end )
procedure MERGE( A, low, high, end)
create a output array D the same size of A
lowWalker ← low
highWalker ← high
destWalker ← low
while lowWalker < high and highWalker < end
if A[lowWalker] < A[highWalker]
then D[destWalker] ← A[lowWalker]
lowWalker ← lowWalker + 1
else D[destWalker] ← A[highWalker]
highWalker ← highWalker + 1
destWalker ← destWalker + 1
if lowWalker < high
then D[destWalker .. end – 1] ← A[lowWalker .. high – 1]
else D[destWalker .. end – 1] ← A[highWalker .. end – 1]
A ← D
Optimization – Pre-allocate the copy vector.
The biggest performance hit in the preceding implementation is the constant reallocations of the hold array – D. The simple solution is to have the
driver function create D and then pass it to the merge function.
Algorithms Section 3
©1991 – 2016 Garth Santor & Trinh Hān GATS Encyclopaedia 35 of 278
Implementation – Random-access Container Using Iteration
procedure MERGE-SORT( A )
sublistSize ← 1
while sublistSize < length{A} do
low ← 0
while low < length{A} do
high ← low + sublistSize
end ← high + sublistSize
if end > length{A}
then end ← length{A}
if high > length{A}
then high ← length{A}
if high ≠ length{A}
then MERGE( A, low, high, end )
low ← low + 2 sublistSize
sublistSize ← 2 sublistSize
Optimization – Random-access Container Using Iteration with Short-circuiting
Another optimization is the recognition that there is unnecessary copying during the merge when the lower half of the array empties first. The data
remaining in the top half of the array is already in the correct position, so copying those elements to the temporary store would be pointless.
hgfedcba §§§§lkji
Array A
Array D
highlow end
lowWalker highWalker
destWalker
ponm
hgfedcba §§§§lkji
Array A
Array D
highlow
end
lowWalker highWalker
destWalker
ponm
ponm
copy
lowWalker high destWalker end
Array A´
Algorithms Section 3
©1991 – 2016 Garth Santor & Trinh Hān GATS Encyclopaedia 36 of 278
procedure MERGE( A, low, high, end )
lowWalker ← low
highWalker ← high
destWalker ← low
while lowWalker < high and highWalker < end
if A[lowWalker] < A[highWalker]
then D[destWalker] ← A[lowWalker]
lowWalker ← lowWalker + 1
else D[destWalker] ← A[highWalker]
highWalker ← highWalker + 1
destWalker ← destWalker + 1
if lowWalker < high
then A[destWalker .. end – 1] ← A[lowWalker .. high – 1]
A[low .. destWalker – 1] ← D[low .. destWalker – 1]
Note that the block copy in line 12 must be a high to low copy since the ranges could overlap.
Implementation – Linked List with Iteration procedure MERGE-SORT( L )
sublistSize ← 1
while sublistSize < length{L} do
empty the holdList
while L is not empty do
split a list of no greater size than sublistSize from the front of L
split another list of no greater size than sublistSize from the front of L
Merge the two lists
splice the merged list onto the end of the holdList
exchange holdList ↔ L
sublistSize ← sublistSize 2
References
http://en.wikipedia.org/wiki/Merge_sort
Ordersort The ordersort algorithm sorts by determining the order in which elements should be arranged, then arranging them into that order. The
arrangement order is determined by locating the immediate predecessors and successors of each element.
References
C/C++ Users Journal (September 2005)
Algorithms Section 3
©1991 – 2016 Garth Santor & Trinh Hān GATS Encyclopaedia 37 of 278
Permutation Sort Permutation sort is a trial-and-error type sort. Try every possible arrangement of the elements – at least one of them is sorted.
Pigeonhole Sort Pigeonhole sort is a special case sort capable of sorting in linear time. Counting sort requires that the input array being sorted only contains
ordinal values in a known and finite range. For our discussion we will assume that values are in the range [0..k]. The idea is to count the number
of instances of each value in the input array. Then for each value detected in the input array, write back to the array the correct number of
instances detected. However, we write the input values back in their sorted order.
One pass of the input array is required to accumulate the frequency table of values, and one more pass is required to write the values back to the
array. This simple approach destroys the original elements and is therefore of little practical use. The sort can be modified to copy the original
values from one array to another.
Implementation – random-access container procedure PEGEONHOLE-SORT( A, k )
for i ← 0 to k do
C[ i ] ← 0
for i ← 0 to length{A} – 1 do
C[ A[ i ] ] ← C[ A[ i ] ] + 1
j ← 0
for i ← 0 to length{C} – 1 do
while C[ i ] > 0 do
C[ i ] ← C[ i ] – 1
A[ j ] ← i
j ← j + 1
References
http://en.wikipedia.org/wiki/Pigeonhole_sort
Quick sort ‘Quick-sort’, as named by its originator – Sir Anthony (C.A.R.) Hoare (Oxford University) is one of the smallest, fastest and most elegant
algorithms known.
The basic idea is to perform ‘swapping passes’ instead of search and swap. During each ‘swapping-pass’, low-value elements in the top half of the
list are swapped for high-value elements in the bottom half of the list. Eventually the swapping pass would come to a middle point such that all of
the values in the bottom half of the list will have a value lower than every value in the top half of the list. The reverse – that all of the values in the
top half of the list will have a value higher than every value in the bottom half of the list – is necessarily true. The two sub-lists could then be
individually ‘quick-sorted’.
Algorithms Section 3
©1991 – 2016 Garth Santor & Trinh Hān GATS Encyclopaedia 38 of 278
Algorithm
1. If the size of the list is 0 or 1, return.
2. Pick any element from the list. Call this value ‘pivot.’ ( Av )
3. Partition the list into two distinct groups, such that the lower list only contains elements that are less than or equal to the pivot value and the upper list only
contains elements that are greater than or equal to the pivot value.
vxvAxL | and vxvAxU |
4. Return the sequential join of Quicksort(L) and Quicksort(U)
Implementation – random-access container (low is pivot)
The pivot value will be partitioned into the top half of the range.
procedure QUICK-SORT( A, low, high )
if low < high
then pivot ← PARTITION( A, low, high )
QUICK-SORT( A, low, pivot )
QUICK-SORT( A, pivot + 1, high )
The following partition algorithm returns the high index of the lower partition.
function PARTITION( A, low, high ) returns integer
pivotValue ← A[ low ]
low ← low – 1
high ← high + 1
loop
repeat low ← low + 1
until A[low] ≥ pivotValue
repeat high ← high – 1
while A[high] ≤ pivotValue
if low < high
then exchange A[low] ↔ A[high]
else return high
Implementation – random-access container (random pivot)
Choosing the first element as a pivot is as good as any other for a randomly scrambled list. However, it is terrible for a sorted or reverse-sorted
list, causing each swapping pass to correctly place only one element – making the sort perform in O(nP
2P) time. A randomly chosen pivot often
achieves the needed variation to avoid degenerate partitioning.
function PARTITION( A, low, high ) returns integer
pivot ← random value in the range [ low, high ]
pivotValue ← A[pivot]
low ← low – 1
…
Algorithms Section 3
©1991 – 2016 Garth Santor & Trinh Hān GATS Encyclopaedia 39 of 278
Implementation – random-access container (middle pivot)
An alternative to the random pivot is the mid-point pivot.
function PARTITION( A, low, high ) returns integer
pivot ← (low + high) div 2
pivotValue ← A[pivot]
low ← low – 1
…
Implementation – random-access container (Hoare)
Hoare’s implementation is an optimization of the mid-point pivot that merges the partition function and the recursive function. Most significantly
it does not move the pivot value to the beginning of the sub-list.
procedure QUICK-SORT( A, low, high )
lo ← low
hi ← high
pivotValue ← A[ (low + high) div 2 ]
while lo ≤ hi do
while A[ lo ] < pivotValue do
lo ← lo + 1
while A[ hi ] > pivotValue do
hi ← hi – 1
if lo ≤ hi
then exchange A[ lo ] ↔ A[ hi ]
lo ← lo + 1
hi ← hi – 1
if low < hi
then QUICK-SORT( A, low, hi )
if lo < high
then QUICK-SORT( A, lo, high )
Reference
http://en.wikipedia.org/wiki/Quicksort
Selection Sort Selection sort is an attempt to minimize the number of swaps performed during a sort by employing a search through the unsorted space to locate
the exact element to be placed in the sorted portion of the list.
Algorithm
1. for each element EBiB in the array;
2. we assume that the preceding elements EB1B, …, EBi-1B have already been sorted;
3. we search EBiB, …, EBnB for the element with the lowest value { EBkB };
4. exchange elements EBiB and EBkB.
Algorithms Section 3
©1991 – 2016 Garth Santor & Trinh Hān GATS Encyclopaedia 40 of 278
Notes: E represents keys.
assume the array to be 1-based.
Implementation – random-access container (lowest)
First, I’ll present a direct translation of the algorithm.
procedure SELECTION-SORT( A )
for idxFirstUnsorted ← 0 to length{A} – 2 do
idxOfLowest ← idxFirstUnsorted
for idx ← idxFirstUnsorted + 1 to length{A} – 1 do
if A[idxOfLowest] > A[idx] then
idxOfLowest idx
if idxOfLowest idxFirstUnsorted then
exchange A[idxOfLowest] ↔ A[idxFirstUnsorted]
Notes: For empty arrays the first line of the algorithm results in an index being created that has a negative value (i.e. –1). If your
implementing language’s index type is an unsigned type this statement would produce number underflow.
Implementation – random-access container (highest)
Often a more efficient implementation can be achieved by searching for the highest value and sorting from the high indices and working down.
The following implements such an approach
procedure SELECTION-SORT(A)
for idxLastUnsorted ← length{A} – 1 downto 1 do
idxOfHighest ← idxLastUnsorted
for idx ← idxLastUnsorted – 1 downto 0 do
if A[idxOfHighest] < A[idx] then
idxOfHighest idx
if idxOfHighest idxLastUnsorted then
exchange A[idxOfHighest] ↔ A[idxLastUnsorted]
Notes: For empty arrays the first line of the algorithm results in an index being created that has a negative value (i.e. –1). If your
implementing language’s index type is an unsigned type this statement would produce number underflow.
Implementation – forward iterators
The final implementation mimics the previous but replaces array references with pointers or iterators.
Algorithms Section 3
©1991 – 2016 Garth Santor & Trinh Hān GATS Encyclopaedia 41 of 278
procedure SELECTION-SORT( beg, end )
while beg end do
lowest ← beg
current ← beg
loop current ← successor{current}
if current = end then
break
if value{lowest} > value{current} then
lowest ← current
if lowest beg then
exchange value{lowest} ↔ value{beg}
beg ← successor{beg}
Reference
http://en.wikipedia.org/wiki/Selection_sort
Shell’s Sort Insertion sort has good performance on sorted list, but poor performance on reversed lists. This fact inspired D. L. Shell to create this variation on
insertion sort. Insertion sort’s major problem is that when an element is found to be a great distance from its proper spot, it is only moved there
one position at a time. This fault produces a costly O(n P
2P) behaviour.
Shell’s sort eliminates this problem by segmenting the data set and performing the insertion on intermittent portions of the array.
Implementation – random-access container
procedure SHELL’S-SORT( A )
stepSize ← length{A} div 2
while stepSize > 0 do
for idxLastInSegment ← stepSize to length{A} – 1 do
idxCurrent ← idxLastInSegment
while idxCurrent ≥ stepSize and A[idxCurrent] < A[idxCurrent – stepSize] do
exchange A[idxCurrent] ↔ A[[idxCurrent – stepSize]
idxCurrent ← idxCurrent – stepSize
stepSize ← stepSize div 2
Reference
http://en.wikipedia.org/wiki/Shell_sort
Applications Section 4
©1991 – 2016 Garth Santor & Trinh Hān GATS Encyclopaedia 42 of 278
Applications
UML Tools
Argo UML Argo UML is an open-source multiplatform UML modeling tool.
URL http://argouml.tigris.org
Installation – Windows
Unzip the argoUML archive to your ‘Program Files’ folder.
With Java installed, run ‘argouml.jar’.
Drag a short-cut of this file to your desktop to create a launch icon.
Installation – Linux
Login as ‘root’.
Download ArgoUML-0.22.tar.gz to the /usr/local directory.
Extract the argoUML archive to that directory.
Open a console and type the command:
ln –s /usr/local/ArgoUML-0.22/argouml.sh /usr/local/bin/argo
This creates a link in the search path of all users that will load Argo UML from its installation directory.
Audio Programming Section 5
©1991 – 2016 Garth Santor & Trinh Hān GATS Encyclopaedia 43 of 278
Audio Programming
Storage Requirements To store a 10 second recording we must know three pieces of information: the sample rate, the sample quality and the number of channels.
The sample rate is the number of samples taken per second, usually measured in Hz.
The sample quality is the number of bits per sample. 8, 12, 16 and 24 bits per sample are typical levels of sample quality. 8 bits per sample gives
256 levels of loudness, 16 bits gives 65536 levels and 24 bits give over 16 million levels of loudness. 8 bits is considered low-quality, 24 bits is
studio mixing board quality and is unnecessary for a typical game.
The number of channels is determined by the number of microphones used to record the sound. One channel for monaural sound (mono), two
channels for stereo, etc.
10 seconds of stereo sound, recorded at a sample rate of 44.1 KHz using a 16-bit sampler requires:
44100 × 2 channels × 2 bytes (16-bits) × 10 seconds = 1,764,000 bytes.
Compact Disc
Sampling Rate Compact Audio Discs (CDs) are sampled at a rate of 44.1 KHz or 44,100 samples per second. Why 44.1 KHz? Before the CD, digital audio was
stored on magnetic video tape. Video tape plays at 60 frames per second showing 245 scan lines. Each scan line has 3 samples (one for each
primary colour). 60 × 245 × 3 = 44100.
Audio Engines Audio Engines serve the same purpose as graphics engines, but in the audio realm. They abstract audio hardware and provide an interface to high-
level audio functions.
Several popular audio engines used in the gaming industry are:
BASS – www.un4seen.com/music/ (Comprehensive support for Windows and many programming languages. Free for freeware.)
FMOD – www.fmod.org (Very comprehensive library that supports virtually every platform – PS2, XBox, GameCube, Windows, etc. Free for
freeware)
MikMod – www.mikmod.org (Cross-platform tracked music library. Freeware)
ModPlug – www.modplug.com (Quick and easy tracked music, Free)
Audio Programming Section 5
©1991 – 2016 Garth Santor & Trinh Hān GATS Encyclopaedia 44 of 278
Miles Sound System – www.ragametools.com (The ultimate system. Used in over 3000 commercial games. Expensive!)
FMOD 4+ A favourite Audio API is FMOD. A favourite since it is multi-platform and free if used in non-commercial software. It can be found at
www.fmod.org.
Installation
fmodex.dll Place the DLL in the same directory as your application or into the
\Windows\system32 directory.
fmod.h
fmod.hpp
fmod_code.h
fmod_dsp.h
fmod_error.h
fmod_output.h
Include a path to these files in your projects include settings
fmodex_vc.lib
fmodexp_vc.lib
Include a path to these files in your projects libraries settings
Coding
This section documents the minimum requirements to setup streaming audio on a Windows XP system.
Preprocessor
Prepare your source code with the following pre-processor directives:
#include <fmod.hpp>
#include <fmod_errors.h>
#pragma comment (lib, "fmodex_vc.lib")
Initialization
Using FMOD’s new object-oriented C++ framework, we first create a system object.
FMOD::System* system;
FMOD_RESULT result = FMOD::System_Create( &system );
if( result != FMOD_OK ) {
cerr << "FMOD Error! (" << result << ") " << FMOD_ErrorString(result) << endl;
return 1;
}
The version number can be acquired from this object. The top 16 bits contains the major version number, the next 8 bits the sub version and the
bottom 8 bits, the minor version number.
unsigned version;
Audio Programming Section 5
©1991 – 2016 Garth Santor & Trinh Hān GATS Encyclopaedia 45 of 278
system->getVersion( &version );
cout << "Version = " << (version >> 16) << '.' << (version & 0xffff >> 8) << '.' << (version & 0xff) << endl;
We can now setup a system that support 256 virtual voices with the command:
system->init( 256, FMOD_INIT_NORMAL, 0 );
Any customizations like the number of software mixers, hardware channels or speaker mode (like 5.1 surround-sound) must be set prior to calling
init().
Loading
Unlike FMOD3, FMOD4 uses a single interface model for all sounds properties whether streamed or not. By default, sounds are fully loaded and
decompressed into memory when opened.
FMOD::Sound* sound;
system->createSound("music.mp3", FMOD_DEFAULT, 0, &sound );
This may cause delays with long files since the entire sound will be decompressed into 16-bit PCM format. If you desire real-time decompression
you can open the file as a stream.
FMOD::Sound* sound;
system->createSound("music.mp3", FMOD_CREATESTREAM, 0, &sound );
Or the short-form of the command.
FMOD::Sound* sound;
system->createStream("music.mp3", FMOD_DEFAULT, 0, &sound );
Playing the sound or stream.
Whether the sound property is fully loaded or a disk-based stream, the same command will play the sound.
FMOD::Channel* channel;
system->playSound( FMOD_CHANNEL_FREE, sound, false, &channel );
Playing will immediately commence on the first available channel. Changing the ‘false’ parameter to ‘true’ will start the sound in a paused state.
Maintainence
Many of the platforms have specific requirements that must be met on a per frame basis. Call FMOD::System::update() each frame to services
these needs. While there is no harm in calling update more than once per frame, it is unnecessary and a drain on the CPU.
system->update();
Cleanup
Release the stream.
sound->release()
Close and release the sound system before process termination.
system->close();
Audio Programming Section 5
©1991 – 2016 Garth Santor & Trinh Hān GATS Encyclopaedia 46 of 278
system->release();
Close out the sound system before process termination.
FMOD 3.74 A favourite Audio API is FMOD. A favourite since it is multi-platform and free if used in non-commercial software. It can be found at
www.fmod.org.
Installation
fmod.dll
fmod64.dll
Place the appropriate DLL in the same directory as your application or into the
\Windows\system32 directory.
fmod.h
fmod_error.h
fmoddyn.h
wincompat.h
Include a path to these files in your projects include settings
fmod64vc.lib
fmodvc.lib
Include a path to these files in your projects libraries settings
Coding
This section documents the minimum requirements to setup streaming audio on a Windows XP system.
Preprocessor
Prepare your source code with the following pre-processor directives:
#include <fmod.h>
#include <fmod_errors.h>
#pragma comment (lib, "fmodvc.lib")
Initialization
Initialization starts with checking the FMOD version, followed by selecting the sound driver type. On Windows 9x and W2k systems (including
Windows/XP) the DirectSound driver is best. On Windows/NT systems, use the Windows multi-media driver.
if( FSOUND_GetVersion() < FMOD_VERSION ) {
wostringstream woss;
woss << L"You are using the wrong DLL version! You should be using FMOD " <<
setprecision(2) << fixed << FMOD_VERSION;
::MessageBox( NULL, woss.str().c_str(), L"FMOD Error", MB_ICONSTOP );
return 1;
}
Gets the version number and checks that it is at least equal to the version compiled against.
if( !FSOUND_SetOutput( FSOUND_OUTPUT_DSOUND ) ) {
Audio Programming Section 5
©1991 – 2016 Garth Santor & Trinh Hān GATS Encyclopaedia 47 of 278
::MessageBox( NULL, L"DirectSound not available.", L"FMOD Error", MB_ICONSTOP );
return 1;
}
Sets the system to use DirectSound as the underlying hardware interface. DirectSound is the most efficient interface for a Win9x or W2K system.
if( !FSOUND_Init( 44100, 32, 0 ) )
{
FSOUND_Close();
return 1;
}
Configuration
The audio buffer size can be set to better control the memory usage and performance. The buffer size is described by the duration in milliseconds.
The actual buffer size is calculated by multiplying the time by the sample rate by the number of channels.
FSOUND_Stream_SetBufferSize(1000);
Opening a stream.
Declare a variable appropriate to the stream.
FSOUND_STREAM* audioStream;
Then open the stream.
audioStream_ = FSOUND_Stream_Open( "Ramble On.mp3", FSOUND_NORMAL, 0, 0 );
if( audioStream_ == NULL )
{
// failure, don’t need to close the stream, do need to close the sound system.
}
The file type can be any of the following PCM based or compressed file formats; wave format (.wav), MP2 and MP3 format, OggVorbis (.ogg) or
RAW (.raw).
The last two parameters represent an offset into the file. The 3rd parameter being the starting position in the file to seek to before playing. The 4th
parameter is the length of the file and is only necessary if the 3rd parameter is non-zero or the file in being read from a memory buffer (not the
example here).
If you wish the audio stream to automatically repeat, pass FSOUND_LOOP_NORMAL as the second parameter of FSOUND_Stream_Open().
Playing the stream. FSOUND_Stream_Play( 0, audioStream );
Plays the audio stream indicated by audioStream on channel 0. The first parameter – the channel number – must not exceed the maximum
number of channels specified by FSOUND_Init().
Stopping the stream.
The stream can be stopped by either close the stream or sound system or by stopping just that particular stream.
Audio Programming Section 5
©1991 – 2016 Garth Santor & Trinh Hān GATS Encyclopaedia 48 of 278
FSOUND_Stream_Stop( audioStream );
Cleanup
Close and release the stream.
FSOUND_Stream_Close( audioStream );
This stops the stream if it is currently playing.
Close out the sound system before process termination.
FSOUND_Close();
Music
Sound Frequencies
C0 16.35 C#0/Db0 17.32 D0 18.35
D#0/Eb0 19.45 E0 20.60 F0 21.83
F#0/Gb0 23.12 G0 24.50 G#0/Ab0 25.96
A0 27.50 A#0/Bb0 29.14 B0 30.87
C1 32.70 C#1/Db1 34.65 D1 36.71
D#1/Eb1 38.89 E1 41.20 F1 43.65
F#1/Gb1 46.25 G1 49.00 G#1/Ab1 51.91
A1 55.00 A#1/Bb1 58.27 B1 61.74
C2 65.41 C#2/Db2 69.30 D2 73.42
D#2/Eb2 77.78 E2 82.41 F2 87.31
F#2/Gb2 92.50 G2 98.00 G#2/Ab2 103.83
A2 110.00 A#2/Bb2 116.54 B2 123.47
C3 130.81 C#3/Db3 138.59 D3 146.83
D#3/Eb3 155.56 E3 164.81 F3 174.61
F#3/Gb3 185.00 G3 196.00 G#3/Ab3 207.65
A3 220.00 A#3/Bb3 233.08 B3 246.94
C4 261.63 C#4/Db4 277.18 D4 293.66
D#4/Eb4 311.13 E4 329.63 F4 349.23
F#4/Gb4 369.99 G4 392.00 G#4/Ab4 415.30
A4 440.00 A#4/Bb4 466.16 B4 493.88
C5 523.25 C#5/Db5 554.37 D5 587.33
D#5/Eb5 622.25 E5 659.26 F5 698.46
F#5/Gb5 739.99 G5 783.99 G#5/Ab5 830.61
A5 880.00 A#5/Bb5 932.33 B5 987.77
Audio Programming Section 5
©1991 – 2016 Garth Santor & Trinh Hān GATS Encyclopaedia 49 of 278
C6 1046.50 C#6/Db6 1108.73 D6 1174.66
D#6/Eb6 1244.51 E6 1318.51 F6 1396.91
F#6/Gb6 1479.98 G6 1567.98 G#6/Ab6 1661.22
A6 1760.00 A#6/Bb6 1864.66 B6 1975.53
C7 2093.00 C#7/Db7 2217.46 D7 2349.32
D#7/Eb7 2489.02 E7 2637.02 F7 2793.83
F#7/Gb7 2959.96 G7 3135.96 G#7/Ab7 3322.44
A7 3520.00 A#7/Bb7 3729.31 B7 3951.07
C8 4186.01 C#8/Db8 4434.92 D8 4698.64
D#8/Eb8 4978.03
C++ Programming Section 6
©1991 – 2016 Garth Santor & Trinh Hān GATS Encyclopaedia 50 of 278
C++ Programming
Assertions An assertion is a statement that can be tested to be either true or false. Programmers use assertions to verify the correctness of code either during
run-time or compile time. Assertions are best used to test for logic errors.
Run-time Assertions A run-time assertion is a statement that tests for a specific condition that would indicate a logic-error has occurred during the execution of the
program. The important idea is that we are looking for conditions that should never occur during the execution of the program under any
circumstance. This is in contrast to a run-time error that while undesirable, may be unavoidable.
Assertions are often used to test or enforce function preconditions, postconditions and invariants.
Example:
/** @fn size_t strlen( const char* string )
@return Number of characters in string.
@param string [in] Address of a zero terminated string.
@note precondition: string is non-null. */
size_t strlen( const char* string ) {
assert( string != 0 ); // confirm precondition
const char* start = string;
while( *string )
++string;
return string - start;
}
Compile-time Assertions A compile-time assertion is a statement that test for a specific condition that would indicate that the code could not be compiled safely as the
platform cannot meet the expectations of the code.
Compile-time assertions are not implemented as a standard element of either the C or C++ languages. The boost library provides a decent
implementation. If boost is not an option, a compile-time (or static assertion) can easily be implemented with the following macro:
#define STATIC_ASSERT(e) 1/(e)
A false condition produces a constant divide-by-zero expression that will be trapped and reported by the compiler.
Example (boost):
#include <boost/static_assert.hpp>
C++ Programming Section 6
©1991 – 2016 Garth Santor & Trinh Hān GATS Encyclopaedia 51 of 278
int main() {
BOOST_STATIC_ASSERT( sizeof(unsigned) == 4 );
unsigned u = 0xA000FFFF;
The preceding code is dependent on unsigned variables being 32 bits and not 16 bits. The static assert will issue a compiler error if type unsigned
is not 4 bytes.
Best Practices We will define a best practice as the best possible way of doing a thing. Best practices may encompass coding style and idiom, documentation,
coding guidelines and in the extreme development processes such as Unified Process or Extreme Programming.
BOOST Use boost!
Boost provides free peer-reviewed portable C++ source libraries.
We emphasize libraries that work well with the C++ Standard Library. Boost libraries are intended to be widely useful, and usable across a broad spectrum of applications. The Boost license encourages both commercial and non-commercial use.
We aim to establish "existing practice" and provide reference implementations so that Boost libraries are suitable for eventual standardization. Ten Boost libraries are already included in the C++ Standards Committee's Library Technical Report (TR1) as a step toward becoming part of a future C++ Standard. More Boost libraries are proposed for the upcoming TR2.
– www.boost.org (December, 2005)
Boost originated with the C++ Standards Committee Library Working Group and has since opened participation to the C++ community at large.
All code accepted into boost is reviewed by the C++ community including those from the Standards Committee.
As of 2005, ten boost libraries had been accepted into TR1. You should not hesitate to use these libraries wherever they may help. These libraries
are:
Library Boost TR1
Tuple <boost/tuple.hpp> <tuple>
Smart Pointers <boost/weak_ptr.hpp>
<boost/shared_ptr.hpp>
<memory>
Array <boost/array.hpp> <array>
Unordered Associative Containers N/A <unordered_map>
<unordered_set>
Function object wrappers <boost/function.hpp> <functional>
Template function mem_fn <boost/mem_fn.hpp> <functional>
C++ Programming Section 6
©1991 – 2016 Garth Santor & Trinh Hān GATS Encyclopaedia 52 of 278
Reference wrapper <boost/ref.hpp> <functional>
Class template result_of <boost/result_of.hpp> <functional>
Function object binders <boost/bind.hpp> <functional>
Type Traits <boost/type_traits.hpp> <type_traits>
Random <boost/random.hpp> <random>
Regular expressions <boost/regex.hpp> <regex>
Utilities <boost/utility.hpp> <utility>
any
Use boost::any when: [K06]
You need to store values of heterogeneous types in containers.
Storage for unknown types is required.
Types are being passed through layers that need not know anything about the types.
Use boost::any_cast<T> when a casting failure is an error. This cast will throw the exception boost::bad_any_cast.
Use boost::any_cast<T *> when a casting failure is not an error. This cast will return a null pointer.
When storing pointers in boost::any store a smart pointer.
variant
Use boost::variant when: [K06]
You need to store values of heterogeneous types in containers.
Storage for known types is required.
Types are being passed through layers that need not know anything about the types.
Casts
boost::lexical_cast<T>
When to use lexical_cast [K06]:
For conversions from string types to numeric types.
For conversions from numeric types to string types.
For all lexical conversions that are supported by your user-defined types.
C++ Programming Section 6
©1991 – 2016 Garth Santor & Trinh Hān GATS Encyclopaedia 53 of 278
boost::numeric_cast<T>
When to use numeric_cast [K06]:
When assigning/comparing unsigned and signed types.
When assigning/comparing integral types of different types.
When assigning a function return type to a numeric variable, to protect against future changes to the function.
boost::polymorphic_cast<T>
When to use polymorphic_cast and dynamic_cast [K06] :
When a polymorphic cast failure is expected, use dynamic_cast<T*>. It makes it clear the failure is not an error.
When a polymorphic cast must succeed, use polymorphic_cast<T*>. It makes it clear the conversion failure is an error.
When performing polymorphic casts to reference types, use dynamic_cast<T&>.
boost::polymorphic_downcast<T>
When to use polymorphic_downcast [K06]:
If you are downcasting and need the speed of static_cast in release builds, use polymorphic_downcast; at least you’ll get assertions
for errors during testing.
If it’s not possible to cover all possible casts in testing, do not use polymorphic_downcast.
Smart Pointers
boost::intrusive_ptr
Use intrusive_ptr when [K06]:
You need to treat this as a smart pointer.
There is existing code that uses or provides an intrusive reference count.
It is imperative that the size of the smart pointer equals the size of a raw pointer.
boost::scoped_ptr
Use scoped_ptr when [K06]:
A pointer is used in a scope where an exception may be thrown.
There are several control paths in a function.
The lifetime of a dynamically allocated object can be limited to a specific scope.
C++ Programming Section 6
©1991 – 2016 Garth Santor & Trinh Hān GATS Encyclopaedia 54 of 278
Exception safety is important (always!)
boost::shared_ptr
Use shared_ptr when [K06]:
When there are multiple clients of an object, but no explicit owner.
When storing pointers in standard library containers.
When passing objects to and from libraries without (other) expressed ownership.
When managing resources that need special cleanup [with the help of custom deleters].
boost::weak_ptr
Use weak_ptr to [K06]:
Break cyclic dependencies
Use a shared resource without sharing ownership
Avoid dangling pointers
tuple
Use boost tuple whenever you would need to create a structure to combine data values, but do not need to create constructors or methods for the
structure.
Utility
BOOST_STATIC_ASSERT
Use BOOST_STATIC_ASSERT when [K06]:
A condition can be expressed at compile time.
Requirements on types are expressible at compile time.
You need to assert a relationship of two or more constant integral values.
boost::addressof
Use addressof when you must retrieve the actual address of an object, regardless of the semantics for operator&. [K06]
boost::checked_delete
Use checked_delete when you need to ensure that types are complete when calling delete. [K06]
C++ Programming Section 6
©1991 – 2016 Garth Santor & Trinh Hān GATS Encyclopaedia 55 of 278
boost::enable_if
[K06]
Use boost::enable_if when:
You need to add or remove a function to the overload set depending on some condition.
You need to add or remove a class template specialization from the set of specializations depending on some condition.
boost::noncopyable
Use boost::noncopyable when [K06]:
Copying and copy assignment of types is not allowed.
Prohibition of copying and assignment should be as explicit as possible.
Coding Style
Prefer compile- and link-time errors to run-time errors.
[SA04] § 14
Use const proactively.
[SA04] § 15
Avoid macros.
[SA04] § 16
Avoid magic numbers.
[SA04] § 17
Declare variables as locally as possible.
[SA04] § 18
Always initialize variables.
[SA04] § 19
Avoid long functions. Avoid deep nesting.
[SA04] § 20
C++ Programming Section 6
©1991 – 2016 Garth Santor & Trinh Hān GATS Encyclopaedia 56 of 278
Avoid initialization dependencies across compilation units.
[SA04] § 21
Minimize definitional dependencies. Avoid cyclic dependencies.
[SA04] § 22
Make header files self-sufficient.
[SA04] § 23
Always write internal #include guards. Never write external #include guards.
[SA04] § 24
Compiler / Environment
Compile cleanly at high warning levels.
[SA04] § 1
For Visual C++ use warning level 4.
Use an automated build system.
[SA04] § 2
Use either Visual Studio or make.
Use a version control system.
[SA04] § 3
Use one of:
Visual Source Safe
CVS
Perforce
Design
Give one entity one cohesive responsibility.
[SA04] § 5
C++ Programming Section 6
©1991 – 2016 Garth Santor & Trinh Hān GATS Encyclopaedia 57 of 278
Correctness, simplicity, and clarity come first.
[SA04] § 6
Know when and how to code for scalability.
[SA04] § 7
Don’t optimize prematurely.
[SA04] § 8
Don’t pessimize prematurely.
[SA04] § 9
Minimize global and shared data.
[SA04] § 10
Hide information.
[SA04] § 11
Know when and how to code for concurrency.
[SA04] § 12
Ensure resources are owned by objects. Use explicit RAII and smart pointers.
[SA04] § 13
Functions and Operators
Take parameters appropriately by value, (smart) pointer, or reference.
[SA04] § 25
Preserve natural semantics for overloaded operators.
[SA04] § 26
Prefer canonical forms of arithmetic and assignment operators.
[SA04] § 27
Prefer the canonical form of ++ and --. Prefer calling the prefix forms.
[SA04] § 28
C++ Programming Section 6
©1991 – 2016 Garth Santor & Trinh Hān GATS Encyclopaedia 58 of 278
Consider overloading to avoid implicit type conversions.
[SA04] § 29
Avoid overloading &&, ||, or , (comma).
[SA04] § 30
Don’t write code that depends on the order of evaluation of function arguments.
[SA04] § 31
Use boost::operators to implement operators where possible.
Boost::operators provides a complete set of comparison operators, arithmetic operators and operators for iterators. It will help you provide a
complete set of operators that behave consistently with established practices while minimizing the amount of code that you write.
Avoid using multiple inheritance when including multiple operator base-classes by employing their derived-from argument in the template
argument list.
Example:
class CMyClass :
boost::less_than_comparable< CMyClass, boost::equality_comparable<CMyClass> >
{
…
};
Class Design and Inheritance
Be clear what kind of class you’re writing.
[SA04] § 32
value class
base class
traits class
policy class
exception class
ancillary class
Prefer minimal classes to monolithic classes.
[SA04] § 33
C++ Programming Section 6
©1991 – 2016 Garth Santor & Trinh Hān GATS Encyclopaedia 59 of 278
Prefer composition to inheritance.
[SA04] § 34
Avoid inheriting from classes that were not designed to be base classes.
[SA04] § 35
Avoid inheriting from concrete base classes.
To add behaviour, prefer to add non-member functions instead of member functions.
To add state, prefer composition instead of inheritance.
Prefer providing abstract interfaces.
[SA04] § 36
Prefer to follow the Dependency Inversion Principle (DIP) that states:
High-level modules should not depend upon low-level modules. Rather, both should depend upon abstractions.
Abstractions should not depend upon details. Rather, details should depend upon abstractions.
Public inheritance is substitutability. Inherit, not to reuse, but to be reused.
[SA04] § 37
Object reuse is about reusing existing functions on new objects. Not new objects reusing base object code.
Practice safe overriding.
[SA04] § 38
An override can ask for less and provide more, but it must never require more or promise less because that would break the contract that was
promised to calling code.
You should only define an override that can fail if the base function can fail.
When overriding, never change default arguments.
Beware of inadvertently hiding overloads in the base class.
Consider making virtual functions non-public, and public functions nonvirtual.
[SA04] § 39
Avoid providing implicit conversions.
[SA04] § 40
By default, write explicit on single-argument constructors.
C++ Programming Section 6
©1991 – 2016 Garth Santor & Trinh Hān GATS Encyclopaedia 60 of 278
Use named functions that offer conversions instead of conversion operators.
Make data members private, except in behaviorless aggregates (C-style structs).
[SA04] § 41
Don’t give away your internals.
[SA04] § 42
Avoid returning handles to internal data managed by your class.
Pimpl judiciously.
[SA04] § 43
Declare a ‘forward declaration’ just before a smart pointer to the implementation.
Prefer writing nonmember nonfriend functions.
[SA04] § 44
Always provide new and delete together.
[SA04] § 45
If you provide any class-specific new, provide all of the standard forms (plain, in-place, and nothrow).
[SA04] § 46
Prefer the Barton-Nackman Trick to resolve cyclic dependencies in class inheritance chains.
http://en.wikipedia.org/wiki/Barton-Nackman
The Barton-Nackman Trick. [K-06]
Multiple Inheritance
1. Make all base classes of abstract classes virtual.
2. Try to give your abstract base classes default constructors.
3. If your class requires outside initialization, create a protected init() function that takes the appropriate parameters and does the initialization.
Note: Do only class specific initialization in the init() function; do not call any base class init() functions.
4. Create single-inheritance constructors that initialize all base classes and all local data members (i.e. those init() functions).
5. Create multiple-inheritance constructors that initialize only the data members of the class. The canonical form of such a constructor just calls
the init() function for the class itself.
[CUJ2006:Multiple Inheritance Considered Useful]
C++ Programming Section 6
©1991 – 2016 Garth Santor & Trinh Hān GATS Encyclopaedia 61 of 278
Construction, Destruction and Copying
Define and initialize member variables in the same order.
[SA04] § 47
Prefer initialization to assignment in constructors.
[SA04] § 48
Avoid calling virtual functions in constructors and destructors.
[SA04] § 49
Make base class destructors public and virtual, or protected and nonvirtual.
[SA04] § 50
Base classes, not concrete classes!
Destructors, deallocation, and swap never fail.
[SA04] § 51
Copy and destroy consistently.
[SA04] § 52
Write copy constructor, copy assignment and destructor together.
Explicitly enable or disable copying.
[SA04] § 53
Avoid slicing. Consider Clone instead of copying in base classes.
[SA04] § 54
Disable copying and implement a Clone function.
Prefer the canonical form of assignment.
[SA04] § 55
Don’t return const T&, this prevents T objects from being put into standard containers.
Whenever it makes sense, provide a no-fail swap (and provide it correctly).
[SA04] § 56
C++ Programming Section 6
©1991 – 2016 Garth Santor & Trinh Hān GATS Encyclopaedia 62 of 278
Namespaces and Modules
Keep a type and its nonmember function interface in the same namespace.
[SA04] § 57
Keep types and functions in separate namespaces unless they’re specifically intended to work together.
[SA04] § 58
Don’t write namespace usings in a header file or before an #include.
[SA04] § 59
Avoid allocating and deallocating memory in different modules.
[SA04] § 60
Don’t define entities with linkage in a header file.
[SA04] § 61
Don’t allow exceptions to propagate across module boundaries.
[SA04] § 62
Use sufficiently portable types in a module’s interface.
[SA04] § 63
Templates and Genericity
Blend static and dynamic polymorphism judiciously.
[SA04] § 64
Dynamic polymorphism is best at:
Uniform manipulation based on superset/subset relationships.
Static type checking.
Dynamic binding and separate compilation.
Binary interfacing.
Static polymorphism is best at:
Uniform manipulation based on syntactic and semantic interface.
C++ Programming Section 6
©1991 – 2016 Garth Santor & Trinh Hān GATS Encyclopaedia 63 of 278
Static type checking.
Static binding (prevents separate compilation).
Efficiency.
Customize intentionally and explicitly.
[SA04] § 65
To avoid providing points of customization unintentionally:
Put any helper functions your template uses internally into their own nested namespace, and call them with explicit qualification to disable ADL
Avoid depending on dependent names: … In short, when referring to any member of a dependent base class, always explicitly qualify with the base
class name or with this->, which you can think of just as a magical way of forcing all compilers to do what you actually want.
Don’t specialize function templates.
[SA04] § 66
You can’t specialize function templates partially, only totally.
Function template specializations never participate in overloading.
Don’t write unintentionally nongeneric code.
[SA04] § 67
Use != instead of < to compare iterators.
Prefer iterator to indexed access.
Use empty() instead of size() == 0.
Use the highest class in the hierarchy that offers the functionality you need.
Write const-correct code.
Prefer partial template specialization to complete template specialization.
Prefer member specialization to complete template specialization.
Error Handling and Exceptions
Assert liberally to document internal assumptions and invariants.
[SA04] § 68
C++ Programming Section 6
©1991 – 2016 Garth Santor & Trinh Hān GATS Encyclopaedia 64 of 278
Establish a rational error handling policy and follow it strictly.
[SA04] § 69
Ensure that your policy includes:
Identification: What conditions are errors.
Severity: How important or urgent each error is.
Detection: Which code is responsible for detecting the error.
Propagation: What mechanisms are used to report and propagate error notification within each module.
Handling: What code is responsible for doing something about the error.
Reporting: How the error will be logged or users notified.
Distinguish between errors and non-errors.
[SA04] § 70
An error is any failure that prevents a function from succeeding.
Violation of, or failure to achieve, a precondition.
Failure to achieve a postcondition.
Failure to reestablish an invariant.
Design and write error-safe code.
[SA04] § 71
Ensure that errors always leave your program in a valid state.
Prefer to guarantee that the final state is either the original state or the promised state.
Prefer to use exceptions to report errors.
[SA04] § 72
Exceptions can’t be silently ignored.
Exceptions propagate automatically.
Exception handling removes error handling and recovery from the main line of control flow.
Exception handling is better than the alternatives for reporting errors from constructors and operators.
Throw by value, catch by reference.
[SA04] § 73
C++ Programming Section 6
©1991 – 2016 Garth Santor & Trinh Hān GATS Encyclopaedia 65 of 278
Report, handle, and translate errors appropriately.
[SA04] § 74
Report errors at the point they are detected and identified as errors.
Handle or translate errors at the nearest level that can do it correctly.
Avoid exception specifications.
[SA04] § 75
STL Containers
Use vector by default. Otherwise, choose an appropriate container.
[SA04] § 76
Write for correctness, simplicity, and clarity first.
Write for efficiency only when and where necessary.
Prefer to write transactional, strongly error-safe code where reasonably possible, and don’t use invalid objects.
Use vector and string instead of arrays.
[SA04] § 77
Use vector (and string::c_str) to exchange data with non-C++ APIs.
[SA04] § 78
Store only values and smart pointers in containers.
[SA04] § 79
Prefer push_back to other ways of expanding a sequence.
[SA04] § 80
Prefer range operations to single-element operations.
[SA04] § 81
Use the accepted idioms to really shrink capacity and really erase elements.
[SA04] § 82
C++ Programming Section 6
©1991 – 2016 Garth Santor & Trinh Hān GATS Encyclopaedia 66 of 278
STL Algorithms
Use a checked STL implementation.
[SA04] § 83
Prefer algorithm calls to handwritten loops.
[SA04] § 84
Consider trying the Boost Lambda library, which automates the task of writing function objects.
Use the right STL search algorithm.
[SA04] § 85
For unsorted ranges: find/find_if and count/count_if.
For sorted ranges: binary_search, lower_bound, upper_bound, and equal_range.
Use the right STL sort algorithm.
[SA04] § 86
Make predicates pure functions.
[SA04] § 87
Don’t allow predicates to hold or access state that affects the result of their operator(), including both member and global state.
STL applies predicates in no particular order and copies them liberally.
Prefer function objects over functions as algorithm and comparer arguments.
[SA04] § 88
Comparers for associative containers must be function objects.
Function objects are adaptable and, counterintuitively, they typically produce faster code than functions.
Write function objects correctly.
[SA04] § 89
Design function objects to be values that are cheap to copy. Where possible, make them adaptable by inheriting from unary_function or
binary_function.
C++ Programming Section 6
©1991 – 2016 Garth Santor & Trinh Hān GATS Encyclopaedia 67 of 278
Type Safety
Avoid type switching; prefer polymorphism.
[SA04] § 90
Rely on types, not on representations.
[SA04] § 91
Avoid using reinterpret_cast.
[SA04] § 92
Avoid using static_cast on pointers.
[SA04] § 93
Avoid casting away const.
[SA04] § 94
Don’t use C-style casts.
[SA04] § 95
Don’t memcpy or memcmp non-PODs.
[SA04] § 96
Don’t use unions to reinterpret representation.
[SA04] § 97
Don’t use varargs (ellipsis).
[SA04] § 98
Don’t use invalid objects. Don’t use unsafe functions.
[SA04] § 99
Don’t treat arrays polymorphically.
[SA04] § 100
C++ Programming Section 6
©1991 – 2016 Garth Santor & Trinh Hān GATS Encyclopaedia 68 of 278
OpenMP
When to use OpenMP
[MSDN20-10]
Target platform is multicore or multiprocessor.
Application is cross-platform.
Parallelizable loops. Loops without loop-carried dependencies.
Last-minute optimizations needed.
String Manipulation
Use boost::regex to perform validation, searching and replacing.
[K-06]
Bit Manipulation
Largest unsigned number template <typename T> T maxUnsigned() { return ~T(0); }
Setting a bit
unsigned var = GetSomeValue();
unsigned int bitToSet = 3;
unsigned int mask = 1 << bitToSet;
var |= mask;
SetSomeValue( var );
Clearing a bit
unsigned var = GetSomeValue();
unsigned int bitToSet = 3;
unsigned int mask = ~(1 << bitToSet);
var &= mask;
SetSomeValue( var );
C++ Programming Section 6
©1991 – 2016 Garth Santor & Trinh Hān GATS Encyclopaedia 69 of 278
Multiplying, Dividing and Remainders
In the past the operations multiply, divide and modulus were relatively expensive compared to the bit-manipulating operations bit-shift-left, bit-
shift-right and bitwise-and.
Multiply by a power of two.
The left-shift operation performs a binary point shift the same way that multiplying by 10 performs a decimal place shift.
int i = 21;
i *= 8;
is equivalent to:
i <<= 3;
Works with true binary and 2’s complement values.
Divide by a power of two.
The right-shift operation performs a binary point shift the same way that dividing by 10 performs a decimal place shift. However, the remainder
part is thrown out.
int i = 384;
i /= 16;
is equivalent to:
i >>= 4;
Works with true binary and 2’s complement values.
Modulus by a power of two.
The bit-wise-and operation can be employed to compute remainders, where the divisor is a power of two. Essentially, we are looking for the
left-over bits that would have been shifted out by a right-shift which is all the bits below the power-of-two bit.
int i = 384;
i %= 16;
is equivalent to:
i &= 0x0f;
Works with true binary and 2’s complement values.
Today, most compilers will look for, and exploit these techniques where is there is a performance improvement to be had.
C++ Programming Section 6
©1991 – 2016 Garth Santor & Trinh Hān GATS Encyclopaedia 70 of 278
XOR swap
A pair of POD variables can be swapped in place without the need for an additional hold variable using a series of XORs.
#include <iostream>
using namespace std;
int main() {
int x = 42, y = 24;
cout << x << "," << y << endl;
x ^= y;
y ^= x;
x ^= y;
cout << x << "," << y << endl;
return 0;
}
Boost All things boost can be found at www.boost.org.
Auto Test (1.36.0)
The simplest example of boost’s auto unit test is:
#define BOOST_TEST_MODULE MyTests
#include <boost/test/unit_test.hpp>
BOOST_AUTO_TEST_CASE( first_test_case )
{
BOOST_CHECK( 1 == 1 ); // pass
BOOST_CHECK( 2 == 1 ); // fail
}
Installation of boost 1.61.0 for Visual Studio 2015
1. From the Boost website (http://www.boost.org/users/download/), download boost_1_61_0.7z
2. Extract the contents of these two files into a temporary folder (e.g. c:\tmp). You should see the folder: boost_1_61_0
3. Open a command shell in the boost_1_61_0 folder.
C++ Programming Section 6
©1991 – 2016 Garth Santor & Trinh Hān GATS Encyclopaedia 71 of 278
4. Enter the command, bootstrap
in the command shell.
5. Enter the command, b2 -–build-type=complete msvc install address-model=32
in the command shell.
5.1. Exception: Sometimes this setting doesn’t build the full set of libraries (usually it’s the static libraries that are missing). You can force
which of the two link models to use by adding the parameter ‘runtime-link=static’ or ‘runtime-link=shared’.
6. Wait a long time… Visual C++’s command line compiler and linker are invoked to compile all of the non-template code into linker-ready
libraries that can be directly included into your projects. This could take ½ hour or longer to complete depending on the speed of your processor
and disk system. A folder will be created in the root of your C: drive called Boost that will contain the INCLUDE and LIB directories.
7. Rename the folder from C:\Boost\lib to C:\Boost\x86.
8. [Optional 64-bit install]
8.1. Open a command shell in the boost_1_61_0 folder.
8.2. Enter the command, b2 -–build-type=complete msvc install address-model=64
in the command shell Configure Visual C++.
8.3. Rename the folder from C:\Boost\lib to C:\Boost\x64.
9. Create a folder called C:\Boost\lib. Move the folder(s) x86 (and x64) into the C:\Boost\lib folder.
10. Load Visual Studio 2015
11. Open any C++ project.
12. Open the property manager (select View → Property Manager)
13. Expand the property manager tree until you see the ‘Microsoft.Cpp.Win32.user’ item in the property manger’s tree view.
C++ Programming Section 6
©1991 – 2016 Garth Santor & Trinh Hān GATS Encyclopaedia 72 of 278
14. Right-click the ‘Microsoft.Cpp.Win32.user’ file and select ‘Properties’.
15. Select, “VC++ Directories” from the “Property Page”.
C++ Programming Section 6
©1991 – 2016 Garth Santor & Trinh Hān GATS Encyclopaedia 73 of 278
16. Edit the ‘Include Directories’ list to contain an entry for the boost include directory. Note that the convention is to write include directives with
the boost folder prefixed to the included header file.
#include <boost/shared_ptr.hpp>
Therefore add a path to the boost-1_61_0 directory. (e.g. c:\Boost\x86\include\boost-1_61_0).
17. Do the same for the “Library Directories”. This time, enter the exact directory containing the library files. (e.g. c:\Boost\x86\lib).
18. [Optional 64-bit library install]
18.1. Open an “x64” project and the repeat steps 14 through 19, substituting 64 for 32 where appropriate.
C++ Programming Section 6
©1991 – 2016 Garth Santor & Trinh Hān GATS Encyclopaedia 74 of 278
Installation of boost 1.45.0 for Visual Studio 2008
19. From the Boost website (http://www.boost.org/users/download/), download
19.1. boost-jam-3.1.18-1-ntx86.zip
19.2. boost_1_45_0.7z
20. Extract the contents of these two files into a temporary folder (e.g. c:\tmp). You should see two folders:
20.1. boost_1_45_0
20.2. boost-jam-3.1.18-1-ntx86
21. Copy the file bjam.exe from the folder boost-jam-3.1.18-1.ntx86 to the folder boost_1_45_0
22. You may delete the folder boost-jam-3.1.18-1.ntx86 if you wish.
23. Open a command shell in the boost_1_45_0 folder.
24. Enter the command "C:\Program Files\Microsoft Visual Studio 9.0\VC\bin\vcvars32.bat" (be certain to include the quotation marks) or
"C:\Program Files (x86)\Microsoft Visual Studio 9.0\VC\bin\vcvars32.bat" on 64-bit Windows. This will
make the C++ 9.0 command line compiler available to the command shell.
25. Enter the command, bjam --toolset=msvc-9.0 -–build-type=complete install
in the command shell.
26. Wait a long time… Visual C++’s command line compiler and linker are invoked to compile all of the non-template code into linker-ready
libraries that can be directly included into your projects. This could take ½ hour or longer to complete depending on the speed of your processor
and disk system. A folder will be created in the root of your C: drive called Boost that will contain the INCLUDE and LIB directories.
27. Rename the folder from C:\Boost to C:\x86.
28. [Optional 64-bit install]
28.1. Open a command shell in the boost_1_45 folder.
28.2. Enter the command"C:\Program Files\Microsoft Visual Studio 9.0\VC\vcvarsall.bat" x64 (be certain to include the quotation marks)
"C:\Program Files (x86)\Microsoft Visual Studio 9.0\VC\vcvarsall.bat" x64 on 64-bit Windows.
This will make the 64-bit compiler tools available to the command shell.
28.3. Enter the command, bjam --toolset=msvc-9.0 -–build-type=complete address-model=64 install
in the command shell Configure Visual C++.
C++ Programming Section 6
©1991 – 2016 Garth Santor & Trinh Hān GATS Encyclopaedia 75 of 278
28.4. Rename the folder from C:\Boost to C:\x64.
29. Create a folder called C:\Boost. Move the folder(s) x86 (and x64) into the C:\Boost folder.
30. Load Visual Studio 2008
31. Open the options dialog (select Tools → Options…)
32. Select the “Projects” folder, then the “VC++ Directories” subfolder.
33. Select, “Includes files” from the “Show directories for:” combo box.
34. Insert a new entry into the directories list.
C++ Programming Section 6
©1991 – 2016 Garth Santor & Trinh Hān GATS Encyclopaedia 76 of 278
35. Enter the location of the boost include files. Note that the convention is to write include directives with the boost folder prefixed to the included
header file.
#include <boost/shared_ptr.hpp>
Therefore add a path to the boost-1_45 directory. (e.g. c:\Boost\x86\include\boost-1_45).
36. Do the same for the “Library files” option of “Show directories for:”. This time, enter the exact directory containing the library files.
(e.g. c:\Boost\x86\lib)
37. [Optional 64-bit library install]
37.1. Select, “x64” option of “Platform” and repeat the previous steps for the include directory
c:\Boost\x64\include\boost-1_45 and the library directory c:\Boost\x64\lib.
C++ Programming Section 6
©1991 – 2016 Garth Santor & Trinh Hān GATS Encyclopaedia 77 of 278
38. Click, , “OK”.
Classes
Access Specifiers (Garth Santor, December 2006)
Access specifiers are keywords that indicate the visibility of members of a class, structure or union. The specifiers are public, protected and
private. Specifiers are applied to class, structure or union members or to inherited classes or structures1. A fourth, special-case specifier –
friend – can be applied to classes, functions or operators.
The access specifiers grant visibility to class members using the following rules.
Class members are private by default, structure and union members are public by default.
Class inheritance is private by default.
Class member is private
Class member is protected
Class member is public
Member is visible from outside class No No Yes Member is visible from inside same class Yes Yes Yes
Member is visible from inside derived class No Yes Yes Member is visible from friend class or function Yes Yes Yes
Class
inheritance is private
Class inheritance is protected
Class inheritance is public
Public base-class members are visible from outside class No No Yes
Public base-class members are visible from inside class Yes Yes Yes
Public base-class members are visible from derived class No Yes Yes
Public base-class members are visible from friend class or function Yes Yes Yes
Protected base-class members are visible from outside class No No No
Protected base-class members are visible from inside class Yes Yes Yes
Protected base-class members are visible from derived class No Yes Yes
Protected base-class members are visible from friend class or function Yes Yes Yes
Private base-class members are visible from outside class No No No
Private base-class members are visible from inside class No No No
Private base-class members are visible from derived class No No No
1 unions cannot be used as base classes.
C++ Programming Section 6
©1991 – 2016 Garth Santor & Trinh Hān GATS Encyclopaedia 78 of 278
Private base-class members are visible from friend class or function No No No
Example class A {
private: int a;
protected: int b;
public: int c;
};
void foo() {
A obj;
obj.a = 42; // error
obj.b = 42; // error
obj.c = 42; // ok
}
class B : public A {
public: void bar() {
a = 42; // error
b = 42; // ok
c = 42; // ok
};
Slurping and Binding Slurping and binding are terms used to describe how temporary objects are handled in operator assignment.
In the statement:
std::string V = a + b;
An object is created as a result of the addition operator. This temporary object is slurped into the variable V, and is then disposed of to complete
the statement. The important thing to note is that an object may be created and destroyed within this statement. Optimizing compilers will attempt
to eliminate this allocation/deallocation by assigning the result of the operator directly to the object that will hold the result.
In the statement:
std::string& R = a + b;
An object is created as a result of the addition operator. This temporary object is bound to the reference R, but is not disposed of at the end of the
statement. Instead the temporary object acquires the life-span of the binding reference R. Binding eliminates the extra allocation/deallocation that
occurs with slurping.
So why slurp? Binding is limited by the scope of the reference which is local. Slurping can be performed on variables that transcend local scope.
C++ Programming Section 6
©1991 – 2016 Garth Santor & Trinh Hān GATS Encyclopaedia 79 of 278
Coding Devices and Idioms
I/O Stream Pattern
The feof() function and .eof() method is a source of confusion in programmers new to C and C++. Languages like BASIC and Pascal report
end-of-file as true once the last character of the input stream has been read. C’s feof() function and C++’s .eof() method don’t report true
until an attempt has been made to read past the end of the input stream. This allows C/C++ programs to append input to the stream after the last
character has been processed. This difference has lead novice C/C++ programmers to write the following code, thinking it to be correct.
#include <iostream>
using namespace std;
int main() {
while( !cin.eof() ) {
double x;
cin >> x;
cout << x << endl;
}
return 0;
}
This leads to the last number read being output twice.
The eof() test must follow the input operation.
#include <iostream>
using namespace std;
int main() {
for( ;; ) {
double x;
cin >> x;
if( cin.eof() )
break;
cout << x << endl;
}
return 0;
}
This implementation is risky. It has the potential of becoming an infinite loop if the input stream contains a value that is not convertible to a
double; a word, for example. An infinite loop could also result from the remote case that input stream becomes utterly and unrecoverably corrupt.
The first case is detected with a call to the istream::fail() method and the second case by a call to the istream::bad() method.
Example:
#include <iostream>
C++ Programming Section 6
©1991 – 2016 Garth Santor & Trinh Hān GATS Encyclopaedia 80 of 278
using namespace std;
int main() {
for( ;; ) {
double x;
cin >> x;
if( cin.eof() || cin.fail() || cin.bad() )
break;
cout << x << endl;
}
return 0;
}
Of course this code is somewhat cumbersome. The three negative tests can be replaced with one positive test: istream::good().
#include <iostream>
using namespace std;
int main() {
for( ;; ) {
double x;
cin >> x;
if( !cin.good() )
break;
cout << x << endl;
}
return 0;
}
The C++ architects want us to constantly test if our input statements succeeded, so they provided a convenient casting operator that returns the
result of istream::good() whenever the istream object finds itself sitting in the position of an ‘if’ or loop conditional. Our code can be more
compactly written as:
#include <iostream>
using namespace std;
int main() {
for( ;; ) {
double x;
if( cin >> x )
cout << x << endl;
else
break;
}
return 0;
}
C++ Programming Section 6
©1991 – 2016 Garth Santor & Trinh Hān GATS Encyclopaedia 81 of 278
The code is now in a pattern in which input successes continue reads, input failures terminate reads. We can refactor this code into a simple while
loop.
#include <iostream>
using namespace std;
int main() {
double x;
while( cin >> x )
cout << x << endl;
return 0;
}
To discover whether the loop terminated on end-of-file or a failure, check the stream status after loop termination.
#include <iostream>
using namespace std;
int main() {
double x;
while( cin >> x )
cout << x << endl;
if( !cin.eof() ) {
cout << "Failure reading input" << endl;
return 1;
}
return 0;
}
C++ Programming Section 6
©1991 – 2016 Garth Santor & Trinh Hān GATS Encyclopaedia 82 of 278
Curiously Recurring Template Pattern (CRTP) It solves the problem of cyclic dependency by using templates. A base-class that needs to know about derived class accepts the base class
definition as a template argument.
class Derived : public Base<Derived> {
…
};
It is heavily used in boost’s operator library.
The Barton-Nackman Trick uses the CRTP.
References
http://en.wikipedia.org/wiki/Curiously_Recurring_Template_Pattern
Delegates Delegates are not intrinsic to standard C++, but a close facsimile can be manufactured using function pointers and member function pointers.
class A {
public:
A();
virtual ~A();
virtual void dfunc( int i );
static void sfunc( int i );
};
Function pointers are used to delegate for static member function.
void (*spDelegate)( int ); // declare
spDelegate = A::sfunc; // bind
(*spDelegate)( 42 ); // call
spDelegate( 42 ); // call
Member function pointers are used to delegate for normal member functions.
void (A::*pDelegate)(int); // declare
pDelegate = &A::dfunc; // bind
A a;
(a.*pDelegate)(42); // call
A* p = &a;
(p->*pDelegate)(42); // call from pointer
The function pointer looks good – it completely hides the name of the bound function and has a simple and elegant syntax. The member function
pointer also hides the name of the bound member function, but in the first form (.*) does not hide the object that the method is called upon. The
second form does manage to hide the host object, but has a complex syntax and requires two variables – an object pointer and a member function
pointer – for its implementation.
C++ Programming Section 6
©1991 – 2016 Garth Santor & Trinh Hān GATS Encyclopaedia 83 of 278
Hiding the implementation details
Obviously, we need to encapsulate these variables in a class. The class interface should be able to handle default construction, binding and
invoking as separate commands.
+bind(in pObj, in pmf)
+bind(in psf)
+operator ()(in x : float) : int
delegate
Such a class should allow us to write the following code:
class A
{
public:
A();
virtual ~A();
virtual int vfunc( float x ) { return (int)x; }
static int sfunc( float x ) { return (int)x*2; }
};
int main()
{
A a;
delegate d( &a, A::vfunc );
delegate dd;
dd.bind( &a, A::vfunc );
assert( 42 == d( 42.0 ) );
assert( 42 == dd( 42.0 ) );
d.bind( A::sfunc );
assert( 84 == d( 42.0 ) );
return 0;
}
A naïve implementation could be:
class delegate
{
public:
typedef int (A::*PMF)(float x);
delegate() : p_( 0 ), pmf_( 0 ), psf_( 0 ) { }
delegate( A* p, PMF pmf ) : p_( p ), pmf_( pmf ) { }
void bind( A* p, PMF pmf )
{
p_ = p;
pmf_ = pmf;
}
C++ Programming Section 6
©1991 – 2016 Garth Santor & Trinh Hān GATS Encyclopaedia 84 of 278
int operator () ( float x )
{
assert( p_ && pmf_ );
return (p_->*pmf_)(x);
}
private:
A* p_;
PMF pmf_;
};
This implementation has several problems, the first being that is doesn’t handle static member functions. This can be easily fixed:
class delegate
{
public:
typedef int (*PSF)(float x);
typedef int (A::*PMF)(float x);
delegate() : p_( 0 ), pmf_( 0 ), psf_( 0 ) { }
delegate( A* p, PMF pmf ) : p_( p ), pmf_( pmf ), psf_( 0 ) { }
delegate( PSF psf ) : p_( 0 ), pmf_( 0 ), psf_( psf ) { }
void bind( A* p, PMF pmf )
{
p_ = p;
pmf_ = pmf;
psf_ = 0;
}
void bind( PSF psf )
{
p_ = 0;
pmf_ = 0;
psf_ = psf;
}
int operator () ( float x )
{
assert( (p_ && pmf_) || psf_ );
if( p_ )
return (p_->*pmf_)(x);
return (*psf_)( x );
}
private:
A* p_;
PMF pmf_;
PSF psf_;
};
Clearly we can see that there are two distinct implementations of the delegate – one for member functions and one for static functions. The bridge
pattern can solve this problem.
C++ Programming Section 6
©1991 – 2016 Garth Santor & Trinh Hān GATS Encyclopaedia 85 of 278
+bind(in pObj, in pmf)
+bind(in psf)
+operator()(in x : float) : int
delegate
+operator()(in x : float) : int
«interface»
delegate_impl
1
-impl
1
+ctor(in psf)
+operator()(in x : float) : int
-psf
delegate_static_impl
+ctor(in pObj, in pmf)
+operator()(in x : float) : int
-pObj
-pmf
delegate_dynamic_impl
+somefunc(in x : float) : int
SomeClass 1
-pObj
1
The delegate implementation classes can be nested inside the delegate class itself:
class delegate
{
struct delegate_impl {
virtual ~delegate_impl() { }
virtual int operator () ( float x ) = 0;
};
struct delegate_dynamic_impl : public delegate_impl {
typedef int (A::*PMF)(float x);
delegate_dynamic_impl( A* p, PMF pmf ) : p_( p ), pmf_( pmf ) { }
int operator () (float x) { return (p_->*pmf_)(x); }
A* p_;
PMF pmf_;
};
struct delegate_static_impl : public delegate_impl {
typedef int (*PSF)(float x);
delegate_static_impl( PSF psf ) : psf_( psf ) { }
int operator () (float x) { return (*psf_)(x); }
PSF psf_;
};
public:
delegate() : pdelegate_( 0 ) { }
delegate( A* p, delegate_dynamic_impl::PMF pmf ) :
pdelegate_( new delegate_dynamic_impl( p, pmf ) ) { }
delegate( delegate_static_impl::PSF psf ) :
pdelegate_( new delegate_static_impl( psf ) ) { }
void bind( A* p, delegate_dynamic_impl::PMF pmf ) {
pdelegate_.reset( new delegate_dynamic_impl( p, pmf ) );
}
void bind( delegate_static_impl::PSF psf ) {
pdelegate_.reset( new delegate_static_impl( psf ) );
C++ Programming Section 6
©1991 – 2016 Garth Santor & Trinh Hān GATS Encyclopaedia 86 of 278
}
int operator () ( float x ) {
assert( pdelegate_.get() ) ;
return (*pdelegate_)(x);
}
private:
std::auto_ptr<delegate_impl> pdelegate_;
};
Now we need to parameterize this class so that it will work with more than just objects of class A.
+bind(in pObj, in pmf)
+bind(in psf)
+operator()(in x : float) : int
delegate
RET, PAR
*
-impl
1
+ctor(in psf)
+operator()(in x : PAR) : RET
-psf
delegate_static_impl
RET, PAR
+ctor(in pObj : CLASS*, in pmf)
+operator()(in x : PAR) : RET
-pObj : CLASS*
-pmf
delegate_dynamic_impl
RET, PAR, CLASS
+somefunc(in x : float) : int
SomeClas 1
-pObj
1
+operator()(in x : PAR) : RET
-nRef
delegate_imp
RET, PAR
SomeClass delegate impl
«bind»(int,float,SomeClass)
Another use feature is to implement reference counting for delegate_impl. This reduces the amount of dynamic memory allocations when
delegates are copied.
Additional operators that can be implemented in delegate:
operator =
operator ==
operator !=
operator !
operator bool
C++ Programming Section 6
©1991 – 2016 Garth Santor & Trinh Hān GATS Encyclopaedia 87 of 278
Multicasting
Delegates are often implemented so as to support the invocation of multiple functions/methods. This delegate type we’ll call a multicast delegate.
The only new operation required by a multicast delegate is an add operation (often implemented with operator +=). Many functions need to
be reengineered to accommodate the multicast delegate implementation. Fortunately, the bridge pattern can accommodate the multicast delegate
as a specialization of delegate_impl.
+bind(in pObj, in pmf)
+bind(in psf)
+operator()(in x : float) : int
+add(in psf)
+add(in pObj, in pmf)
+add(in delegate)
delegate
RET, PAR
*
-impl
1
+ctor(in psf)
+operator()(in x : PAR) : RET
-psf
delegate_static_impl
RET, PAR
+ctor(in pObj : CLASS*, in pmf)
+operator()(in x : PAR) : RET
-pObj : CLASS*
-pmf
delegate_dynamic_impl
RET, PAR, CLASS
+somefunc(in x : float) : int
SomeClass 1
-pObj
1
+operator()(in x : PAR) : RET
+isMulticast() : bool
-nRef
delegate_imp
RET, PAR
SomeClass delegate impl
«bind»(int,float,SomeClass,,,)
+operator()(in x : PAR) : RET
multicast_delegate
RET, PAR
*
*
The greatest short-coming of this design is that templates don’t handle variable-length argument lists with any grace. Therefore, you’ll need to
implement a version for void functions, one for single-parameter functions, another for two-parameter functions, and so on.
Duff’s Device Duff’s device was invented by Lucasfilm developer Tom Duff who in 1983 need to solve a performance issue involving a loop. The bottleneck
occurred due to the overhead of the looping mechanism in the language.
The standard way of unrolling a loop takes original code like:
for( int i = 0; i < numOut; ++i )
*pDest++ = *pSource++;
C++ Programming Section 6
©1991 – 2016 Garth Santor & Trinh Hān GATS Encyclopaedia 88 of 278
And replaces it with:
int numLoops = numOut / 8;
for( int i = 0; i < numLoops; ++i ) {
*pDest++ = *pSrc++;
*pDest++ = *pSrc++;
*pDest++ = *pSrc++;
*pDest++ = *pSrc++;
*pDest++ = *pSrc++;
*pDest++ = *pSrc++;
*pDest++ = *pSrc++;
*pDest++ = *pSrc++;
}
for( int i = 0; i < numOut % 8; ++i ) {
*pDest++ = *pSrc++;
}
The remaining writes are handled by the second loop.
Duff’s Device consolidates the two loops by the clever combining of a do-while loop and a switch statement. Giving:
int numLoops = (numOut + 8 – 1) / 8;
switch( numOut % 8 ) {
case 0: do { *pDest++ = *pSrc++;
case 7: *pDest++ = *pSrc++;
case 6: *pDest++ = *pSrc++;
case 5: *pDest++ = *pSrc++;
case 4: *pDest++ = *pSrc++;
case 3: *pDest++ = *pSrc++;
case 2: *pDest++ = *pSrc++;
case 1: *pDest++ = *pSrc++;
} while( --numLoops > 0 );
}
Note that Duff’s Device has one critical flaw?
It doesn’t numOut == 0. It gives 8 outputs instead. This is easily corrected by an enclosing if-statement. However, the zero-case is rare enough
that we don’t require it to be written with all implementations of the device.
Ralph Holly published an excellent C++-macro implementation of Duff’s Device in Dr. Dobbs Journal, August 2005 – Embedded Systems.
Functors Functors in C++ are implemented by overloading the function call operator – operator ().
C++ Programming Section 6
©1991 – 2016 Garth Santor & Trinh Hān GATS Encyclopaedia 89 of 278
In this example a vector will be populated with the Fibonacci sequence. A functor is used as the generator argument to the STL algorithm
std::generate().
#include <algorithm>
#include <iostream>
#include <vector>
using namespace std;
/** @class template <typename NUMBER_T> class CFibonacciSequence
@brief Produces a sequence of numbers that follow a linear progression. */
template <typename NUMBER_T> class CFibonacciSequence {
private:
NUMBER_T m_value; //< The current value in the sequence
NUMBER_T m_previous; //< The previous value in the sequence
public:
/** @fn FibonacciSequence()
@brief constructor */
CFibonacciSequence() : m_value( 1 ), m_previous( 0 ) { }
/** @fn NUMBER_T operator() ()
@brief Function operator
@return the current value in the sequence
@note Calculates and stores the next value in the sequence. */
NUMBER_T operator() ()
{
NUMBER_T next = m_value + m_previous;
m_previous = m_value;
m_value = next;
return m_previous;
}
};
int main() {
vector<unsigned> sequence(16);
generate( sequence.begin(), sequence.end(), CFibonacciSequence<unsigned>() );
copy( sequence.begin(), sequence.end(), ostream_iterator<unsigned>( cout, " " ) );
return 0;
}
Transactional Programming See Programming Concepts: Transactional Programming Styles for an overview.
The issue of rolling back nested transactions has been explored by Calum Grant of Sophos Plc. He has implemented a transaction-based approach
to the standard template library containers that have the capability to rollback any number of nested operations on individual variables or
containers.
http://calumgrant.net/atomic/
C++ Programming Section 6
©1991 – 2016 Garth Santor & Trinh Hān GATS Encyclopaedia 90 of 278
Dangerous Coding Practices Every programming language has its perils, pitfalls, hazards and dangerous practices. The C language has been described as the rope with which
you will eventually hang yourself – C++ as the rope that is long enough to hang yourself and still have enough left over to hang the rest of your
project team!
operator T* Casting operators that create an implicit cast a pointer are dangerous since they can be invoked by the delete command. The delete will delete
what the cast operator exposes not the object as expected.
class Foo {
char * pOwnedByFoo_;
public:
~Foo () { delete pOwnedByFoo_; }
operator const char * () { return pOwnedByFoo_; }
};
void func() {
Foo bar;
…
delete bar; // bar.pOwnedByFoo_ deleted through cast operator
} // bar.pOwnedByFoo_ deleted by destructor
Raw Pointers Using raw pointers to manage dynamic memory (see Memory Management: Memory Leaks)
C++ Programming Section 6
©1991 – 2016 Garth Santor & Trinh Hān GATS Encyclopaedia 91 of 278
Memory Management
Memory Layout
Operating System
Heap
Data
Code
Interrupt Vector Table
Stack
0GiB
4GiB
2GiB
{local variables}
{dynamic variables (new/delete)}
{global & static variables}
{litterals}
Memory Leaks A memory leak is a block of dynamically allocated memory that can no longer be released by the owning process resulting in a loss of usable
memory blocks.
The most common source of memory leaks in C/C++ are:
Failing to deallocate memory blocks at end of scope.
Failing to deallocate memory blocks before over-writing the owning pointer.
Example void function( void ) {
A* p = new A;
int* q = new int [512];
C++ Programming Section 6
©1991 – 2016 Garth Santor & Trinh Hān GATS Encyclopaedia 92 of 278
…
q = new int [256]; // q:512 leaks - overwrite
delete [] q;
} // p leaks – object of class A not deallocated
How big a problem? The most common problem caused by memory leaks is degraded performance due to insufficient memory. When the memory demand of the
application’s working set exceeds the amount of available RAM, the operating system must resort to continually swapping the working set in and
out of RAM (thrashing).
In practice, small memory leaks are common-place and often harmless. The virtual memory system of modern operating systems will reclaim the
‘leaked’ memory when the application (and related virtual machine) is terminated. Applications that run for short periods of time or leak memory
at very low rates can often pass without notice.
More serious leak scenarios include:
Where the O/S does not automatically release memory on application termination. This is more common on older operating systems like
the Amiga OS.
Where an application runs for longer periods, such as server applications and embedded programs (switches, consumer electronics).
Where memory allocations are frequent, such as real-time simulations and computer games.
Where the leak occurs inside the operating system, device drivers, or resident applications like virus scanners.
Where program termination doesn’t require memory deallocation, such as with shared memory.
Leave Avoidance The two most common methods for avoiding memory leaks both involve abandoning the use of raw pointers to manage dynamic memory.
One of the most common reasons to use dynamic memory is to allocate an array whose size will not be known until run-time.
void function() {
unsigned size;
cin >> size;
int* array = new [ size ];
…
delete [] array;
}
This code can easily be replaced by an STL vector.
void function() {
unsigned size;
cin >> size;
std::vector<int> array(size);
…
} // ~vector<int> automatically called.
C++ Programming Section 6
©1991 – 2016 Garth Santor & Trinh Hān GATS Encyclopaedia 93 of 278
The vector solution has the added benefit of being exception safe. If the function terminates on an exception, the delete command from the first
function will not be executed. The vector destructor will execute!
The other approach is to use smart pointers such as those provided by the BOOST library. Replace:
void function( void ) {
A* p = new A;
…
delete p;
}
With:
void function( void ) {
boost::scoped_ptr<A> p( new A );
…
} // destructor deallocates object
Currently (2008), BOOST’s shared_ptr<> has been accepted into Technical Report 1 of the upcoming C++ Standard. It is found in
<memory> as std::tr1::shared_ptr<>.
Leak Detection While leak avoidance is a good strategy, it does not eliminate leaks. They may still occur and therefore we need a technology for detecting
memory leaks. There is no standard technology in C or C++ to do this, but there are many products available that can. The biggest problem
though, is that the solutions tend to be compiler or platform specific.
Multiplatform
Rational (IBM) Purify (Windows, Linux & Unix) – memory debugger and code library.
Parasoft Insure++ (Windows, Linux & Unix) – a competitor to Purify.
Memwatch (ANSI C) – a portable C-library (with source) for memory tracking and execution tracing.
M-Patrol by Graeme Roy (Windows, Linux, Unix, Amiga) – memory tracking library.
Linux
Valgrind – originally a GPL implementation of Purify. It has grown to a general debugging tool.
Electric Fence by Bruce Perens – memory tracking library.
Checker by Tristan Gingold – memory tracking library with a modified compiler back end.
Windows
CRTDBG – Microsoft’s memory tracking library that integrates and ships with Visual Studio.
C++ Programming Section 6
©1991 – 2016 Garth Santor & Trinh Hān GATS Encyclopaedia 94 of 278
Microsoft’s CRTDBG Library Microsoft’s CRTDBG library provides memory leak tracking facilities that are easily accessible via Visual Studio.
Enabling Leak Checking Add the following code at the top of main()...
#include <crtdbg.h>
int main() {
#ifndef NDEBUG
int tmpFlag = _CrtSetDbgFlag( _CRTDBG_REPORT_FLAG );
// Turn On (OR) - Keep freed memory blocks in the
// heap's linked list and mark them as freed
tmpFlag |= _CRTDBG_DELAY_FREE_MEM_DF;
tmpFlag |= _CRTDBG_LEAK_CHECK_DF;
// Turn Off (AND) - prevent _CrtCheckMemory from
// being called at every allocation request
tmpFlag &= ~_CRTDBG_CHECK_ALWAYS_DF;
// Set the new state for the flag
_CrtSetDbgFlag( tmpFlag );
#endif
This will display a report of leaked memory blocks to the output window in Visual Studio.
Detected memory leaks!
Dumping objects ->
{121} normal block at 0x00194D40, 100 bytes long.
Data: < > CD CD CD CD CD CD CD CD CD CD CD CD CD CD CD CD
Object dump complete.
It will also delay the return of freed memory blocks to OS. This can be useful in stress testing and it also guarantees that all memory allocations
are new allocations (data block is initialized to 0xCD).
Enhancing identification The memory block that leaked can be difficult to detect from its hex dump. To help identify objects in the memory dump, we can place
descriptive text.
class Base {
#ifndef NDEBUG
char m_tag[100];
#endif
public:
Base() {
#ifndef NDEBUG
strcpy( m_tag, "Base class" );
#endif
C++ Programming Section 6
©1991 – 2016 Garth Santor & Trinh Hān GATS Encyclopaedia 95 of 278
cout << "def ctor" << endl;
}
~Base() { cout << "dtor" << endl; }
void msg() { cout << "msg()" << endl; }
};
The text – “Base class” – will now appear in the debug window memory dump.
Detected memory leaks!
Dumping objects ->
{121} normal block at 0x00B54D40, 100 bytes long.
Data: <Base class > 42 61 73 65 20 63 6C 61 73 73 00 CD CD CD CD CD
Object dump complete.
Preprocessor
Macros Macros perform (more-or-less intelligent) source code substitution prior to compilation. Macro substitutions are performed by the preprocessor.
The macro preprocessor was inherited from C and is often used for a purpose that is appropriate for C, but not for C++.
Macros as constants #define NSIZE 42
Substitutes the literal ‘42’ for the word NSIZE as in the statement:
int a[NSIZE];
This is unnecessary in C++ as a constant declaration would work while providing type checking.
int NSIZE = 42;
Macros as functions #define max(a,b) ((a)>(b)?(a):(b))
Substitutes the literal expression for the mnemonic ‘max’ as in the statement:
int c = max(a,b);
The problem with this substitution is that it does not type-check the parameters. In C++, use a template instead.
template <typename T> T& max( T& a, T& b) { return a > b ? a : b; }
Sloppy function macros can lead to unusual and hard to detect failures.
#define F(a,b) a + b
int c = F(a,b) * 3; which expands to:
int c = a + b * 3;
C++ Programming Section 6
©1991 – 2016 Garth Santor & Trinh Hān GATS Encyclopaedia 96 of 278
Clearly, unintended!
Useful macros… The ‘#’ operator converts token following to a string.
#define F(expr) cout << #expr << " = " << expr << endl;
F(a + b); expands to:
cout << "a + b" << " = " << a + b << endl;
The ‘##’ operator concatenates two tokens.
#ifdef UNICODE
#define T(str) L##str
#else
#define T(str) str
#endif
The ‘UNICODE’ version of the macro prepends an L to indicate the string literal is a UNICODE string.
T("Hello") expands to L"Hello" for a UNICODE build and to "Hello" for a standard build.
The preprocessor also defines useful macros such as __LINE__ that is replaced by the source code line number being compiled, __FILE__ that
is replaced by the name of the file being compiled and __FUNCTION__ that is replaced by the name of the function being compiled. Examine
your compiler documentation for other predefined macros.
Conditional compilation Arguably, the most useful macro in C/C++ is the assert() macro. A simple implementation of assert could be:
#ifdef NDEBUG
#define assert(cond)
#else
#define assert(cond) \
if(cond == false) {\
cerr << #cond " failed in " __FILE__ " at line " << __LINE__ << endl;\
exit(1);\
}
#endif
which is effectively stripped from release builds, but compiled into debug builds.
References
[STRO2000]
C++ Programming Section 6
©1991 – 2016 Garth Santor & Trinh Hān GATS Encyclopaedia 97 of 278
STL
Which container do I use? The answer, of course, is that it depends on what I am using the container for. Each container has strength and weaknesses that we must consider.
vector list stack queue dequeue map multimap set Multiset
Find O(n) O(n) n/a n/a n/a O( log n ) O( log n ) O( log n ) O( log n )
Find - sorted O( log n ) O(n) n/a n/a n/a O( log n ) O( log n ) O( log n ) O( log n )
Insert O(n) O(1) n/a n/a n/a O( log n ) O( log n ) O( log n ) O( log n )
Delete O(n) O(1) n/a n/a n/a O( log n ) O( log n ) O( log n ) O( log n )
Sort O( logn n ) O( logn n ) n/a n/a n/a O(1)* O(1)* O(1)* O(1)*
push_front O(n) O(1) n/a n/a O(1) n/a n/a n/a n/a
pop_front O(n) O(1) n/a n/a O(1) n/a n/a n/a n/a
push_back O(1) O(1) n/a n/a O(1) n/a n/a n/a n/a
pop_back O(1) O(1) n/a n/a O(1) n/a n/a n/a n/a
push / enqueue n/a n/a O(1) O(1) n/a n/a n/a n/a n/a
pop / dequeue n/a n/a O(1) O(1) n/a n/a n/a n/a n/a
* always sorted
Templates
Template Programming Techniques The following techniques employ C++’s template mechanism to solve various programming problems.
Parameterizing method virtualization Whether a method is polymorphic can be determined by a template parameter. In C++ a method is made polymorphic by prefixing the method
declaration with the keyword ‘virtual’ and once polymorphic, always polymorphic. The ‘virtual’ keyword is not needed in derived classes.
Consider the classes:
class Base {
C++ Programming Section 6
©1991 – 2016 Garth Santor & Trinh Hān GATS Encyclopaedia 98 of 278
public:
void foo() {}
};
And the class:
class VBase {
public:
virtual void foo() {}
};
The choice of base class – Base or VBase – will determine whether method foo() is polymorphic within the class hierarchy. We can make this
choice compile-time selectable with the template class:
template <class BASETYPE>
class Derived : public BASETYPE {
public:
void foo();
};
We can then choose a non-polymorphic implementation with the declaration:
Derived<Base> nonPolymorphic;
Or a polymorphic implementation with the declaration:
Derived<VBase> polymorphic;
Database Section 7
©1991 – 2016 Garth Santor & Trinh Hān GATS Encyclopaedia 99 of 278
Database
Data Normalization Data normalization is a data modelling technique that improves the quality of a database and is a theory that defines the properties of relations.
Normalization can reduce data duplication which intern improves storage efficiency and increases reliability.
Concept: Functional Dependency
Functional dependency is a relation between attributes of a class. Specifically, it indicates that the value of one attribute is directly determined by
another.
For example: in an inventory database the product name is functionally dependent on the product code. In other words, ‘if we know the product
code we can uniquely determine the product name.’
Functional dependency can be in one direction or both. When functional dependency runs in both directions (i.e. A B and B A) we call the
relationship a 1-to-1 relationship. When it runs in one direction (i.e. A B only) we call the relation a 1-to-many relationship. No functional
dependency indicates a many-to-many relationship.
Normal Forms
Normal forms specify the ‘rules’ for relationships between table attributes.
First (1NF), second (2NF) and third (3NF) normal forms were identified by E. F. Codd. Boyce-Codd (BCNF), fourth (4NF) and fifth (5NF) were
added in later research. Each form is wholly contained within its preceeding, simpler form. The containment relationship is 1NF 2NF 3NF
BCNF 4NF 5NF.
In 1981, a seventh normal form was discovered, domain/key normal form (DK/NF). This normal form eliminates modification anomalies, but is
difficult to convert relation into this form.
First Normal Form (1NF)
According to Codd...
A relation is in first normal form if and only if all columns are single valued (null attributes not allowed).
Or: Each record as the same number of fields.
Or: Each row has the same number of columns.
Database Section 7
©1991 – 2016 Garth Santor & Trinh Hān GATS Encyclopaedia 100 of 278
According to Chris Date...
A relation is in first normal form if and only if it is isomorphic to some relation, or:2
1. There is no top-to-bottom ordering to the rows.
2. There is no left-to-right ordering to the columns.
3. There are no duplicate rows.
4. Every row-column intersection contains exactly one value from the applicable domain (and nothing else).
5. All columns are regular [i.e. rows have no hidden components such as row IDs, object IDs, or common timestamps].
Example of tables violating 1NF
User
User ID Name Email
100 Phil Alain [email protected]
101 Sue Coleman [email protected], [email protected]
102 Tom Thomson [email protected]
103 Danièle Rochon [email protected]
This table violates 1NF by storing multiple email addresses for Sue Coleman.
User
User ID Name Email
100 Phil Alain [email protected]
101 Sue Coleman [email protected]
102 Tom Thomson [email protected]
103 Danièle Rochon [email protected]
This table violates 1NF by storing an array (or table) of values for the email addresses of Sue Coleman.
User
User ID Name Email 1 Email 2 Email 3
100 Phil Alain [email protected]
101 Sue Coleman [email protected] [email protected]
102 Tom Thomson [email protected]
103 Danièle Rochon [email protected]
This table violates 1NF by having null fields.
2 Chris Date, “What First Normal Form Really Means”, pp 127-8 http://www.dbdebunk.com/page/page/629796.htm
Database Section 7
©1991 – 2016 Garth Santor & Trinh Hān GATS Encyclopaedia 101 of 278
Problems
1. Searches are more complex – they must check for multiple matches in the field. A straight pattern match won’t be sufficient.
2. Records are variable sizes – making the database more difficult to optimize (how much space should be reserved for new records?)
3. Space is wasted – many fields with be left empty.
Solution = 1NF
User Name
User ID Name
100 Phil Alain
101 Sue Coleman
102 Tom Thomson
103 Danièle Rochon
User email
User ID Email
Second Normal Form (2NF)
Terminology – Candidate Key
A candidate key is set of record attributes that can uniquely and completely identify a database record. A given table may have one or more
candidate keys. Typically, one of the candidate keys is chosen as the primary key of the table.
User
First Name Surname Email
Phil Alain [email protected]
Sue Coleman [email protected]
Tom Thomson [email protected]
Sue Thomson [email protected]
Danièle Rochon [email protected]
In this table neither the first name nor the surname uniquely identifies a record. The candidate key of the first name + surname does uniquely
identify a record.
Database Section 7
©1991 – 2016 Garth Santor & Trinh Hān GATS Encyclopaedia 102 of 278
Definition
A table is in second normal form if-and-only-if it is in first normal form and none of its non-prime attributes (fields) are functionally dependant on
just part of a candidate key.
Corollary: a table in first normal form without a candidate is automatically in second normal form.
Example
User
Name Account Types Email
Phil Alain Standard [email protected]
Sue Coleman Standard [email protected]
Sue Coleman Power User [email protected]
Sue Coleman Administrator [email protected]
Tom Thomson Standard [email protected]
Tom Thomson Power User [email protected]
Danièle Rochon Standard [email protected]
This table violates 2NF by since it has a candidate key (name + account type) and the email attribute is functionally dependant on the name but not
the account type.
Problems
1. Wasted space – data is repeated. The same email address is stored in more than one record.
2. Data integrity – if a user’s email is changed, multiple records need be updated.
Solution = 2NF
User Account Type
Name Account Types
Phil Alain Standard
Sue Coleman Standard
Sue Coleman Power User
Sue Coleman Administrator
Tom Thomson Standard
Tom Thomson Power User
Danièle Rochon Standard
User Email
Name Email
Phil Alain [email protected]
Database Section 7
©1991 – 2016 Garth Santor & Trinh Hān GATS Encyclopaedia 103 of 278
Sue Coleman [email protected]
Tom Thomson [email protected]
Danièle Rochon [email protected]
Third Normal Form (3NF) A table is in third normal form if-and-only-if the relation is in second normal form and every non-prime attribute of the table is directly dependant
on every key of the table.
Example
PGA Tour Winners
Tournament Date Winner Winner Date of Birth
Memorial Tournament May 28, 2008 Kenny Perry August 10, 1960
Mercedes-Benz Championship Jan 11, 2009 Geoff Ogilvy June 11, 1977
Sony Open – Hawaii Jan 18, 2009 Zach Johnson Feb 24, 1976
Bob Hope Classic Jan 25, 2009 Pat Perez March 1, 1976
FBR Open Feb 1, 2009 Kenny Perry August 10, 1960
The Tournament + Date is the candidate key for the table.
This table violates 3NF by since the Winner Date of Birth is only transitively dependant on the candidate key. The Winner Date of Birth is
dependent on the Winner which is in turn dependent on the candidate key.
Problems
1. Wasted space – values in the Winner Date of Birth are repeated.
2. Data integrity – if a Winner Date of Birth value needs to be corrected, multiple records need be corrected.
Solution = 3NF
PGA Tour Winners
Tournament Date Winner
Memorial Tournament May 28, 2008 Kenny Perry
Mercedes-Benz Championship Jan 11, 2009 Geoff Ogilvy
Sony Open – Hawaii Jan 18, 2009 Zach Johnson
Bob Hope Classic Jan 25, 2009 Pat Perez
FBR Open Feb 1, 2009 Kenny Perry
Winners Date of Birth
Winner Winner Date of Birth
Kenny Perry August 10, 1960
Database Section 7
©1991 – 2016 Garth Santor & Trinh Hān GATS Encyclopaedia 104 of 278
Geoff Ogilvy June 11, 1977
Zach Johnson Feb 24, 1976
Pat Perez March 1, 1976
Forth Normal Form (4NF)
A table is in fourth normal form if-and-only-if, for every one of its non-trivial multivalued dependencies XY, X is either a candidate key or a
superset thereof.
Example
Pizza Delivery Permutations
Restaurant Variety Delivery Area
Dominos Thick Crust North
Dominos Thick Crust Central
Dominos Thick Crust East
Dominos Stuffed Crust North
Dominos Stuffed Crust Central
Dominos Stuffed Crust East
Little Caesar’s Thin Crust East
Little Caesar’s Stuffed Crust East
Pizza Pizza Thick Crust North
Pizza Pizza Thick Crust Central
Pizza Pizza Thin Crust North
Pizza Pizza Thin Crust Central
All fields are part of a candidate key – therefore automatically 3NF.
Problems
1. Data redundancy – repeated values, multiple updates.
Solution = 4NF
Varieties by Restaurant
Restaurant Variety
Dominos Thick Crust
Dominos Stuffed Crust
Little Caesar’s Thin Crust
Little Caesar’s Stuffed Crust
Pizza Pizza Thick Crust
Pizza Pizza Thin Crust
Database Section 7
©1991 – 2016 Garth Santor & Trinh Hān GATS Encyclopaedia 105 of 278
Delivery Area by Restaurant
Restaurant Delivery Area
Dominos North
Dominos Central
Dominos East
Little Caesar’s East
Pizza Pizza North
Pizza Pizza Central
Data Structures Section 8
©1991 – 2016 Garth Santor & Trinh Hān GATS Encyclopaedia 106 of 278
Data Structures Data structures are organizational patterns for data storage that describe the relationship
between element locations, size and reference information.
Example: An array stores elements in contiguous memory where an index indicates the offset of a given element from the beginning of the block
of memory.
Set The collection of things called elements. This concept forms the basis and set theory.
Axioms
Extensionality
(equivalence)
If X and Y are sets for which every element of X is an element of Y, and
every element of Y is an element of X, then the sets X and Y are one and the
same.
X = Y
Existence A collection that is empty ( ) is still a set.
Schema of
Comprehension Let P x be a predicate. For any set S, the collection of all objects x which
belong to S and for which P x is true is a set.
Notation: |x S P x
Example:
Let 1,2,3,4,5,6,7,8S .
Let | 4T x S x
array A 8992442
Offset = 0 Offset = 3
Data Structures Section 8
©1991 – 2016 Garth Santor & Trinh Hān GATS Encyclopaedia 107 of 278
Therefore 1,2,3,4T
Pair For any sets A and B, the collection which has as its only objects A and B is
a set.
Notation: ,A B
Union For any set S, the collection of all objects which are elements of S is a set,
called the union of S.
Notation: SU
Infinity The collection ¥ of all natural numbers is a set with the following
property: If S is a subset of ¥ which satisfies the requirements:
1. 0 S ;
2. n ¥ , if n S , then 1n S ;
Then S ¥ .
Power Set For any set S, the collection of all subsets of S is a set.
Notation: The power set of S, is denoted by SP
Examples
1,2 , 1 , 2 , 1,2
P
P
Definitions
Empty set: The empty set is the unique set with no elements. Denoted by
Intersection: For any sets A and B, the intersection of A and B is the set |x A x B
Notation: A B
Union: For any sets A and B, the union of A and B is the union of the set ,A B .
Notation: ,A B A B U
Subset: For any set S, a set A is said to be a subset of S, if every element of A is an
element of S.
Notation: A S or S A
Alternate reading: A is included in S.
Data Structures Section 8
©1991 – 2016 Garth Santor & Trinh Hān GATS Encyclopaedia 108 of 278
Finite set If S is a set for which there exists a positive integer n such that the elements
of S can be matched up by a one-to-one correspondence with the elements
of the set 1,2,3, ,nJ n K , then S is said to be a finite set. S is said to have
n elements, or to have size n.
Notation: S n
The empty set is also said to be finite with a size of zero. 0
Ordered Pair For objects A and B, the set , ,A A B is called the ordered pair of A and
B. A is called the first coordinate of the ordered pair and B is called the
second coordinate of the ordered pair.
Notation: , , ,A B A A B
Note that if A B then ,A B A
Cartesian Product For any sets S and T, the Cartesian product of S and T, is the set
| , for some and some X S T X A B A S B T P P
Notation: S T is the Cartesian product of S and T.
Alias: direct product
Ordered Triple For objects a, b, c, the ordered triple, (a, b, c) is defined by
, , , ,a b c a b c
Alias: 3-tuple
Data Structures Section 8
©1991 – 2016 Garth Santor & Trinh Hān GATS Encyclopaedia 109 of 278
Cartesian Product
as ordered
pair/triple
Let A be a set and n be a positive integer. The Cartesian product 1
n
iA
is
denoted by nA .
Note: 1
n n
iA A A A A A
K , in other words, n Cartesian products of
A with itself.
Examples
Let 0,1A
1
2
3
0,1
0,0 , 0,1 , 1,0 , 1,1
0,0,0 , 0,0,1 , 0,1,0 , 0,1,1 , 1,0,0 , 1,0,1 , 1,1, 0 , 1,1,1
A
A
A
Properties
Union of empty
set. For any set A, A A A
Union is
commutative.
For any sets A and B, A B B A
Subset and the
empty set. For any set A, A
Self containment For any set A, A A
Predicate
containment For any predicate P x and set S, |x S P x S .
Intersection
containment For any sets A and B, A B A
Union
containment For any sets A and B, A A B
Size of power set For any natural number n, if S is a set with S n , then 2nS P
Ordered Pairs are
contained in
Power Sets
For any sets S and T, ,A B S T P P for every A S and B T .
Data Structures Section 8
©1991 – 2016 Garth Santor & Trinh Hān GATS Encyclopaedia 110 of 278
History
Set theory was founded by the German/Russian mathematician Georg Cantor (1845 – 1918). After graduating from the University of Berlin in
1867 he published a series of papers in which he formulated his ideas on sets and infinite numbers.
Design Patterns Section 9
©1991 – 2016 Garth Santor & Trinh Hān GATS Encyclopaedia 111 of 278
Design Patterns
Bridge The bridge pattern is normally implemented using bounded dynamic polymorphism.
+operation()
Abstraction
+operation()
Implementor
1
-impl
1
+operation()
ConcreteImplementationA
+operation()
ConcreteImplementationB
However, C++ and other languages with generics may implement the bridge pattern using unbounded static polymorphism.
+operation()
Abstraction
IMPL
+operation()
ConcreteImplementationA
+operation()
ConcreteImplementation
+operation()
AbstractionA
«bind»(ConcreteImplementationA)
+operation()
AbstractionB
«bind»(ConcreteImplementationB)
Delegate A delegate is an object that represents a function or method, but hides the identity of the specific function or method.
Design Patterns Section 9
©1991 – 2016 Garth Santor & Trinh Hān GATS Encyclopaedia 112 of 278
A delegate is much like a function pointer but with a much cleaner interface. A delegate allows the programmer to invoke the delegated function
without knowing the actual name of the function or the name of the object to which the member function pointer has been bound to. In many
implementations, the delegate can support multiple function pointers using a subscription system.
Delegates can simplify the implementation of the observer pattern or callback systems.
Implementation Patterns
Double Check Locking Pattern (DCLP) DCLP was originally called the “Double-check Locking Optimization Pattern”.
DCLP is broken in Java.
DCLP is difficult in C++.
DCLP is a solution to the synchronization defect in the standard singleton pattern.
Intent
DCLP is a creational design pattern that facilitates lazy initialization of the shared resource.
Visual Studio 2005
Microsoft claims that DCLP can be implemented using critical sections and a volatile static pointer. (MSDN Magazine: June 2007)
Producer-Consumer
Introduction
The classical Producer-Consumer pattern has significant flaw when implemented – it cannot easily shut itself down.
Classic Pattern – Mutex and Semaphores
Mutex g_mutex
Semaphore g_emptySpots = BUFFER_SIZE
Semaphore g_fullSpots = 0
procedure PRODUCER
loop
PRODUCEITEM( item )
WAIT( g_emptySpots )
LOCK( g_mutex )
ENQUEUE( item )
UNLOCK( mutex )
SIGNAL( g_fullSpots )
end-loop
Design Patterns Section 9
©1991 – 2016 Garth Santor & Trinh Hān GATS Encyclopaedia 113 of 278
procedure CONSUMER
loop
WAIT( g_fullSpots )
LOCK( g_mutex )
DEQUEUE( item )
UNLOCK( g_mutex )
SIGNAL( g_emptySpots )
CONSUMEITEM( item )
end-loop
The problem with the classic pattern is that it assumes that the producer and consumer will run forever and that there is only one consumer.
Solution – Condition Variable, Mutex & Semaphore
Boolean g_done = false
Mutex g_mutex
Semaphore g_emptySpots = BUFFER_SIZE
Condition g_producerChange
Queue g_Q
procedure CONSUMER
loop
LOCK(g_mutex)
if g_done and g_emptySpots then
UNLOCK(g_mutex)
return
if size{ g_Q } = 0 then
CONDITIONWAIT(g_producerChange)
if size{ g_Q } > 0 then
DEQUEUE( g_Q , item )
UNLOCK(g_mutex)
if item then
SIGNAL(g_emptySpots)
CONSUMEITEM(item)
end-loop
procedure PRODUCER
loop n times
PRODUCEITEM(item)
WAIT(g_emptySpots)
LOCK(g_mutex)
ENQUEUE(g_Q , item)
UNLOCK(g_mutex)
CONDITIONSIGNAL(g_producerChange)
end-loop
g_done ← true
CONDITIONBROADCAST(g_producerChange)
Design Patterns Section 9
©1991 – 2016 Garth Santor & Trinh Hān GATS Encyclopaedia 114 of 278
Game Programming Section 10
©1991 – 2016 Garth Santor & Trinh Hān GATS Encyclopaedia 115 of 278
Game Programming
Game Architecture
Direct3D and the Win32 Message Pump (Garth Santor, March 2007)
Win32/C++ still underlies the majority of games, frameworks and engines in the game industry. Unfortunately, the architecture of the standard
Win32/C++ application is not ideal for real-time Direct3D3.
Standard Win32 Here is the standard “Hello, world!” application written in Win32/C++.
#define STRICT
#define WIN32_LEAN_AND_MEAN
#include <windows.h>
LRESULT CALLBACK WndProc( HWND hwnd, UINT uMsg, WPARAM wParam, LPARAM lParam ) {
switch( uMsg ) {
case WM_CREATE:
return 0;
case WM_PAINT: {
PAINTSTRUCT ps;
HDC hdc = BeginPaint( hwnd, &ps );
RECT rect;
GetClientRect( hwnd, &rect );
static TCHAR* pszGreetings = "Hello, world!";
DrawText( hdc, pszGreetings, lstrlen( pszGreetings ), &rect, DT_CENTER | DT_VCENTER | DT_SINGLELINE );
EndPaint( hwnd, &ps );
return 0;
}
case WM_DESTROY:
PostQuitMessage( 0 );
return 0;
default:
return DefWindowProc( hwnd, uMsg, wParam, lParam );
}
}
3 For the sake of this article Direct3D will refer to Direct3D9.
Game Programming Section 10
©1991 – 2016 Garth Santor & Trinh Hān GATS Encyclopaedia 116 of 278
int WINAPI WinMain( HINSTANCE hInstance, HINSTANCE /* hPrevInstance */, LPSTR /* lpCmdLine */, int nCmdShow ) {
// Register the window class
WNDCLASSEX wc = { 0 };
static char strAppName[] = "Hello, world";
wc.cbSize = sizeof( wc );
wc.style = CS_HREDRAW | CS_VREDRAW | CS_OWNDC;
wc.lpfnWndProc = WndProc;
wc.hInstance = hInstance;
wc.hbrBackground = (HBRUSH)GetStockObject( WHITE_BRUSH );
wc.hIcon = LoadIcon( NULL, IDI_APPLICATION );
wc.hIconSm = LoadIcon( NULL, IDI_APPLICATION );
wc.hCursor = LoadCursor( NULL, IDC_ARROW );
wc.lpszMenuName = NULL;
wc.lpszClassName = strAppName;
RegisterClassEx( &wc );
// Create the main application window.
HWND hwnd = CreateWindowEx( NULL, strAppName, strAppName, WS_OVERLAPPEDWINDOW, CW_USEDEFAULT, CW_USEDEFAULT,
512, 512, NULL, NULL, hInstance, NULL );
// Display the window
ShowWindow( hwnd, nCmdShow );
UpdateWindow( hwnd ); // force WM_PAINT
// run message pump
MSG msg;
while( GetMessage( &msg, NULL, 0, 0 ) ) {
TranslateMessage( &msg );
DispatchMessage( &msg );
}
// return exit code to Windows
return static_cast<int>( msg.wParam );
}
If you examine the task manager while this application is running you will notice that the processor load if virtually zero, except briefly when the
window was created, resized or closed.
Why? A standard window application spends most of its time in a suspended state.
The Win32 function GetMessage() is key to understanding this behaviour. GetMessage() is a blocking function that acquires Windows
messages from that application’s message queue. If there are no messages pending, the application is suspended and execution transfers to another
process. The application doesn’t resume until an external event causes a message to be issued to the application. The application’s process state is
then changed from suspended to ready. Once the message queue has been cleared, the application returns to a suspended process state.
GetMessage() only returns false (and terminates the loop) when the message acquired is WM_QUIT.
Game Programming Section 10
©1991 – 2016 Garth Santor & Trinh Hān GATS Encyclopaedia 117 of 278
Why this is bad… Real-time graphics applications like games don’t like the behaviour of standard Win32 applications, because they don’t want the program to enter
a suspended process state the moment the message queue is cleared. We want our full time-slice for rendered frames at as high a rate as possible.
Just because the user stopped playing doesn’t mean that the game has stopped playing.
To get our full time-slice back, we need to stop using GetMessage().
PeekMessage Pump The message-pump code of the standard Win32 application:
MSG msg;
while( GetMessage( &msg, NULL, 0, 0 ) ) {
TranslateMessage( &msg );
DispatchMessage( &msg );
}
Is replaced with:
int cIdle = 0;
MSG msg;
for(;;) {
if( PeekMessage( &msg, NULL, 0, 0, PM_REMOVE ) ) {
if( msg.message == WM_QUIT )
break;
TranslateMessage( &msg );
DispatchMessage( &msg );
}
else {
HDC hdc = GetDC( hwnd );
RECT rect;
GetClientRect( hwnd, &rect );
std::wstringstream oss;
oss << L"Hello, " << ++cIdle;
DrawText( hdc, oss.str().c_str(), (int)oss.str().size(), &rect, DT_CENTER|DT_VCENTER|DT_SINGLELINE );
ReleaseDC( hwnd, hdc );
}
}
PeekMessage() is non-blocking and return false when the message queue is empty, not when WM_QUIT has been issued as is the case with
GetMessage(). This behaviour allows our application to update the frame on any idle cycles.
Examining the task manager performance tab will reveal 100% CPU usage on single-thread, non-hyper-thread processors. Hyper-thread and
multi-core processors will show 50% CPU usage as the other core will be used to execute GDI function calls that are processed synchronously
with the application executing on the original core.
Game Programming Section 10
©1991 – 2016 Garth Santor & Trinh Hān GATS Encyclopaedia 118 of 278
Now with Direct3D I’ll add the minimal Direct3D9 plumbing to the previous example, replacing the GDI calls that render “Hello, world” with an
IDirect3DDevice9::Clear() that cycles the window colour through all the shades of pure blue.
#define STRICT
#include <windows.h>
#include <d3d9.h>
#pragma comment (lib,"d3d9.lib")
IDirect3DDevice9* g_pd3dDevice = NULL;
void Render() {
static unsigned char blue = 0;
--blue;
g_pd3dDevice->Clear( 0, NULL, D3DCLEAR_TARGET, D3DCOLOR_XRGB(0,0,blue), 1.0f, 0 );
g_pd3dDevice->Present( NULL, NULL, NULL, NULL );
}
LRESULT CALLBACK MsgProc( HWND hwnd, UINT uMsg, WPARAM wParam, LPARAM lParam ) {
switch( uMsg ) {
case WM_DESTROY:
PostQuitMessage( 0 );
return 0;
default:
return DefWindowProc( hwnd, uMsg, wParam, lParam );
}
}
int WINAPI WinMain( HINSTANCE hInstance, HINSTANCE, LPSTR, int nCmdShow ) {
IDirect3D9* pd3d = Direct3DCreate9( D3D_SDK_VERSION );
if( !pd3d )
return 1;
// Register the window class.
WNDCLASSEX wc = { sizeof(WNDCLASSEX), CS_CLASSDC, MsgProc, 0L, 0L,
GetModuleHandle(NULL), NULL, NULL, NULL, NULL,
L"D3D Tutorial", NULL };
RegisterClassEx( &wc );
// Create the application's window.
HWND hWnd = CreateWindow( L"D3D Tutorial", L"D3D: CreateDevice", WS_OVERLAPPEDWINDOW, 100, 100, 300, 300,
GetDesktopWindow(), NULL, wc.hInstance, NULL );
if( hWnd == NULL )
return 1;
// Create the full screen device
D3DPRESENT_PARAMETERS d3dpp = { 0 };
Game Programming Section 10
©1991 – 2016 Garth Santor & Trinh Hān GATS Encyclopaedia 119 of 278
d3dpp.Windowed = TRUE;
d3dpp.SwapEffect = D3DSWAPEFFECT_DISCARD;
d3dpp.BackBufferFormat = D3DFMT_UNKNOWN;
HRESULT hres = pd3d->CreateDevice( D3DADAPTER_DEFAULT, D3DDEVTYPE_HAL, hWnd, D3DCREATE_SOFTWARE_VERTEXPROCESSING,
&d3dpp, &g_pd3dDevice );
if( FAILED( hres ) )
return 1;
ShowWindow( hWnd, nCmdShow );
UpdateWindow( hWnd );
// Message Pump
MSG msg;
for(;;) {
if( PeekMessage( &msg, NULL, 0, 0, PM_REMOVE ) ) {
if( msg.message == WM_QUIT )
break;
TranslateMessage( &msg );
DispatchMessage( &msg );
}
else
Render();
}
g_pd3dDevice->Release();
pd3d->Release();
return (int)msg.wParam; // all ok
}
Once again the processor load drops to near zero. If we measure the time it takes to cycle through all the shades of blue, we will discover that our
frame rate is approximately 60 fps. By default, a windowed presentation mode will have vertical sync enabled, locking the frame rate to the
monitor’s refresh rate. Since the IDirect3DDevice9::Present() method is synchronous, the application is suspended until the GPU
completes the operation.
To achieve higher frame rates, we need to turn vertical sync off with a more precisely specified device mode.
Game Programming Section 10
©1991 – 2016 Garth Santor & Trinh Hān GATS Encyclopaedia 120 of 278
Game Loops
Load Game
Unload Game
/ Quit
Service Windows
Get Input
AI/Logic
Physics/Model Update
Render and Sound
Real-time Game Loop:
Stand-alone
Game Programming Section 10
©1991 – 2016 Garth Santor & Trinh Hān GATS Encyclopaedia 121 of 278
Load Game
Unload Game
/ Quit
Service Windows
Send User Input to Server
Update Game State
Render and Sound
Real-time Game Loop:
Client
Load Game
Unload Game
/ Quit
Service OS
Get Client States
AI/Logic
Physics/Model Update
Broadcast Game State Changes
Real-time Game Loop:
Server
Game Programming Section 10
©1991 – 2016 Garth Santor & Trinh Hān GATS Encyclopaedia 122 of 278
Load Game
Unload Game
/ Quit
Service Windows
Send User Input to Server
Update Game State
Render and Sound
Real-time Game Loop:
Threaded Client
Load Game
Unload Game
/ Quit
Service OS
Get Client Actions
AI/Logic
Physics/Model Update
Broadcast Game State Changes
Real-time Game Loop:
Threaded Server
Get State Changes
Update Game State
/ Quit
Get Client Input
Queue Client Action
/ Quit
Game Programming Section 10
©1991 – 2016 Garth Santor & Trinh Hān GATS Encyclopaedia 123 of 278
Input
Thumbing Styles Game controllers present an interesting problem for software developers because controls, more than most input devices, are susceptible to
different input styles. Controller button input styles tend to be a variation of either the precise thumbing style or the sloppy thumbing style.
In the precise thumbing style, the user places their thumb above the primary button resting the tip of the thumb on the button. The thumb is then
moved to the other buttons as needed, but typically returns to the primary button after each press.
In the sloppy thumbing style, the user places their thumb above and touching all the buttons. The thumb is then rocked or tilted onto the specific
button as required.
The GameCube controller was built with sloppy thumb players in mind and has a larger primary key.
The great concern for a developer in understanding thumbing styles is that players with the sloppy thumbing style is more likely to accidentally
press more than one button when only a single button press is desired. This could result in a character such as Mario performing a ‘ground pound’
instead of the player’s intended ‘jump’ operation. These ambiguous button situations are a major source of player frustration with a game.
The two most common solutions to sloppy thumb problems are to only accept commands in the appropriate context or to increase the window of
time that a command can be executed (e.g. if jumping off a cliff, allow the jump command to be issued up to 0.25 seconds after running off the
edge of the cliff.)
Logic / AI
Feedback Loops A feedback loop is a technique that can be applied to any system where a transformation occurs. System input represent the influence of the
environment on the system; system output the influence of the system on the environment. Feedback is a system output that is also used as a
system input. Feedback represents the system’s influence on itself.
Positive Feedback Loops
If the feedback data accelerates the system’s progress in the same direction as preceding output, then we have a positive feedback loop. The
feedback heard in microphone/amplifier systems is an example of positive feedback. Other examples are chain reactions, explosions (both the
chemical kind and the population kind), compound interest, and the spread of a disease.
Negative Feedback Loops
If the feedback data reverses the direction from the preceding output, then we have a negative feedback loop. The feedback felt in a shock
absorber system is an example of negative feedback. If a negative feedback system produces a series of values that are successively smaller in
magnitude from the preceding output, the system will approach a state of equilibrium. These feedback loops can be characterized as goal seeking.
Game Programming Section 10
©1991 – 2016 Garth Santor & Trinh Hān GATS Encyclopaedia 124 of 278
It is the negative feedback systems that are most interesting in game and simulation programming!
Networking
DirectPlay
Introduction
DirectPlay is the DirectX system for building multiplayer games. Introduced as part of the DirectX 2.0 API in 1996, DirectPlay provides a device-
independent and network independent communication model. The mechanics of enumerating and connecting to game servers and transferring
data among them is abstracted within the API. The most significant omission from the API is synchronization. Synchronization is not a part of
the API since developers differ greatly on how to implement synchronization.
With DirectX 9.0, DirectPlay supports the following features:
Available for Windows 95, 98, ME, NT, 2000, XP, 2003 and Pocket PC.
Communicates over Transmission Control Protocol/Internet Protocol (TCP/IP), Internetworking Packages Exchange (IPX), modem and serial
links.
Peer-to-peer sessions.
Client/server sessions.
Player lobbies.
Player groups.
Voice.
Can calculate round-trip travel times for messages.
Thread pools.
Support for Network Address Translation.
Support for Internet Protocol v6.
What DirectX does not support:
Secure communications.
Architecture
DirectPlay is composed of the DirectPlay COM object, which provides the programming interface, and the DirectPlay Service Provider which
implements network specific communications.
Game Programming Section 10
©1991 – 2016 Garth Santor & Trinh Hān GATS Encyclopaedia 125 of 278
DirectPlay Transport Protocol
DirectPlay implements its own network protocol, the DirectPlay Transport Protocol. As of DirectX 8.0, it is used for all DirectPlay messages.
This transport layer provides features that are specific to the needs of game developers.
Reliable and unreliable messages. Reliable messages that are resent until received whereas unreliable messages are not.
Sequential and non-sequential messages. Sequential messages are received in the same order they were sent.
Message fragmentation and assembly. On networks with packet size limits, messages are fragmented, sent, and then reassembled by the
receiving application.
Congestion control. DirectPlay throttles the outgoing messages to a rate that the target application can handle. This prevents flooding of the
target application.
Message priorities. Messages can be sent with low, medium or high priority, with high priority messages being sent first.
Message lifespan. Message can be sent with a timeout attribute after which the sender will quit sending the message.
DirectPlay uses UDP for communicating over IP networks, which it implements using Winsock.
DirectPlay Addresses
DirectPlay uniquely identifies each game with a DirectPlay Address. DirectPlay Addresses take the form of an URL string. The format is:
x-directplay:/[data string]
The DirectPlay address string is normally encapsulated in a DirectPlay Address object, so the specific details are not an issue programmers need to
deal with.
Ports
DirectPlay automatically assigns a port address between 2302 and 2400 for local use when hosting enumerating or connecting.
Sessions
Since multiple games can be played on the same network, DirectPlay needs a method of identifying one game from another. This is called
sessions. Each game on the network, either peer-to-peer (P2P) or client/server is represented by a session. The host or the first peer creates the
session, then the clients or other players of a P2P games join that session.
Players
maintains a list of current players in a session.
each player has a friendly name, a formal name and an ID.
Player names are not used internally.
Game Programming Section 10
©1991 – 2016 Garth Santor & Trinh Hān GATS Encyclopaedia 126 of 278
Player Groups
Player groups are like teams.
Player groups appear like players in a session.
Messages can be sent to the members of a group.
Messages
Communication is performed using ‘messages’.
Message can be sent to everyone, the group or an individual player.
Networking Issues (Garth Santor, pre 2006)
Most networking issues in multiplayer games are not unique to game programming. They are however, significant!
Issues that developers need to consider are:
number of players
network architecture
protocol
what data needs to be transmitted
time sensitivity of the information
Furthermore, these issues are related.
Network Architecture – Peer-to-Peer vs. Client/Server (and number of players) Network architectures in gaming can be generalized into one of three general models.
1. Client/Server – Server is a player.
2. Client/Server – Dedicated server.
3. Peer-to-peer.
Game Programming Section 10
©1991 – 2016 Garth Santor & Trinh Hān GATS Encyclopaedia 127 of 278
host client
client client
host
client
client
clientclient
peer
peer peer
peer
Client/Server
Server is player
Client/Server
Dedicated ServerPeer-to-peer
In client-server architectures a server process executes the game logic and manages communication between all the players. Client processes
render the graphics and play audio, and handle input from the player. A dedicated server architecture has the server process running on it own
machine, whereas the server is a player architecture has the host player’s machine running both the server process and one of the client processes.
Real-time-strategy games are often implemented with the server is a player architecture. The dedicated server architecture is common in multi-
player first person shooters and massively-multiplayer online role-playing games.
The peer-to-peer approach treats all players as equal and each peer process executes its part of the game logic. Peer-to-peer architectures are more
common on network card games.
Critique
Peer-to-peer networking is generally easier to program and produces the shortest transmission times, but is limited in the number of players in a
game. Adding more players drastically increases the number of connections to the point of being unmanageable.
# Players # Connections – P2P
# Connections C/S
1 0 1
2 1 2
3 3 3
4 6 4
5 10 5
n
12
1
1O
2
n
i
i
n nx n
On n
Clearly, P2P networks do not scale well.
Game Programming Section 10
©1991 – 2016 Garth Santor & Trinh Hān GATS Encyclopaedia 128 of 278
Another benefit of peer-to-peer networking is for host migration. If the game host quits, the host can easily be migrated to another computer
without having to re-establish network connections to the new server.
Protocols – TCP vs. UDP (and time sensitivity) TCP is a streamed protocol that focuses on reliable communication between client and server. It performs three way handshaking to ensure that
everything sent actually arrives. This has the consequence that establishing a connection requires a minimum of three packets to be sent back and
forth. Lost packets cause the system to halt transmission of new packets until the missing packet has been resent and received. It is however; very
easy to use as the TCP stack performs a lot of the security and reliability task for the application programmer.
UDP is a connectionless datagram protocol that focuses on efficient communication between client and server. It sends packets without
handshaking. If the packet fails to arrive the sender won’t know of the failure and the receiver won’t know a packet was sent. Security and
reliability must be handled by the application programmer. UDP has the added benefit that it can be multicast.
Multicasting allows a server to broadcast a single packet to an entire network. This is particularly useful for streaming video to multiple clients or
sending player state data to all the players on a LAN. A UDP broadcast does not require knowledge of specific client IP addresses and is therefore
useful to query a LAN for the presence of players.
A further consideration is the time-sensitivity of the information being transmitted. In the case of a 1st-person shooter – the direction a character is
facing is important, only in the present. If that information did not get transmitted at that instant, we can forget about that information. No-one
will have any historical interest as the current state of the character is not dependent on that information. Contrast this to a chess game. We must
record every move that each player makes and in correct sequence. The network must continue to try to transmit the data or quit the game. TCP
offers no benefit when the data is time sensitive and time independent; it just slows your communications. UDP is better suited to this situation.
Threading Issues Multi-threading is a topic that is rarely discussed in game programming books, largely due to the fact that programming multiple threads in
Direct3D is somewhat difficult. Direct3D, in general, doesn’t like to execute in multiple threads!
Why? I would assume that Direct3D’s designers didn’t want to handle the situation where thread A causes a display mode change while thread B
is rendering to Direct3D. To handle this situation, Direct3D would have to share a mutex with the OS that would destroy the performance of the
system. Due to this problem, the Direct3D engineers decided to enforce the rule that the methods IDirect3DDevice9::Reset and
IDirect3D9::CreateDevice can only be called by the thread that handles windows messages. The added complication of avoiding overlap in
IDirect3DDevice9::BeginScene / IDirect3DDevice9::EndScene calls leads developers to place all of the Direct3D code in the same thread as the
window message handler.
Where can you safely multithread?
The most common places for multithreading in a game are:
scene loading
networking
AI
Game Programming Section 10
©1991 – 2016 Garth Santor & Trinh Hān GATS Encyclopaedia 129 of 278
Scene Loading
Scene or level loading usually requires one or more files on disk to be read, especially where textures must be loaded. Loading a textures usually
requires reading some portion of the file into memory, decoding the data (decompress and/or translate to a different format), then transfer the
texture to video memory. Reading data from the disk is normally handled by the system’s DMA controller and therefore requires little or no CPU
activity.
Each texture can be read and decompressed/converted in a separate thread. When the thread is blocked due to an I/O wait, the next thread will
execute. Eventually, the first thread will complete its read and move on decompression. While decompression occurs (a CPU intensive
operation) other threads will be performing disk-to-memory data transfers. The total load time can often be reduced to a fraction of the time that
would be required to load the texture in a serial fashion.
Networking
To avoid having to write your network routines as a polling system, the network read function can be written using blocking read functions that
reside in a loop running in a separate thread. This thread reads the socket and updates a block of shared memory that contains the state of game
objects from the network.
AI
AI is often processed in a separate thread. This is typically done when the AI calculations are complex and cannot be performed within the time
allotted between frames.
Graphics Section 11
©1991 – 2016 Garth Santor & Trinh Hān GATS Encyclopaedia 130 of 278
Graphics
Concepts
Blit A blit is a colloquialism for bit block transfer.
Camera
Introduction
The ‘camera’ represents the virtual viewer (the user) within a 3D scene. The camera encapsulates the position, direction, orientation and ocular
properties of the viewer. An object-oriented implementation of a camera can enhance understanding of the system and simplify the overall
implementation of the rendering engine.
Both DirectX and OpenGL have support for the 3D camera concept. However, DirectX’s D3DXMatrixLookAtLH/RH() functions and
OpenGL’s gluLookAt() function are somewhat limited and are best suited to a system that is aiming at a fixed position.
3D games such as simulators and first-person shooters work with the idea that the viewer will look ahead, but not at anything in particular. There
is some variation in the camera’s behaviour depending on whether we use the camera for an aerial object or a land-based object.
Solution
The solution consists of three parts:
The view matrix.
Orientation operations.
Motion operations.
View Matrix
Each object in a 3D world can be thought to have its own 3-axis coordinate system. With that in mind, we can imagine that the camera’s
coordinate system is congruent to the world’s coordinate system, but with a different origin (translation) and a different orientation (rotation). If
we can find a combination of translation and rotation that transforms our local coordinate system to the world coordinate system then we can find
another transform that can transform the world coordinate system to our local (viewer) coordinate system.
Let zyx pppp be the position vector of the viewer.
Let zyx kkkk be the look vector of the viewer.
Graphics Section 11
©1991 – 2016 Garth Santor & Trinh Hān GATS Encyclopaedia 131 of 278
Let zyx uuuu be the up vector of the viewer.
Let zyx rrrr be the right vector of the viewer.
Find a transformation matrix V such that:
000pV The position is transformed to the origin.
100kV The look vector is transformed to the z-axis.
010uV The up vector is transformed to the y-axis.
001rV The right vector is transformed to the x-axis.
Translation Part
The translation that takes p to the origin is simply −p, since 0pp .
Written as a 4x4 matrix with homogenous coordinates:
1 0 0 0
0 1 0 0
0 0 1 0
1x y z
T
p p p
Rotation Part
Since rotation matrices don’t require homogenous coordinates and 3x3 matrices are easier to work with than are 4x4 matrices, we will seek a 3x3
matrix A that aligns the right, up and look vectors to the world’s x-axis, y-axis and z-axis.
100
222120
121110
020100
aaa
aaa
aaa
kkk zyxkA
010
222120
121110
020100
aaa
aaa
aaa
uuu zyxuA
001
222120
121110
020100
aaa
aaa
aaa
rrr zyxrA
Since each system has the same coefficient matrix A, we can solve all the system at once.
Graphics Section 11
©1991 – 2016 Garth Santor & Trinh Hān GATS Encyclopaedia 132 of 278
00 01 02
10 11 12
20 21 22
1 0 0
0 1 0
0 0 1
x y z
x y z
x y z
a a a
a a a
a a a
r r r
BA u u u
k k k
A can be solved in many ways, but the simplest solution is to recognize that A is the inverse of B since 1BBIBA
In the case that a matrix is orthogonal (its row vectors are an orthonormal basis – they are at right angles), we know that its inverse is equal to its
transpose.
1 T
x x x
y y y
z z z
r u k
B B A r u k
r u k
We can now combine the translation matrix with the rotation matrix to produce the final view matrix
1 0 0 0 0 0
0 1 0 0 0 0
0 0 1 0 0 0
1 0 0 0 1 1
x x x x x x
y y y y y y
z z z z z z
x y z
r u k r u k
r u k r u kTA V
r u k r u k
p p p p r p u p k
Right-Handed Systems
The solution provided here assumes a left-handed coordinate system. On a right-handed coordinate system we must flip either the
right vector to point left, or the look vector to be looking at us. All of the preceding arguments still apply for right-handed system.
The calculation requires that we start with -k for the look vector. The result is the view matrix transform:
0 0
0 0
0 0
1 1
x x x x x x
y y y y y y
z z z z z z
r u k r u k
r u k r u k
r u k r u k
p r p u p k p r p u p k
Orientation Operations
Orientation operations adjust the pitch, roll and yaw of the camera.
A change in pitch is a rotation about the camera’s right-vector. A positive pitch angle produces a downward pitch. Calculate a rotation matrix
about the right vector, then transform the coordinates of the up and look vectors by that rotation matrix.
A change in roll is a rotation about the camera’s look-vector. A positive roll angle produces a roll to the left or a bank-left in an aircraft. Calculate
a rotation matrix about the look-vector, then transform the coordinates of the right and up vectors by that rotation matrix. For land-based cameras
the roll operation can be ignored.
A change in yaw is a rotation about the camera’s up-vector. A positive yaw angle produces a yaw or turn to the right. Calculate a rotation matrix
about the up-vector, then transform the coordinates of the right and look vectors by that rotation matrix. For land-based cameras, calculate the
Graphics Section 11
©1991 – 2016 Garth Santor & Trinh Hān GATS Encyclopaedia 133 of 278
rotation matrix about the world’s y-axis. Since the y-axis and the up-vector are not necessarily the same, you must transform the up-vector by the
rotation matrix as well.
Motion Operations
Motion operations adjust the location of the camera. The three types of motion are walk (forward and back), strafe (left and right) and fly (up and
down).
The walk operation adds the look-vector to the position-vector. For a land-based walk, add only the x and z components of the look-vector.
The strafe operation adds the right-vector to the position-vector. For a land-based strafe, add only the x and z components of the right-vector.
The fly operation adds the up-vector to the position-vector. For a land-based fly, do nothing.
Creeping Error
A concern about this camera system is that the axis vectors – look, up, right – will eventually loose their orthogonality and their normality. If this
happens, distortion will occur in view transform and the precision of the movement will be compromised. An occasional correction will need to
be applied to the vectors.
Left-Hand Coordinate System Right-Hand Coordinate System
kk
k
u k r
uu
u
r u k
rr
r
kk =
k
u = r k
uu =
u
r = k u
rr =
r
Culling, Backface Backface culling is the process of removing polygons from the rendering pipeline whose backface is oriented towards the viewer.
Why?
There are two reasons for backface culling: speed and wireframe objects.
Speed
In the case of rendering solid 3D objects, the faces pointing towards the viewer obscure our view of the faces pointing away from the viewer. (e.g.
a cube always has a maximum of three faces visible to the viewer and a minimum of 3 faces not visible to the viewer.) By not rendering the non-
visible faces, a significant amount of processing can be avoided by rendering the visible faces only.
Graphics Section 11
©1991 – 2016 Garth Santor & Trinh Hān GATS Encyclopaedia 134 of 278
Wireframe Objects
When an object is rendered as a wireframe model, the viewer can see through the object. It is often difficult to identify the correct orientation of
the object (i.e. an optical illusion.) Backface culling can remove the surfaces that would not be seen and as a result, the edges that are rendered in
wireframe.
How?
The backface of an object can be identified by generating a surface normal from three consecutive vertices on the surface (the vertices must not
be collinear.) The vertex winding will determine the direction of the surface normal generated (see Vertex Winding.)
Once a surface normal has be acquired we can determine whether the surface points toward the viewer by testing the inner product of the normal
vector and a vector drawn from the surface to the viewer.
Let n be the normal vector of the surface.
Let v be a vector originating on the surface and terminating at the viewer.
s n v
If 0s then the surface faces the viewer (i.e. frontface)
If 0s then the surface faces away from the viewer (i.e. backface)
If 0s then the viewer is on the surface (this condition is usually treated as a backface)
Which cull type is correct for Direct3D?
The cull type to use in Direct3D depends on a combination of the coordinate system and vertex winding.
Right handed coordinate system (+Z towards user)
Left handed coordinate system (+Z away from user)
Anti-clockwise winding D3DCULL_CW D3DCULL_CCW
Clockwise winding D3DCULL_CCW D3DCULL_CW
Mouse Look Mouse look is a relatively easy feature to implement if you already have a camera class.
I’ll assume that you already have a camera class with the following minimal interface.
+Pitch()
+Yaw()
+Run()
+Strafe()
Camera
Graphics Section 11
©1991 – 2016 Garth Santor & Trinh Hān GATS Encyclopaedia 135 of 278
The run and strafe simply map the ‘W’ and ‘S’ keys to the Run method and ‘A’ and ‘D’ keys to the Strafe method.
The trickier part is the Pitch and Yaw that must be tied to the mouse’s movements. A DirectInput mouse will provide data indicating the distance
in screen coordinates that the mouse have moved since the last polling (either through a state object or by accumulating mouse events in buffered
input.) Map the screen coordinates to an angle indicating the amount of rotation or elevation. As a starting point use:
Axis Screen Units (SU) Angle () Formula
Horizontal (Yaw) ½ screen width (180) 2
1
2
su su
widthwidth
Vertical (Pitch) ½ screen height ½ (90) 1
1 2
2
su su
heightheight
Picking Picking is the process of mapping a physical screen location to logical location within the 3D world.
The process of picking starts with reading a value from the mouse or another pointing device that reports its location in screen coordinates. From
this location, we calculate a ray that runs from the eye of the viewer through that screen location. The ray is expressed in terms of the virtual or
logical 3D world. With this ray we iterate through the objects of the scene testing objects (or just triangles) until we find an object that it
intersects. Typically, we search these items in a nearest to farthest order.
Picking algorithm.
The picking ray is calculated in three steps:
calculate the point on the projection window (the near plane of the projection) represented by the physical point on the screen.
calculate the picking ray that shoots through the point on the projection window.
transform the picking ray and the objects into the same space.
test for intersection between the picking ray and the scene objects.
Sprite A sprite is a graphic image that can be moved about a larger graphical scene.
Sprites are most commonly used in 2D games and to implement the mouse pointer graphic in a GUI. Standard sprite operations include loading
and unloading a sprite, moving a sprite, blitting, and rotating the sprite image (like a cartoon animation).
Texel Texel is an abbreviation of texture element, a pixel-like element or colour value of a texture.
Graphics Section 11
©1991 – 2016 Garth Santor & Trinh Hān GATS Encyclopaedia 136 of 278
Vertex Buffer A vertex buffer is an array of vertices typically located in video memory from which a graphics accelerator draws geometry with which is renders
primitives (points, lines and triangles).
In DirectX, vertex buffers are managed through the IDirect3DVertexBuffer9 interface.
Vertex Winding Vertex winding refers to the order in which vertices are listed when used to represent a surface (usually a triangle). Vertices are wound in either
clockwise or anti-clockwise order.
Counter-clockwise winding.
Clockwise winding.
Why?
By imposing a consistent vertex winding upon the vertices that define a surface in a 3D model, we can mathematically determine whether the front
side or the back side of a triangle presents itself to the viewer.
A surface normal (a vector perpendicular to the surface) can be generated with the following formula:
AB AC
B A C A
n
n
uuur uuur
The surface normal n, will point towards the viewer in a counter-clockwise wound triangle. In the clockwise wound triangle, surface normal n
will point away from the viewer.
The surface normal can then used to determine whether the front face or back face presents itself to the viewer. Back faces could be culled if
belonging to solid polyhedra.
Typically, right-handed coordinate systems prefer counter-clockwise winding and left-handed systems prefer clockwise winding.
AB
C
A
B
C
Graphics Section 11
©1991 – 2016 Garth Santor & Trinh Hān GATS Encyclopaedia 137 of 278
Direct3D 9.0 Programming
Blitting Surface to Back Buffer
To blit images from a surface object to the back buffer, we must first ensure that the surface has been created in the D3DPOOL_SYSTEMMEM
memory pool.
IDirect3DSurface9* pBackBuffer = 0;
g_pd3dDevice->BeginScene();
g_pd3dDevice->GetBackBuffer( 0, 0, D3DBACKBUFFER_TYPE_MONO, &pBackBuffer );
g_pd3dDevice->UpdateSurface( g_pSurface, NULL, pBackBuffer, NULL );
pBackBuffer->Release();
g_pbd3dDevice->EndScene();
See also Images – Load as Surface
CopyRect
IDirect3DDevice8::CopyRects() (Direct3D 8.0) has been replaced by IDirect3DDevice9::UpdateSurface().
Direct3D9 Pipeline The specific and full details of the Direct3D rendering pipeline can confuse and impede a persons understanding of its operation. We will examine
the pipeline with the aid of several simplified models.
This model gives the steps in processing a fixed vertex format 3D geometry.
Graphics Section 11
©1991 – 2016 Garth Santor & Trinh Hān GATS Encyclopaedia 138 of 278
World Space Transform
View Space Transform
Backface Culling
Lighting
Clipping
Projection Transform
Viewport Transform
Rasterization
Geometery recorded relative to a local coordinate system.
Pixels are recorded in framebuffer/z-buffer
The object is placed within the scene (world).
Matrix transform applied with D3DTS_WORLD.
The viewer (or camera) is placed within the scene.
Matrix transform applied with D3DTS_VIEW.
Vertex winding is used to determine frontface/backface.
Backfaces are culled (removed) from the render pipeline.
Lighting normals, colour values, etc. are generated.
Triangles are clipped to the projection frustum.
Either wholely are partially.
Matrix transform applied with D3DTS_PROJECTION.
Converts geometry from 3D to 2D (projects to near view plane).
Logical (now 2D) coordinates are converted to
physical device coordinates.
Triangles and lines are drawn into the frame buffer.
Graphics Section 11
©1991 – 2016 Garth Santor & Trinh Hān GATS Encyclopaedia 139 of 278
The relationship between GPU activity and Video RAM resource use is modeled here:
Using Fixed-Function Processing Using Shaders
Vertex Buffer
Index Buffer
VB/IB
Transform &
Lighting
Rasterizer /
Interpolator
Texture Stage
Cascade
Z, Alpha, Stencil,
Fog
Texture
Depth / Stencil
Render Target
Command Input
Video RAM
Vertex Buffer
Index Buffer
VB/IB
Vertex Shader
Rasterizer /
Interpolator
Pixel Shader
Z, Alpha, Stencil,
Fog
Texture
Depth / Stencil
Render Target
Command Input
Video RAM
Texture (SM3)
Flexible Vertex Format Flexible Vertex Format (FVF) is a protocol for describing vertices to the Direct3D render pipeline. The challenge is to efficiently provide the
pipeline with multiple buffer formats. Sometimes we want to couple geometry with colour information, and at other times with texture and normal
information.
The FVF structure is composed off one or more of the following items and must be declared in the order presented.
Graphics Section 11
©1991 – 2016 Garth Santor & Trinh Hān GATS Encyclopaedia 140 of 278
FVF Description Data Declarations D3DFVF_XYZ X, Y, Z coordinates of the vertex D3DXVECTOR3 v;
D3DFVF_XYZRHW X, Y, Z, RHW coordinates of the
vertex
D3DXVECTOR4 v;
D3DFVF_XYZW X, Y, Z, W coordinates of the
vertex
D3DXVECTOR4 v;
D3DFVF_NORMAL 3 element vector indicating the
surface normal at the vertex
FLOAT nx, ny, nz;
D3DXVECTOR3 n;
D3DFVF_PSIZE Vertex point size FLOAT psize;
D3DFVF_DIFFUSE Diffuse colour information DWORD color;
D3DCOLOR color;
D3DFVF_SPECULAR Specular colour information DWORD specular;
D3DCOLOR specular;
D3DFVF_TEXCOORDSIZE1(x)
D3DFVF_TEXCOORDSIZE2(x)
D3DFVF_TEXCOORDSIZE3(x)
D3DFVF_TEXCOORDSIZE4(x)
Texture coordinate information.
The size ordinal indicates the
dimension of the textures: 1D,
2D, 3D, 4D.
FLOAT tu;
D3DXVECTOR2 t;
D3DXVECTOR3 t;
D3DXVECTOR4 t;
Fog Fog is a visual effect that blends the colour of the objects in a scene with a chosen fog colour. The fog colour becomes proportionately greater as
the depth of the objects in the scene increases.
Fog is used for several different purposes other than actual fog. These include ambience, heat haze, dust, mist, or rain. One of the most common
uses of fog is to obscure distant objects as they come into the view volume. We don’t want users to see house that are sliced in half or street lamps
suspended from nothing (the post is just outside the view volume). Fog can blur these most distant objects enough that we will not have our
attention drawn to these anomalies. Fog may, in fact, completely obscure these problems.
Fog in Direct3D
Direct3D supports two types of fog, pixel fog and vertex fog. Vertex fog can employ range-based fog which uses a more complex calculation that
measures the distance from the viewpoint instead of the distance from the front of the view volume. This can eliminate some of the odder things
that occur when viewing depth-based fog.
Code Sample: linear range-based vertex fog float const start = 10.0f;
float const end = 30.0f;
pd3dDevice->SetRenderState( D3DRS_FOGENABLE, TRUE );
pd3dDevice->SetRenderState( D3DRS_FOGCOLOR, color );
pd3dDevice->SetRenderState( D3DRS_FOGTABLEMODE, D3DFOG_NONE );
pd3dDevice->SetRenderState( D3DRS_FOGVERTEXMODE, D3DFOG_LINEAR );
pd3dDevice->SetRenderState( D3DRS_RANGEFOGENABLE, TRUE );
pd3dDevice->SetRenderState( D3DRS_FOGSTART, *reinterpret_cast<DWORD*>(&start) );
Graphics Section 11
©1991 – 2016 Garth Santor & Trinh Hān GATS Encyclopaedia 141 of 278
pd3dDevice->SetRenderState( D3DRS_FOGEND, *reinterpret_cast<DWORD*>(&end) );
See Also
MSDN-DirectX SDK Help: DirectX Graphics → Programming Guide → Getting Started → Direct3D Rendering → Fog
Images
Load as Surface To load an image into a surface for the purpose of blitting:
IDirect3DSurface9* g_pSurface = 0;
D3DXIMAGE_INFO info;
D3DXGetImageFromFile( "image.jpg", &info );
g_pd3dDevice->CreateOffscreenPlainSurface( info.Width, info.Height, info.Format,
D3DPOOL_SYSTEMMEM, &g_pSurface, NULL );
D3DXLoadSurfaceFromFile( g_pSurface, NULL, NULL, "image.jpg", NULL, D3DX_DEFAULT, 0, NULL );
The critical detail in this code is the memory pool in which we will create and store the surface. We have chosen D3DPOOL_SYSTEMMEM since
we are blitting the surface to the back-buffer.
DX-SDK9.0c: Create in OnCreateDevice() and Release() in OnDestroyDevice().
DX-SDK9.0b: Create in InitDeviceObjects() and Release() in DeleteDeviceObjects().
See also Blitting – Surface to Back Buffer
Load as Texture To load an image into a texture object:
IDirect3DTexture9* g_pTexture = 0;
D3DXCreateTextureFromFile( g_pd3dDevice, "myImage.jpg", &g_pTexture );
DX-SDK 9.0c: Create in OnCreateDevice() and Release() in OnDestroyDevice().
DX-SDK 9.0b: Create in InitDeviceObjects() and Release() in DeleteDeviceObjects().
Lighting, Direct3D Types Direct3D supports four types of lights – ambient light, directional lights, point lights and spot lights.
Ambient Light
Ambient light is the environmental light that seems to come from no particular place or direction – its just there. Unlike the other three light types,
we do not need to set a D3DLIGHT9 to use ambient light. Ambient light is handled as part of a device’s render state.
pd3dDevice->SetRenderState( D3DRS_AMBIENT, D3DCOLOR_XRGB(32,32,32) );
Graphics Section 11
©1991 – 2016 Garth Santor & Trinh Hān GATS Encyclopaedia 142 of 278
Directional Light
Directional lights are the simplest and least computationally expensive lights in Direct3D. They have
colour and direction, but no position – distance and attenuation have no effect on results.
Directional lights are used to simulate the lighting from a distance source such as the sun.
D3DLIGHT9 light;
// Initialize light properties
ZeroMemory( &light, sizeof(light) );
light.Type = D3DLIGHT_DIRECTIONAL;
light.Diffuse = D3DXCOLOR( … );
light.Specular = D3DXCOLOR( … );
light.Ambient = D3DXCOLOR( … );
light.Direction = D3DXVECTOR3( … ); // the direction the light will travel
// Enable the light
pd3dDevice->SetLight( 0, &light );
pd3dDevice->LightEnable( 0, true );
pd3dDevice->SetRenderState( D3DRS_SPECULARENABLE, true );
pd3dDevice->SetRenderState( D3DRS_LIGHTING, true );
Point Light
Point lights have a source, but no direction. Light emanates from a specified location within the scene’s world
coordinate system. Distance to the light source and attenuation are calculated. There is no single direction. Light is
provided equally in all directions from the source location.
D3DLIGHT9 light;
// Initialize light properties
ZeroMemory( &light, sizeof(light) );
light.Type = D3DLIGHT_POINT;
light.Diffuse = D3DXCOLOR( … );
light.Specular = D3DXCOLOR( … );
light.Ambient = D3DXCOLOR( … );
light.Position = D3DXVECTOR3( … ); // the location the light emanate from
light.Range = 100.0f; // don’t illuminate objects beyond 100 units
light.Attenuation1 = 1.0f; // simple attenuation
// Enable the light
pd3dDevice->SetLight( 0, &light );
pd3dDevice->LightEnable( 0, true );
pd3dDevice->SetRenderState( D3DRS_SPECULARENABLE, true );
pd3dDevice->SetRenderState( D3DRS_LIGHTING, true );
Graphics Section 11
©1991 – 2016 Garth Santor & Trinh Hān GATS Encyclopaedia 143 of 278
Light Attenuation
Attenuation controls how a light’s intensity diminishes with distance. Attenuation is determined using the formula
2
0 1 2
1attenuation
att att d att d
where d is the distance from the light source to the vertex being lit.
The standard attenuation values (though not default) are0 1 20, 1, 0att att att . Under no circumstances
should all attenuation values be zero.
Spot Light
Spot lights are similar to point lights in that they have a position within the scene (expressed in world
coordinates). They differ, however, in that they do not emanate in all directions, but have instead a
specific direction.
D3DLIGHT9 light;
// Initialize light properties
ZeroMemory( &light, sizeof(light) );
light.Type = D3DLIGHT_SPOT;
light.Diffuse = D3DXCOLOR( … );
light.Specular = D3DXCOLOR( … );
light.Ambient = D3DXCOLOR( … );
light.Direction = D3DXVECTOR3( … ); // the direction the light will travel
light.Position = D3DXVECTOR3( … ); // the location the light emanate from
light.Range = 100.0f; // don’t illuminate objects beyond 100 units
light.Attenuation1 = 1.0f; // simple attenuation
light.Falloff = 1.0f; // rate that cone diminishes
light.Theta = D3DX_PI / 20.0f; // inner cone
light.Phi = D3DX_PI / 10.0f; // outer cone
// Enable the light
pd3dDevice->SetLight( 0, &light );
pd3dDevice->LightEnable( 0, true );
pd3dDevice->SetRenderState( D3DRS_SPECULARENABLE, true );
pd3dDevice->SetRenderState( D3DRS_LIGHTING, true );
Performance
Each light type has performance consequences for your application. In general the light types exhibit the following performance levels:
Lowest cost Ambient
Low cost Directional
High cost Spot light†
Highest cost Point light†
innercone
outercone
Graphics Section 11
©1991 – 2016 Garth Santor & Trinh Hān GATS Encyclopaedia 144 of 278
†This depends on the amount of objects illuminated. Spot lights can have a higher cost than point lights if they illuminate large numbers of
objects.
General Light Tips
1. Minimize the number of light sources.
2. Prefer ambient light to more lights to increase overall light level in a scene.
3. Use the range parameter to limit a light to the parts of the scene that matters. This is particularly effective with spot lights.
4. Disable specular highlights. Specular highlight typically double the cost of a lighting effect.
5. Set D3DRS_LOCALVIEWER to false with orthographic projections. This will decrease the cost of the halfway vector calculations.
Meshes
Definition
A mesh is a collection of vertices defining some geometry; a set of indices defining the triangular faces and a set of attribute groups to differentiate
the material properties and textures of the faces.
D3DX supports four types of meshes, the standard mesh – ID3DXMesh, progressive meshes – ID3DXPMesh, simplification meshes –
ID3DXSPMesh and skinned meshes – ID3DXSkinMesh.
+CloneMesh()
+DrawSubset()
«interface»
ID3DXBaseMesh
«interface»
ID3DXPMesh
+CloneMesh()
«interface»
ID3DXSPMesh
«interface»
ID3DXMesh
Usage
Meshes are collections of vertices, face indices and attributes groups. We can decompose meshes into subsets on the base of attributes as in this
‘boat’ example.
Boat
Subset 0 - Hull Subset 1 - Mast Subset 2 - Sail
We can also decompose meshes into vertices, face indices and subset attribute groups.
Graphics Section 11
©1991 – 2016 Garth Santor & Trinh Hān GATS Encyclopaedia 145 of 278
2...40
Attribute Buffer: specifies subset
...320210 232221
...3210 23
Vertex Buffer: specifies geometery
Index Buffer: specifies vertex
Triangle 0 Triangle 1 Triangle 11
Coding struct TVertex
{
D3DXVECTOR3 xyz;
D3DXVECTOR3 nor;
D3DXVECTOR2 tex;
static const DWORD FVF = D3DFVF_XYZ | D3DFVF_NORMAL | D3DFVF_TEX1;
TVertex() { }
TVertex( FLOAT x, FLOAT y, FLOAT z, FLOAT nx, FLOAT ny, FLOAT nz, FLOAT t, FLOAT u )
: xyz(x,y,z), nor(nx,ny,nz), tex(t,u) { }
};
ID3DXMesh* pMesh;
IDirect3DTexture9* apTextures[nSubsets];
D3DXCreateMeshFVF( nFaces, nVertices, D3DXMESH_MANAGED, TVertex::FVF, m_pd3dDevice, &pMesh );
TVertex* v = 0;
pMesh->LockVertexBuffer( 0, (void**)&v );
v[0] = …;
…
v[nVertices-1] = …;
pMesh->UnlockVertexBuffer();
// create index buffer for the mesh
WORD* ind = 0;
pMesh->LockIndexBuffer( 0, (void**)&ind );
ind[0] = …;
…
ind[nFaces * 3 – 1] = …;
pMesh->UnlockIndexBuffer();
// assign triangles to subsets
DWORD* attr = 0;
pMesh->LockAttributeBuffer( 0, &attr );
Graphics Section 11
©1991 – 2016 Garth Santor & Trinh Hān GATS Encyclopaedia 146 of 278
attr[0] = …;
attr[nFaces - 1] = …;
pMesh->UnlockAttributeBuffer();
…
// rendering
m_pd3dDevice->BeginScene();
for( int i = 0; i != nSubsets; ++i )
{
m_pd3dDevice->SetTexture( 0, apTextures[ i ] );
pMesh->DrawSubset( i );
}
m_pd3dDevice->EndScene();
…
// cleanup
for( int i = 0; i != nSubsets; ++i )
apTextures[i]->Release();
pMesh->Release();
Optimization
The advantage of meshes is primary, their easy of use. However, this simplicity often results in inefficient ordering of vertices or primitives.
Recognizing this problem, the ID3DXMesh developers offer several mesh optimizations.
OptimizeInplace()
The simplest method for optimization is in-place optimization. Unlike ID3DXMesh::Optimize(), a new mesh is not created, but instead the
existing mesh is optimized in its current location. All that is required is an adjacency list and hints as to how the mesh should be optimized.
The adjacency list, which is normally generated from the initial mesh, contains information about face relationship. The list contains three entries
per face in the mesh. Each trio contains the face indices of triangles that share a common edge with that triangle.
The hints can be any of the following:
D3DXMESHOPT_COMPACT – This removes indices and vertices that are unreferenced by the mesh.
D3DXMESHOP_ATTRSORT – Sorts the faces by attribute. This will enhance the performance of DrawSubset commands.
D3DXMESHOPT_VERTEXCACHE – Increases the probability of a hit on the vertex cache.
D3DXMESHOPT_STRIPREORDER – Reorganizes the indices to maximize the length of triangle strips. This option cannot be used in
combination with D3DXMESHOPT_VERTEXCACHE.
D3DXMESHOPT_IGNOREVERTS – Optimize indices without optimizing vertices.
Graphics Section 11
©1991 – 2016 Garth Santor & Trinh Hān GATS Encyclopaedia 147 of 278
Coding (continued from previous example) // optimize mesh and produce an attribute table
std::vector<DWORD> adjacencyBuffer( m_pMesh->GetNumFaces() * 3 );
m_pMesh->GenerateAdjacency( 0.0f, &adjacencyBuffer[0] );
m_pMesh->OptimizeInplace( D3DXMESHOPT_ATTRSORT | D3DXMESHOPT_COMPACT |
D3DXMESHOPT_VERTEXCACHE, &adjacencyBuffer[0], 0, 0, 0 );
Primitives Primitives are the simplest graphical object that the system can render. Complex scenes are rendered by combining primitives to form more
elaborate objects.
In DirectX, primitives are points, lines and triangles. Primitives are described by vertex data and are usually grouped into collections. These
collections then impose an order or context for interpreting the relationship between individual vertices. The most common collections are lists,
fans, strips and meshes4. Most graphics systems also permit the order of vertices in a list to be determined by a separate index list.
Points – D3DPT_POINTLIST
Each vertex produces 1 point on
the display
nPoints nVertices
.
.
...
.
.
.
Lines – D3DPT_LINELIST
Vertices are taken in pairs to produce
a series of straight lines
2
nVerticesnLines
Lines – D3DPT_LINESTRIP
Vertices are connected one to the
next until the last vertices is reached.
1nLines nVertices
4 Meshes are typically handled by higher-level objects and not the graphics core.
Graphics Section 11
©1991 – 2016 Garth Santor & Trinh Hān GATS Encyclopaedia 148 of 278
Triangles –
D3DPT_TRIANGLELIST
Vertices are taken in triplets to
produce a series of triangles.
3
nVerticesnTriangles
Triangles –
D3DPT_TRIANGLESTRIP
The first triangle is formed from the
first three vertices. Successive
triangles are formed from the last
two vertices of the last triangle
rendered and a new vertex.
2nTriangles nVertices
A
B
C
D
E
F
G
H
Triangles –
D3DPT_TRIANGLEFAN
The first triangle is formed from the
first three vertices. Successive
triangles are formed from the last
vertex of the last triangle, a new
vertex and the first vertex.
2nTriangles nVertices
AB
C D E
F
Primitives can also be rendered with colour, lighting, textures, cell, vertex and pixel shaders.
Rendering Primitives Rendering primitives in Direct3D is a three-step process:
1. Defining a vertex structure.
Graphics Section 11
©1991 – 2016 Garth Santor & Trinh Hān GATS Encyclopaedia 149 of 278
2. Identifying a source of vertex data.
3. Calling IDirect3DDevice::DrawPrimitive*()
However, step two can be quite elaborate if vertex data is indexed and/or stored in video memory.
Method 1: user memory pointer.
The simplest method for drawing a primitive is also the least efficient, but we can get straight to drawing.
In step one; we must create a vertex structure. Here we create a transformed5 vertex structure.
struct TVertex {
FLOAT x, y, z, rhw;
DWORD color;
static const DWORD FVF = D3DFVF_XYZRHW | D3DFVF_DIFFUSE;
};
D3DX objects can also be used to simplify the vertex declaration.
struct TVertex {
D3DXVECTOR4 ver;
D3DCOLOR color;
static const DWORD FVF = D3DFVF_XYZRHW | D3DFVF_DIFFUSE;
};
The static constant is not stored as part of the vertex, but is accessible through the structure name; i.e. TVertex::FVF.
We inform the Direct3D run-time of our choice of vertex format with the IDirect3DDevice9::SetFVF() method.
In step two; we identify a source for vertex data. We can simply load an array with the appropriate data.
TVertex vertices[] = {
D3DXVECTOR4( 150.0f, 50.0f, 0.5f, 1.0f ), D3DCOLOR_ARGB( 255,255,0,0 ),
D3DXVECTOR4( 50.0f, 250.0f, 0.5f, 1.0f ), D3DCOLOR_ARGB( 255,0,0,255 ),
D3DXVECTOR4( 250.0f, 250.0f, 0.5f, 1.0f ), D3DCOLOR_ARGB( 255,0,255,0 ),
};
These vertices define a triangle with red, green and blue corners.
The third and last step is render the primitive with the IDirect3DDevice9::DrawPrimitiveUP() method. We must identify the type of
primitive to draw (more than one type can be generated from the same list of vertices) and the number of primitives to draw. We must also pass
the vertex stride. The stride is the number of bytes from the beginning of one vertex in the array to the beginning of the next vertex in the array.
Sometimes we ignore some the information packed in the vertex structure and we want the graphics core to jump over it in the list.
To draw a triangle from what we have, we must issue the DrawPrimiteUP within a BeginScene/EndScene pair. The complete code of an
OnFrameRender() would be:
void CALLBACK OnFrameRender( IDirect3DDevice9* pdev, double /*time*/, float /*elapsedTime*/ )
{
5 Transformed vertices do not require (or use) projection, view or world matrix transforms to be visible, however, they also cannot be rendered with lighting as
they are incompatible is surface normals.
Graphics Section 11
©1991 – 2016 Garth Santor & Trinh Hān GATS Encyclopaedia 150 of 278
pdev->Clear( 0, NULL, D3DCLEAR_TARGET | D3DCLEAR_ZBUFFER,
D3DCOLOR_XRGB(0,0,0), 1.0f, 0 );
if( SUCCEEDED( pdev->BeginScene() ) )
{
TVertex vertices[] = {
D3DXVECTOR4( 150.0f, 50.0f, 0.5f, 1.0f ), D3DCOLOR_ARGB( 255,255,0,0 ),
D3DXVECTOR4( 50.0f, 250.0f, 0.5f, 1.0f ), D3DCOLOR_ARGB( 255,0,0,255 ),
D3DXVECTOR4( 250.0f, 250.0f, 0.5f, 1.0f ), D3DCOLOR_ARGB( 255,0,255,0 ),
};
int nVertices = sizeof( vertices ) / sizeof( vertices[0] );
pdev->SetFVF( TVertex::FVF );
pdev->DrawPrimitiveUP( D3DPT_TRIANGLELIST, nVertices/3, (void*)vertices,
sizeof(TVertex) );
pdev->EndScene();
}
}
To draw the vertices as a line strip use:
pdev->DrawPrimitiveUP( D3DPT_LINESTRIP, nVertices-1, (void*)vertices,
sizeof(TVertex) );
Method 2: vertex buffer.
For this example we will use a global vertex buffer interface pointer:
IDirect3DVertexBuffer9* g_pVB = NULL;
The vertex buffer is created in OnResetDevice().
TVertex vertices[] = {
{ 150.0f, 50.0f, 0.5f, 1.0f, 0xffff0000, }, // x, y, z, rhw, color
{ 250.0f, 250.0f, 0.5f, 1.0f, 0xff00ff00, },
{ 50.0f, 250.0f, 0.5f, 1.0f, 0xff00ffff, },
};
V_RETURN( pd3dDevice->CreateVertexBuffer( 3 * sizeof(TVertex), 0, TVertex::FVF,
D3DPOOL_DEFAULT, &g_pVB, NULL ) );
VOID* pVertices = NULL;
V_RETURN( g_pVB->Lock( 0, sizeof(vertices), &pVertices, 0 ) );
memcpy( pVertices, vertices, sizeof(vertices) );
g_pVB->Unlock();
The vertex buffer is destroyed in OnLostDevice().
SAFE_RELEASE( g_pVB );
And rendered in OnFrameRender().
Graphics Section 11
©1991 – 2016 Garth Santor & Trinh Hān GATS Encyclopaedia 151 of 278
if( SUCCEEDED( pd3dDevice->BeginScene() ) )
{
// Render a triangle
pd3dDevice->SetStreamSource( 0, g_pVB, 0, sizeof(TVertex) );
pd3dDevice->SetFVF( TVertex::FVF );
pd3dDevice->DrawPrimitive( D3DPT_TRIANGLELIST, 0, 1 );
V( pd3dDevice->EndScene() );
}
Sprites – ID3DXSprite The ID3DXSprite object works in concert with IDirect3DTexture9 objects to provide a rudimentary sprite engine for Direct3D.
Setup
The ID3DXSprite object is created on an IDirect3DDevice9 object. If the IDirect3DDevice9 object is lost we should call
ID3DXSprite::OnLostDevice() to cleanup the sprite object’s state in preparation for a device reset. After reset, we can call
ID3DXSprite::OnResetDevice() to ready the sprite object for rendering.
The location at which a sprite will be drawn is determined by a set of transform methods.
SetTransform( D3DXMATRIX* ) – an all-in-one world-space transform setup.
SetWorldViewLH( D3DXMATRIX* pWorld, D3DXMATRIX* pView ) – customizes the world and view transforms for a left-hand
system.
SetWorldViewRH( D3DXMATRIX* pWorld, D3DXMATRIX* pView ) – customizes the world and view transforms for a right-hand
system.
The last two transforms are only required if the sprite is rendering using D3DXSPRITE_BILLBOARD, D3DXSPRITE_SORT_DEPTH_xxxx.
The transforms are stored in the object’s state and can be initialized prior to rendering.
Rendering g_pSprite->Begin( 0 );
g_pSprite->Draw( g_pTexture, NULL, NULL, NULL, 0xFFFFFFFF );
g_pSprite->End();
Textures with an alpha channel can be rendered by changing the parameter of ID3DXSprite::Begin() to D3DXSPRITE_ALPHABLEND.
DX-SDK 9.0c: Call D3DXCreateSprite() in OnCreateDevice() and release in OnDestroyDevice(). Call
ID3DXSprite::OnLostDevice() in OnLostDevice() and ID3DXSprite::OnResetDevice() in OnResetDevice().
DX-SDK 9.0b: Call D3DXCreateSprite() in InitDeviceObjects() and release in DeleteDeviceObjects(). Call
ID3DXSprite::OnLostDevice() in InvalidateDeviceObjects() and ID3DXSprite::OnResetDevice() in
RestoreDeviceObjects().
Graphics Section 11
©1991 – 2016 Garth Santor & Trinh Hān GATS Encyclopaedia 152 of 278
Surfaces – Direct writes to the back-buffer DirectX 9.0
By default, the back buffer in DirectX is not directly writable. To make the back-buffer writable we must create the device with the presentation
parameter D3DPRESENTFLAG_LOCKABLE_BACKBUFFER.
DX-SDK9.0c: To create a device with a lockable back-buffer, you’ll have to write a ModifyDeviceSettings callback function and register it in the
call to DXUTCreateDevice().
void CALLBACK ModifyDeviceSettings( DXUTDeviceSettings *pDeviceSettings,
const D3DCAPS9* pCaps )
{
pDeviceSettings->pp.Flags |= D3DPRESENTFLAG_LOCKABLE_BACKBUFFER;
}
The back buffer’s actual location in video RAM is not fixed, so writing to it will require locking the buffer and acquiring a pointer to the buffer
once locked. This cannot be done while a scene is being rendered as BeginScene() locks the back buffer itself.
The code for locking and accessing the back buffer is:
IDirect3DSurface9* pBackBuffer = 0;
if( SUCCEEDED( pd3dDevice->GetBackBuffer( 0/*swap-chain*/, 0 /* first back buffer */,
D3DBACKBUFFER_TYPE_MONO, &pBackBuffer ) ) )
{
D3DLOCKED_RECT lockedRect;
pBackBuffer->LockRect( &lockedRect, NULL /* entire surface */, 0 );
And the code to unlock and release the back buffer is:
pBackBuffer->UnlockRect();
pBackBuffer->Release();
}
Once locked the D3DLOCKED_RECT object will contain a pointer to the back-buffer: pBits and the number of bytes in a single row or line of
back-buffer: Pitch. The location of a specific pixel can be calculated using the following byte-offset formula:
byteoffset y pitch x bytesperpixel
This byte offset is then added to pBits – the address of the beginning of the back-buffer.
Since the resulting address is of type void*, we cannot dereference it. We must first convert to a pointer of the correct size for the current pixel
colour depth. (e.g. a 32-bit colour scheme would use type INT32, DWORD, or unsigned long. Any of the 32-bit integer types.)
int byteOffset = y * lockedRect.Pitch + x * sizeof(INT32);
void* address = lockedRect.Pitch + byteOffset;
INT32* p = reinterpret_cast<INT32*>( address );
Finally, the colour can be written to the pixel’s memory location.
*p = (INT32)color;
Graphics Section 11
©1991 – 2016 Garth Santor & Trinh Hān GATS Encyclopaedia 153 of 278
Tuning Tips (Optimization)
Lighting
1. When multiple light models can achieve the same effect, prefer:
a. ambient lighting to all others.
b. directional lighting to spot or point lighting.
c. spot lighting to point lighting when there are few objects caught by the light source.
d. point lighting to spot lighting when there are many objects caught by the light source.
2. Use ambient lighting to control the overall brightness of a scene.
3. Minimize the number of light sources.
4. Use the range parameter to limit a point or spot light to the part of the scene that matters.
5. Disable specular highlights.
6. Set D3DRS_LOCALVIEWER to false with orthographic projections. This will decrease the cost of the halfway vector calculations.
Textures
1. Texture load time can be improved by scaling and formatting images with a photo-editing tool.
2. Some hardware requires power-of-2 dimensions (e.g. 256 × 256), so store textures in a power-of-2 dimension.
3. Use Microsoft’s DDS format to store images. DDS can store any DirectX 9.0 texture format including mipmaps. It is also the easiest format
for D3DX to read. Its mipmap storage capabilities allow you use mipmap generation algorithms that may be more advanced than D3DX’s
algorithm.
4. Resample textures to a smaller size, thereby reducing the number of texels processed when mapping to a surface.
Direct3D 10.0 Programming
API Differences between Direct3D 9 and Direct3D 10
Direct3D 9 Direct3D 10
IDirect3DDevice9 ID3D10Device – methods are prefixed to indicate subsystem.
IA = Input Assembler
VS = Vertex Shader
GS = Geometry Shader
Graphics Section 11
©1991 – 2016 Garth Santor & Trinh Hān GATS Encyclopaedia 154 of 278
SO = Stream Out
RS = Rasterizer Stage
PS = Pixel Shader
OM = Output Merger
IDirect3D9 IDXGIFactory, IDXGIAdapter, IDXGIDevice
IDirect3DDevice9::Present IDXGISwapChain::Present
IDirect3DDevice9::TestCooperativeLevel IDXGISwapChain::Present with PRESENT_TEST
IDirect3DBaseTexture9
IDirect3DTexture9
IDirect3DCubeTexture9
IDirect3DVolumeTexture9
IDirect3DIndexBuffer9
IDirect3DVertexBuffer9
ID3D10Buffer
ID3D10Texture1D
ID3D10Texture2D
ID3D10Texture3D
IDirect3DVertexShader9 ID3D10VertexShader
IDirect3DPixelShader9 ID3D10PixelShader
N/A ID3D10GeometryShader
IDirect3DVertexDeclaration9 ID3D10InputLayout
IDirect3DDevice9::SetRenderState ID3D10BlendState
ID3D10DepthStencilState
ID3D10RasterizerState
IDirect3DDevice9::SetTextureStageState ID3D10SamplerState
IDirect3DDevice9::DrawIndexedPrimitive
IDirect3DDevice9::DrawPrimitive
ID3D10Device::Draw
ID3D10Device::DrawIndexed
ID3D10Device::DrawIndexedInstanced
ID3D10Device::DrawInstanced
ID3D10Device::IASetPrimitiveTopology
Triangle fans are no longer supported
Graphics Section 11
©1991 – 2016 Garth Santor & Trinh Hān GATS Encyclopaedia 155 of 278
N/A ID3D10Device::DrawAuto
IDirect3DDevice9::BeginScene
IDirect3DDevice9::EndScene
IDirect3DDevice9::PrimitiveUP
IDirect3DDevice9::DrawIndexedPrimitiveUP
Removed
IDirect3DDevice9::ShowCursor
IDirect3DDevice9::SetCursorPosition
IDirect3DDevice9::SetCursorProperties
Removed: Win32 mouse cursors now work with Direct3D
IDirect3DDevice9::Reset No more LOST DEVICE cases
IDirect3DDevice9::DrawRectPatch
IDirect3DDevice9::DrawTriPatch
IDirect3DDevice9::LightEnable
IDirect3DDevice9::MultiplyTransform
IDirect3DDevice9::SetLight
IDirect3DDevice9::SetMaterial
IDirect3DDevice9::SetNPatchMode
IDirect3DDevice9::SetTransform
IDirect3DDevice9::SetFVF
Removed
IDirect3DDevice9::CheckDepthStencilMatch
IDirect3DDevice9::CheckDeviceFormat
IDirect3DDevice9::GetDeviceCaps
IDirect3DDevice9::ValidateDevice
Cap bits removed.
Only a few formats usage cases are optional. Check with
ID3D10Device::CheckFormatSupport
File Formats
RAW RAW files have the simplest format for storing graphics image data. RAW files contain pixel data only. The only variation in the format is the
number of bits or bytes used to store a single pixel. The most common pixel size is a single byte per pixel.
Graphics Section 11
©1991 – 2016 Garth Santor & Trinh Hān GATS Encyclopaedia 156 of 278
RAW files are useful since there is no header to decode (or bypass), no compression and no encryption. Raw files are simple! Loading a RAW
file usually requires a single function call.
The down-side of RAW files is that the application must acquire information about the dimensions of the image from another source (or have the
information hard-coded).
Organization
RAW files usually represent two-dimensional images.
However, the data is stored as a one-dimensional vector. By convention, graphical image editors
such as Adobe Photoshop interpret the first element as the top-left pixel. The next element is the
second pixel in the first row. The last element is the bottom-right pixel.
A mapping from x, y coordinates to offsets and back can be produced if an image width can be
assumed.
xowpixelsPerRyoffset or,
colowpixelsPerRrowoffset
And the reverse…
owpixelsPerR
offsetyrow
owpixelsPerRoffsetxcol mod
X-file Direct3D
Introduction
X files were introduced in DirectX 2.0 with a binary format appearing in DirectX 3.0. DirectX 6.0 introduced interfaces that facilitated reading
from and writing to .x files.
X files enable a DirectX programmer to store:
meshes
textures
animations
user-defined objects
X files are template driven and support instancing (multiple references to an object) and hierarchies.
0,0:0 63,0:63
63,63:40950,63:4032A 4KB RAW file showing
x,y:offset.
Width and height are 64 pixels
Graphics Section 11
©1991 – 2016 Garth Santor & Trinh Hān GATS Encyclopaedia 157 of 278
Format
X files use this format:
1. header
2. user templates
3. data objects
Header
For a text-based x file (the only format we will discuss), the header is composed of the ‘magic-number’, the version numbers, encoding tag and
float size indicator.
e.g. xof 0303txt 0032
magic number xof ‘x’ object file
major version number 03 latest version as of DirectX
9.0
minor version number 03 latest version as of DirectX
9.0
encoding tag txt Text encoding
float size indicator 0032 use IEEE 32-bit floats
Data Objects
A comprehensive list of data objects can be found in the DirectX SDK Help.
DirectX Graphics
Reference
X File Reference
X File Format Reference
X File Templates
Mesh
The most common x file template is the mesh.
A general format is:
Mesh meshname {
number-of-vertices;
x0; y0; z0;,
x1; y1; z1;,
…
xn-1; yn-1; zn-1;;
Graphics Section 11
©1991 – 2016 Garth Santor & Trinh Hān GATS Encyclopaedia 158 of 278
number-of-faces;
3; a0, b0, c0;,
3; a1, b1, c1;,
…
3; an-1, bn-1, cn-1;;
MeshMaterialList {
number-of-materials;
number-of-faces;
materialf0, // material for face 0
materialf1, // material for face 1
…
materialfn-1; // material for the last face
Material {
red; green; blue; alpha; ; // face color
shininess;
red; green; blue; // specular
red; green; blue; // emissive
}
}
}
Example:
xof 0303txt 0032
Mesh Square {
4; // number of vertices
-1.0; -1.0; 0.0;, // vertex 0
-1.0; 1.0; 0.0;, // vertex 1
1.0; 1.0; 0.0;, // vertex 2
1.0; -1.0; 0.0;; // vertex 3
2; // number of triangles
3;0,1,2;, // triangle #1
3;0,2,3;; // triangle #2
MeshMaterialList {
1; // one material
2; // two faces
0, // face #0 use material #0
0;;
Material
{
0.0; 1.0; 0.0; 1.0;; // face color
0.0; // power
0.0; 0.0; 0.0;; // specular
0.0; 0.0; 0.0;; // emissive color
}
}
}
Graphics Section 11
©1991 – 2016 Garth Santor & Trinh Hān GATS Encyclopaedia 159 of 278
Materials
Materials can be placed outside of a Mesh block then referenced by name.
Material materialname {
red; green; blue; alpha; ; // face color
shininess;
red; green; blue; // specular
red; green; blue; // emissive
}
Mesh meshname {
number-of-vertices;
x0; y0; z0;,
x1; y1; z1;,
…
xn-1; yn-1; zn-1;;
number-of-faces;
3; a0, b0, c0;,
3; a1, b1, c1;,
…
3; an-1, bn-1, cn-1;;
MeshMaterialList {
number-of-materials;
number-of-faces;
materialf0, // material for face 0
materialf1, // material for face 1
…
materialfn-1; // material for the last face
{materialname}
}
}
Normals
Normals can be recorded as part of the mesh data;
Mesh meshname {
number-of-vertices;
x0; y0; z0;,
x1; y1; z1;,
…
xn-1; yn-1; zn-1;;
number-of-faces;
3; a0, b0, c0;,
3; a1, b1, c1;,
…
3; an-1, bn-1, cn-1;;
MeshNormals {
Graphics Section 11
©1991 – 2016 Garth Santor & Trinh Hān GATS Encyclopaedia 160 of 278
number-of-normals;
x0; y0; z0;,
x1; y1; z1;,
…
xn-1; yn-1; zn-1;;
}
}
Example xof 0303txt 0032
Material Red {
1.0;0.0;0.0;0.0;;
0.0;
1.0;0.0;0.0;;
0.0;0.0;0.0;;
}
Material Green {
0.0;1.0;0.0;0.0;;
0.0;
1.0;0.0;0.0;;
0.0;0.0;0.0;;
}
Material Blue {
0.0;0.0;1.0;0.0;;
0.0;
1.0;0.0;0.0;;
0.0;0.0;0.0;;
}
Mesh Cube {
24;
-1.0;-1.0;-1.0;,
-1.0;-1.0;1.0;,
-1.0;1.0;1.0;,
-1.0;1.0;-1.0;,
-1.0;1.0;-1.0;,
-1.0;1.0;1.0;,
1.0;1.0;1.0;,
1.0;1.0;-1.0;,
1.0;1.0;-1.0;,
1.0;1.0;1.0;,
1.0;-1.0;1.0;,
1.0;-1.0;-1.0;,
-1.0;-1.0;1.0;,
-1.0;-1.0;-1.0;,
1.0;-1.0;-1.0;,
1.0;-1.0;1.0;,
Graphics Section 11
©1991 – 2016 Garth Santor & Trinh Hān GATS Encyclopaedia 161 of 278
-1.0;-1.0;1.0;,
1.0;-1.0;1.0;,
1.0;1.0;1.0;,
-1.0;1.0;1.0;,
-1.0;-1.0;-1.0;,
-1.0;1.0;-1.0;,
1.0;1.0;-1.0;,
1.0;-1.0;-1.0;;
12;
3;0,1,2;,
3;2,3,0;,
3;4,5,6;,
3;6,7,4;,
3;8,9,10;,
3;10,11,8;,
3;12,13,14;,
3;14,15,12;,
3;16,17,18;,
3;18,19,16;,
3;20,21,22;,
3;22,23,20;;
MeshNormals {
24;
-1.000000;0.000000;0.000000;,
-1.000000;0.000000;0.000000;,
-1.000000;0.000000;0.000000;,
-1.000000;0.000000;0.000000;,
0.000000;1.000000;0.000000;,
0.000000;1.000000;0.000000;,
0.000000;1.000000;0.000000;,
0.000000;1.000000;0.000000;,
1.000000;0.000000;0.000000;,
1.000000;0.000000;0.000000;,
1.000000;0.000000;0.000000;,
1.000000;0.000000;0.000000;,
0.000000;-1.000000;0.000000;,
0.000000;-1.000000;0.000000;,
0.000000;-1.000000;0.000000;,
0.000000;-1.000000;0.000000;,
0.000000;0.000000;1.000000;,
0.000000;0.000000;1.000000;,
0.000000;0.000000;1.000000;,
0.000000;0.000000;1.000000;,
0.000000;0.000000;-1.000000;,
0.000000;0.000000;-1.000000;,
0.000000;0.000000;-1.000000;,
0.000000;0.000000;-1.000000;;
12;
3;0,1,2;,
3;2,3,0;,
Graphics Section 11
©1991 – 2016 Garth Santor & Trinh Hān GATS Encyclopaedia 162 of 278
3;4,5,6;,
3;6,7,4;,
3;8,9,10;,
3;10,11,8;,
3;12,13,14;,
3;14,15,12;,
3;16,17,18;,
3;18,19,16;,
3;20,21,22;,
3;22,23,20;;
}
MeshMaterialList {
3;
12;
0,
0,
1,
1,
0,
0,
1,
1,
2,
2,
2,
2;
{Red}
{Green}
{Blue}
}
VertexDuplicationIndices {
24;
8;
0,
1,
2,
3,
3,
2,
6,
7,
7,
6,
10,
11,
1,
0,
11,
10,
Graphics Section 11
©1991 – 2016 Garth Santor & Trinh Hān GATS Encyclopaedia 163 of 278
1,
10,
6,
2,
0,
3,
7,
11;
}
}
Sample Framework DX-SDK 9.0c Install the EmptyProject sample from the DirectX Sample Browser.
The minimal functioning complete main is:
#include "dxstdafx.h"
#include "resource.h"
INT WINAPI WinMain( HINSTANCE, HINSTANCE, LPSTR, int )
{
DXUTInit();
DXUTCreateWindow();
DXUTCreateDevice();
DXUTMainLoop();
return DXUTGetExitCode();
}
Graphics Section 11
©1991 – 2016 Garth Santor & Trinh Hān GATS Encyclopaedia 164 of 278
Sequence of events
Changing the window caption DXUTCreateWindow( L"DX9cFramework" );
Note that the string is a Unicode string.
DXUTCreateWindow
DXUTCreateDevice
RegisterClassEx()
CreateWindow()
ShowWindow()
UpdateWindow()
creates IDirect3D9 object
enumerates devices
chooses optimal mode
creates IDirect3DDevice9 object
OnCreateDevice()
OnResetDevice()
DXUTMainLoop()Win32 message pump
Normal execution
OnLostDevice()
OnDestroyedDevice()
Window resize
OnLostDevice()
Resize
OnResetDevice()
OnLostDevice()
Mode Change
OnResetDevice()
OnDestroyedDevice()
OnCreatedDevice()
OnFrameMove()
OnFrameRender()
Mode change
Quit
Graphics Section 11
©1991 – 2016 Garth Santor & Trinh Hān GATS Encyclopaedia 165 of 278
Default Framework Windows Message Handler
The default message handler installed by the framework handles the following messages:
WM_KEYDOWN
WM_SYSKEYDOWN
WM_KEYUP
WM_SYSKEYUP
WM_LBUTTONDOWN
WM_LBUTTONUP
WM_LBUTTONDBLCLK
WM_MBUTTONDOWN
WM_MBUTTONUP
WM_MBUTTONDBLCLK
WM_RBUTTONDOWN
WM_RBUTTONUP
WM_RBUTTONDBLCLK
WM_XBUTTONDOWN
WM_XBUTTONUP
WM_XBUTTONDBLCLK
WM_MOUSEWHEEL
WM_MOUSEMOVE
WM_PAINT
WM_SIZE
WM_GETMINMAXINFO
WM_ENTERSIZEMOVE
WM_EXITSIZEMOVE
WM_SETCURSOR
WM_ACTIVATEAPP
WM_ENTERMENULOOP
WM_EXITMENULOOP
WM_NCHITTEST
WM_POWERBROADCAST
WM_SYSCOMMAND
WM_SYSCHAR
WM_CLOSE
WM_DESTROY
Custom device setting on start-up
A full screen 800x600 display can be the starting resolution with the line:
DXUTCreateDevice( D3DADAPTER_DEFAULT, false, 800, 600 );
Showing the cursor full screen
Place the line:
DXUTSetCursorSettings( true, true );
Before the line:
DXUTInit();
Rendering
Rendering is accomplished by registering a render callback function. This function has the signature:
void CALLBACK OnFrameRender( IDirect3DDevice9* pd3dDevice,
double fTime, float fElapsedTime )
This function is called once per frame or during a WM_PAINT.
We register the function with the statement:
DXUTSetCallbackFrameRender( OnFrameRender );
The callback registration must occur before the main loop (message pump) is executed.
NOTE: This is the point at which the V( ) macro is first used. The V( ) macro requires that a local scope variable of the type HRESULT with the
identifier ‘hr’ be defined.
Text
Render text requires the creation and management of a font object. The framework does not provide a font object but readily supports the D3DX
object ID3DXFont.
Graphics Section 13
©1991 – 2016 Garth Santor & Trinh Hān GATS Encyclopaedia 166 of 278
The font object requires an IDirect3DDevice9 object during creation and also need attention during device reset and device loss. Callback
functions must be registered for object creation and maintenance. Place the following the ‘WinMain’ function:
DXUTSetCallbackDeviceCreated( OnCreateDevice );
DXUTSetCallbackDeviceDestroyed( OnDestroyDevice );
DXUTSetCallbackDeviceReset( OnResetDevice );
DXUTSetCallbackDeviceLost( OnLostDevice );
Declare a global font object:
ID3DXFont* g_pFont = NULL; // Font for drawing text
The create the following functions containing the font creation and maintenance code:
HRESULT CALLBACK OnCreateDevice( IDirect3DDevice9* pd3dDevice,
const D3DSURFACE_DESC* pBackBufferSurfaceDesc )
{
HRESULT hr;
// Initialize the font
V_RETURN( D3DXCreateFont( pd3dDevice, 15, 0, FW_BOLD, 1, FALSE,
DEFAULT_CHARSET, OUT_DEFAULT_PRECIS, DEFAULT_QUALITY,
DEFAULT_PITCH | FF_DONTCARE, L"Arial", &g_pFont ) );
return S_OK;
}
HRESULT CALLBACK OnResetDevice( IDirect3DDevice9* pd3dDevice,
const D3DSURFACE_DESC* pBackBufferSurfaceDesc )
{
HRESULT hr;
if( g_pFont )
V_RETURN( g_pFont->OnResetDevice() );
return S_OK;
}
void CALLBACK OnLostDevice()
{
if( g_pFont )
g_pFont->OnLostDevice();
}
void CALLBACK OnDestroyDevice()
{
SAFE_RELEASE( g_pFont );
}
GUI Controls
GUI Controls can be added to your system using the CDXUTDialog framework.
Create a dialog object:
CDXUTDialog g_GUI;
Graphics Section 13
©1991 – 2016 Garth Santor & Trinh Hān GATS Encyclopaedia 167 of 278
This object serves the same purpose as a Windows dialog box. It hosts a set of controls and manages their I/O playing host to their message
handler.
Next we’ll add a control to the dialog. We’ll add a button that toggles between full-screen and windowed mode. In the application initialization
function (performed before the window is created), issue the following command.
g_GUI.AddButton( IDC_TOGGLEFULLSCREEN, L"Toggle full screen", X, Y, W, H );
IDC_TOGGLEFULLSCREEN is an ordinal (I use an enum) identifying the control. The X and Y coordinates are relative to the dialog location
which defaults to the location (0, 0).
The control must now be rendered by issuing the command:
V( g_GUI.OnRender( fElapsedTime ) );
Place this command in your OnFrameRender method between calls to BeginScene and EndScene.
This dialog location by default anchors on the top-left corner of the display. We can change this by resetting the dialog anchor in the
OnResetDevice callback.
g_GUI.SetLocation( pBackBufferSurfaceDesc->Width-125, 0 );
You will notice at this point that the control is inactive. We must redirect mouse and keyboard events to the dialog to get a response. For this we
need a custom message handler for the application. The callback and registration look like this.
LRESULT CALLBACK MsgProc( HWND hWnd, UINT uMsg, WPARAM wParam, LPARAM lParam,
bool* pbNoFurtherProcessing )
{
// Give the dialogs a chance to handle the message first
*pbNoFurtherProcessing = g_GUI.MsgProc( hWnd, uMsg, wParam, lParam );
if( *pbNoFurtherProcessing )
return 0;
return 0;
}
DXUTSetCallbackMsgProc( MsgProc );
This callback is called prior to the frameworks own application window message handler. The if(*pbNoFurtherProcessing) statement
provided to stop the framework from processing message that has already been consumed by a previous handler.
Next, we must create and register an event handler for the GUI. The event handler signature is:
void CALLBACK OnGUIEvent( UINT nEvent, int nControlID, CDXUTControl* pControl );
For now we’ll just use the second parameter ‘int nControlID’ to identify the button that we had created in a handler that toggles from
windowed to full-screen mode on each click of the button.
void CALLBACK OnGUIEvent( UINT, int nControlID, CDXUTControl* )
{
switch( nControlID )
{
case IDC_TOGGLEFULLSCREEN: DXUTToggleFullScreen(); break;
}
Graphics Section 13
©1991 – 2016 Garth Santor & Trinh Hān GATS Encyclopaedia 168 of 278
}
As always, the handler must be registered.
g_GUI.SetCallback( OnGUIEvent );
Which can be done at any time prior to the execution of the main loop.
Sound
The new framework also provides abstractions for sound, although it is largely a rehash of the previous framework.
After confirming that the files DXUTsound.h and DXUTsound.cpp are part of the project, add the line: ‘#pragma comment (lib,"dsound.lib")’
somewhere into your project.6
The framework requires a minimum of two objects to play a sound file. First, a CSoundManager object that represents the DirectSound system
as a whole and a CSound object that represents the specific sound or sound file.
CSoundManager sm;
The sound manager needs to be initialized and connected and configured for an application window.
sm.Initialize( hwnd, DSSCL_NORMAL );
The DSSCL_ constants are those defined for IDirectSound8::SetCooperativeLevel().
The sound object itself is created from the sound manager object.
CSound* ps;
sm.Create( &ps, L"File.wav" );
The sound object can now be played and stopped using sound object interface.
ps->Play();
ps->Play( 0, DSBPLAY_LOOPING );
if( ps->IsSoundPlaying() )
ps->Stop();
Cleanup is a relatively simple matter, just delete the sound objects. If you are going to reuse a sound object, stop it, reset it
(CSound::Reset()) then reuse it.
Sample Framework DX-SDK < 9.0c
Introduction
Microsoft has provided programmers with a decent application framework for developing real-time Direct3D based applications. However, the
framework requires the programmer to accept some ugly code dependencies. We will start by identifying what files are required by the DirectX
SDK Common Samples (from here on, the DXCS).
6 I put this line in the DXUTsound.cpp file.
Graphics Section 13
©1991 – 2016 Garth Santor & Trinh Hān GATS Encyclopaedia 169 of 278
Building a Project
To build a project with DXCS we need to collect the appropriate files, make some modifications to those files and then write a main program.
File Manifest
The files listed in this manifest should be deposited into the project’s directory.
File Type Folder and File Names
Manifest \DXSDK\Samples\C++\Direct3D\Billboard\billboard.manifest
Resource \DXSDK\Samples\C++\Direct3D\Billboard\winmain.rc
\DXSDK\Samples\C++\Common\directx.ico
Header \DXSDK\Samples\C++\Common\Include\
d3dapp.h
d3denumeration.h
d3dres.h
d3dsettings.h
d3dutil.h
dxutil.h
resource.h
Source \DXSDK\Samples\C++\Common\Src\
d3dapp.cpp
d3denumeration.cpp
d3dsettings.cpp
d3dutil.cpp
dxutil.cpp
Fix Dependencies
Edit the files with the following instructions.
File Tasks billboard.manifest Copy any of the manifest files from a sample to your project folder (e.g.
\DXSDK\Samples\C++\Direct3D\Fur\Fur.manifest).
Rename the file to myprogram.manifest.
winmain.rc Rename the manifest reference to myprogram.manifest.
Fixed the icon reference (delete the relative path).
d3dapp.h Add the following includes: "d3denumeration.h", "d3dsettings.h"
d3denumeration.h Add the following includes: <d3d9.h>, "dxutil.h"
d3dapp.cpp Add ‘pragma comment (lib,"d3d9.lib")’
dxutil.cpp Add ‘pragma comment (lib,"winmm.lib")’
d3dutil.cpp Add ‘pragma comment (lib,"d3dx9.lib")’
Create a WinMain #define STRICT
#include <windows.h>
Graphics Section 13
©1991 – 2016 Garth Santor & Trinh Hān GATS Encyclopaedia 170 of 278
#include <commctrl.h>
#pragma comment (lib,"comctl32.lib")
#include "d3dapp.h"
class CMyApp : public CD3DApplication
{
};
INT WINAPI WinMain( HINSTANCE hInst, HINSTANCE, LPSTR, INT )
{
CMyApp d3dApp;
InitCommonControls();
if( FAILED( d3dApp.Create( hInst ) ) )
return 0;
return d3dApp.Run();
}
Understanding the Common Sample Architecture
The common sample architecture implements a standard, albeit simple game-loop architecture.
Initialization is implemented in the methods:
OneTimeSceneInit()
InitDeviceObjects()
RestoreDeviceObjects()
Game logic is implemented in the FrameMove() method.
Rendering is implemented in the Render() method.
Shutdown is implemented in the methods:
InvalidateDeviceObjects()
DeleteDeviceObjects()
FinalCleanup()
Initialization and Shutdown are separated into 3 methods each since some cleanup is required
when an application is minimized or resized. This approach allows the common sample architecture
to rebuild graphical objects on an as-needed basis. The key framework methods are called under the
following circumstances:
Startup
1. The application object’s constructor.
Initialization
Quit?
Game Logic
no
Render
Shutdownyes
start
end
Graphics Section 13
©1991 – 2016 Garth Santor & Trinh Hān GATS Encyclopaedia 171 of 278
2. ConfirmDevice()
3. OneTimeSceneInit()
4. InitDeviceObjects()
5. RestoreDeviceObjects()
Normal Execution
1. FrameMove()
2. Render()
Window-resize
1. InvalidateDeviceObjects()
2. RestoreDeviceObjects()
Change of video mode
1. InvalidateDeviceObjects()
2. DeleteDeviceObjects()
3. InitDeviceObjects()
4. RestoreDeviceObjects()
Shutdown
1. InvalidateDeviceObjects()
2. DeleteDeviceObjects()
3. FinalCleanUp()
4. The application object’s destructor.
Other Components
The common sample architecture contains other useful DirectX components, both graphical and otherwise.
Fonts
The first step to using the font management classes is to bind the code to your project. Add d3dfont.cpp and d3dfont.h to your project.
The CD3DFont class constructor has two required parameters – firstly, the font type face and secondly, the character height measured in pixels.
Since these values are generally not known at compile time, create a pointer to your font class, as you may have to recreate it at run-time.7
You must now call the following CD3DFont methods in the corresponding CD3DApplication methods:
7 A smart pointer such as boost::scoped_ptr is recommended.
Graphics Section 13
©1991 – 2016 Garth Santor & Trinh Hān GATS Encyclopaedia 172 of 278
InitDeviceObjects
RestoreDeviceObjects
DeleteDeviceObjects
InvalidateDeviceObjects
Drawing operations are performed between a BeginScene() / EndScene() sandwich.
Music
CMusicManager mm;
CMusicSegment* pms;
mm.Initialize( hwnd );
mm.CreateSegmentFromFile( &pms, "sound1.wav", TRUE, FALSE );
pms->SetRepeats( 0 );
pms->Play();
delete pms;
Note that CMusicManager and CMusicSegment require dxguid.lib to be linked.
Input with CInputDeviceManager
CInputDeviceManager abstracts the uses of Direct Input 8 action mapping.
#include "diutil.h"
Link: diutil.cpp, dxutil.h
Dependencies: dxutil.h, dxutil.cpp
Overview
When using action-maps, DirectInput notifies the application only when an object’s state changes. Therefore the application is required to record
the state of the input device (i.e. whether a button is up or down.)
Multiple devices can be used to control the game object. Each device is likely to record a user action differently. Therefore we abstract input to
another level – the user state.
Declarations – CMyApp
There are fours parts to declaring input:
1. data structures definitions
2. map definition
3. objects
Graphics Section 13
©1991 – 2016 Garth Santor & Trinh Hān GATS Encyclopaedia 173 of 278
4. methods
struct InputDeviceState
{
FLOAT fAxisRotateLR;
BOOL bButtonRotateLeft;
BOOL bButtonRotateRight;
FLOAT fAxisRotateUD;
BOOL bButtonRotateUp;
BOOL bButtonRotateDown;
BOOL bButtonPlaySoundButtonDown;
};
struct UserInput
{
FLOAT fAxisRotateUD;
FLOAT fAxisRotateLR;
BOOL bPlaySoundButtonDown;
BOOL bDoConfigureInput;
BOOL bDoConfigureDisplay;
};
The map definition:
enum INPUT_SEMANTICS
{
// Gameplay semantics
// TODO: change as needed
INPUT_ROTATE_AXIS_LR=1, INPUT_ROTATE_AXIS_UD,
INPUT_ROTATE_LEFT, INPUT_ROTATE_RIGHT,
INPUT_ROTATE_UP, INPUT_ROTATE_DOWN,
INPUT_CONFIG_INPUT, INPUT_CONFIG_DISPLAY,
INPUT_PLAY_SOUND,
};
// Actions used by this app
DIACTION g_rgGameAction[] =
{
// TODO: change as needed. Be sure to delete user map files
// (C:\Program Files\Common Files\DirectX\DirectInput\User Maps\*.ini)
// after changing this, otherwise settings won't reset and will be read
// from the out of date ini files
// Device input (joystick, etc.) that is pre-defined by DInput, according
// to genre type. The genre for this app is space simulators.
{ INPUT_ROTATE_AXIS_LR, DIAXIS_3DCONTROL_LATERAL, 0, TEXT("Rotate left/right"), },
{ INPUT_ROTATE_AXIS_UD, DIAXIS_3DCONTROL_MOVE, 0, TEXT("Rotate up/down"), },
{ INPUT_PLAY_SOUND, DIBUTTON_3DCONTROL_SPECIAL, 0, TEXT("Play sound"), },
// Keyboard input mappings
{ INPUT_ROTATE_LEFT, DIKEYBOARD_LEFT, 0, TEXT("Rotate left"), },
{ INPUT_ROTATE_RIGHT, DIKEYBOARD_RIGHT, 0, TEXT("Rotate right"), },
{ INPUT_ROTATE_UP, DIKEYBOARD_UP, 0, TEXT("Rotate up"), },
{ INPUT_ROTATE_DOWN, DIKEYBOARD_DOWN, 0, TEXT("Rotate down"), },
{ INPUT_PLAY_SOUND, DIKEYBOARD_F5, 0, TEXT("Play sound"), },
{ INPUT_CONFIG_DISPLAY, DIKEYBOARD_F2, DIA_APPFIXED, TEXT("Configure Display"), },
Graphics Section 13
©1991 – 2016 Garth Santor & Trinh Hān GATS Encyclopaedia 174 of 278
{ INPUT_CONFIG_INPUT, DIKEYBOARD_F3, DIA_APPFIXED, TEXT("Configure Input"), },
};
#define NUMBER_OF_GAMEACTIONS (sizeof(g_rgGameAction)/sizeof(DIACTION))
Add to the framework application class:
CInputDeviceManager* m_pInputDeviceManager; // DirectInput device manager
DIACTIONFORMAT m_diafGame; // Action format for game play
HRESULT InputAddDeviceCB( CInputDeviceManager::DeviceInfo* pDeviceInfo, const DIDEVICEINSTANCE* pdidi );
static HRESULT CALLBACK StaticInputAddDeviceCB( CInputDeviceManager::DeviceInfo* pDeviceInfo, const DIDEVICEINSTANCE* pdidi,
LPVOID pParam );
OneTimeSceneInit() HRESULT CMyD3DApplication::InitInput( HWND hWnd )
{
HRESULT hr;
// Setup action format for the actual gameplay
ZeroMemory( &m_diafGame, sizeof(DIACTIONFORMAT) );
m_diafGame.dwSize = sizeof(DIACTIONFORMAT);
m_diafGame.dwActionSize = sizeof(DIACTION);
m_diafGame.dwDataSize = NUMBER_OF_GAMEACTIONS * sizeof(DWORD);
m_diafGame.guidActionMap = g_guidApp;
// TODO: change the genre as needed
m_diafGame.dwGenre = DIVIRTUAL_CAD_3DCONTROL;
m_diafGame.dwNumActions = NUMBER_OF_GAMEACTIONS;
m_diafGame.rgoAction = g_rgGameAction;
m_diafGame.lAxisMin = -100;
m_diafGame.lAxisMax = 100;
m_diafGame.dwBufferSize = 16;
_tcscpy( m_diafGame.tszActionMap, _T("DX9Joystick Game") );
// Create a new input device manager
m_pInputDeviceManager = new CInputDeviceManager();
if( FAILED( hr = m_pInputDeviceManager->Create( hWnd, NULL, m_diafGame,
StaticInputAddDeviceCB, this ) ) )
return DXTRACE_ERR( "m_pInputDeviceManager->Create", hr );
return S_OK;
}
Note that the last parameter ‘this’ is a pointer to the call-back parameters.
StaticInputAddDeviceCB
This call-back function is a helper function that assists the device manager in adding devices. For each device enumerated by the
CInputDeviceManager::Create, this function is called. This implementation then calls the application’s InputAddDeviceCB method which creates
a device state object for the device and sets the dead zone.
HRESULT CALLBACK CMyD3DApplication::StaticInputAddDeviceCB(
CInputDeviceManager::DeviceInfo* pDeviceInfo,
Graphics Section 13
©1991 – 2016 Garth Santor & Trinh Hān GATS Encyclopaedia 175 of 278
const DIDEVICEINSTANCE* pdidi,
LPVOID pParam )
{
CMyD3DApplication* pApp = (CMyD3DApplication*) pParam;
return pApp->InputAddDeviceCB( pDeviceInfo, pdidi );
}
InputAddDeviceCB
InputAddDeviceCB creates an InputDeviceState object for each input device and links that object to the device info object for that device. This
example also sets the dead-zone for the input device.
HRESULT CMyD3DApplication::InputAddDeviceCB(
CInputDeviceManager::DeviceInfo* pDeviceInfo,
const DIDEVICEINSTANCE* pdidi )
{
UNREFERENCED_PARAMETER( pdidi );
// Setup the deadzone
DIPROPDWORD dipdw;
dipdw.diph.dwSize = sizeof(DIPROPDWORD);
dipdw.diph.dwHeaderSize = sizeof(DIPROPHEADER);
dipdw.diph.dwObj = 0;
dipdw.diph.dwHow = DIPH_DEVICE;
dipdw.dwData = 500;
pDeviceInfo->pdidDevice->SetProperty( DIPROP_DEADZONE, &dipdw.diph );
// Create a new InputDeviceState for each device so the
// app can record its state
InputDeviceState* pNewInputDeviceState = new InputDeviceState;
ZeroMemory( pNewInputDeviceState, sizeof(InputDeviceState) );
pDeviceInfo->pParam = (LPVOID) pNewInputDeviceState;
return S_OK;
}
FrameMove()
The FrameMove is most direct. Simply access the user input state object and modify the model to match.
UpdateInput( &m_UserInput );
// Update the world state according to user input
D3DXMATRIX matWorld;
D3DXMATRIX matRotY;
D3DXMATRIX matRotX;
if( m_UserInput.fAxisRotateLR )
m_fWorldRotY += m_fElapsedTime * m_UserInput.fAxisRotateLR;
if( m_UserInput.fAxisRotateUD )
m_fWorldRotX += m_fElapsedTime * m_UserInput.fAxisRotateUD;
D3DXMatrixRotationX( &matRotX, m_fWorldRotX );
D3DXMatrixRotationY( &matRotY, m_fWorldRotY );
Graphics Section 13
©1991 – 2016 Garth Santor & Trinh Hān GATS Encyclopaedia 176 of 278
D3DXMatrixMultiply( &matWorld, &matRotX, &matRotY );
m_pd3dDevice->SetTransform( D3DTS_WORLD, &matWorld );
If the display device is being reconfigured, you should disable the direct input system until the reconfiguration has completed (otherwise direct
input will intercept commands that should go to the dialog reconfiguration dialog boxes.)
if( m_UserInput.bDoConfigureDisplay )
{
// One-shot per keypress
m_UserInput.bDoConfigureDisplay = FALSE;
Pause(true);
// Configure the display device
UserSelectNewDevice();
Pause(false);
}
The task is a little more complex when user input is being reconfigured. if( m_UserInput.bDoConfigureInput && m_bWindowed ) // full-screen configure disabled
{
// One-shot per keypress
m_UserInput.bDoConfigureInput = FALSE;
Pause( true );
// Get access to the list of semantically-mapped input devices
// to delete all InputDeviceState structs before calling ConfigureDevices()
CInputDeviceManager::DeviceInfo* pDeviceInfos;
DWORD dwNumDevices;
m_pInputDeviceManager->GetDevices( &pDeviceInfos, &dwNumDevices );
for( DWORD i=0; i<dwNumDevices; i++ )
{
InputDeviceState* pInputDeviceState =
(InputDeviceState*) pDeviceInfos[i].pParam;
SAFE_DELETE( pInputDeviceState );
pDeviceInfos[i].pParam = NULL;
}
// Configure the devices (with edit capability)
if( m_bWindowed )
m_pInputDeviceManager->ConfigureDevices(m_hWnd,NULL,NULL,DICD_EDIT,NULL);
else
m_pInputDeviceManager->ConfigureDevices( m_hWnd, m_pDIConfigSurface,
(VOID*)StaticConfigureInputDevicesCB, DICD_EDIT, (LPVOID) this );
Pause( false );
}
UpdateInput()
UpdateInput() examines each device’s InputDeviceState object using that information to update the UserInputState object.
void CMyD3DApplication::UpdateInput( UserInput* pUserInput )
Graphics Section 13
©1991 – 2016 Garth Santor & Trinh Hān GATS Encyclopaedia 177 of 278
{
if( NULL == m_pInputDeviceManager )
return;
// Get access to the list of semantically-mapped input devices
CInputDeviceManager::DeviceInfo* pDeviceInfos;
DWORD dwNumDevices;
m_pInputDeviceManager->GetDevices( &pDeviceInfos, &dwNumDevices );
// Loop through all devices and check game input
for( DWORD i=0; i<dwNumDevices; i++ )
{
DIDEVICEOBJECTDATA rgdod[10];
DWORD dwItems = 10;
HRESULT hr;
LPDIRECTINPUTDEVICE8 pdidDevice = pDeviceInfos[i].pdidDevice;
InputDeviceState* pInputDeviceState = (InputDeviceState*) pDeviceInfos[i].pParam;
hr = pdidDevice->Acquire();
hr = pdidDevice->Poll();
hr = pdidDevice->GetDeviceData( sizeof(DIDEVICEOBJECTDATA),
rgdod, &dwItems, 0 );
if( FAILED(hr) )
continue;
// Get the sematics codes for the game menu
for( DWORD j=0; j<dwItems; j++ )
{
BOOL bButtonState = (rgdod[j].dwData==0x80) ? TRUE : FALSE;
FLOAT fButtonState = (rgdod[j].dwData==0x80) ? 1.0f : 0.0f;
FLOAT fAxisState = (FLOAT)((int)rgdod[j].dwData)/100.0f;
UNREFERENCED_PARAMETER( fButtonState );
switch( rgdod[j].uAppData )
{
// TODO: Handle semantics for the game
// Handle relative axis data
case INPUT_ROTATE_AXIS_LR:
pInputDeviceState->fAxisRotateLR = -fAxisState;
break;
case INPUT_ROTATE_AXIS_UD:
pInputDeviceState->fAxisRotateUD = -fAxisState;
break;
// Handle buttons separately so the button state data
// doesn't overwrite the axis state data, and handle
// each button separately so they don't overwrite each other
case INPUT_ROTATE_LEFT:
pInputDeviceState->bButtonRotateLeft = bButtonState; break;
case INPUT_ROTATE_RIGHT:
pInputDeviceState->bButtonRotateRight = bButtonState; break;
case INPUT_ROTATE_UP:
pInputDeviceState->bButtonRotateUp = bButtonState; break;
case INPUT_ROTATE_DOWN:
pInputDeviceState->bButtonRotateDown = bButtonState; break;
case INPUT_PLAY_SOUND:
pInputDeviceState->bButtonPlaySoundButtonDown = bButtonState; break;
Graphics Section 13
©1991 – 2016 Garth Santor & Trinh Hān GATS Encyclopaedia 178 of 278
// Handle one-shot buttons
case INPUT_CONFIG_INPUT: if( bButtonState ) pUserInput->bDoConfigureInput = TRUE; break;
case INPUT_CONFIG_DISPLAY: if( bButtonState ) pUserInput->bDoConfigureDisplay = TRUE; break;
}
}
}
// TODO: change process code as needed
// Process user input and store result into pUserInput struct
pUserInput->fAxisRotateLR = 0.0f;
pUserInput->fAxisRotateUD = 0.0f;
pUserInput->bPlaySoundButtonDown = FALSE;
// Concatinate the data from all the DirectInput devices
for( i=0; i<dwNumDevices; i++ )
{
InputDeviceState* pInputDeviceState = (InputDeviceState*) pDeviceInfos[i].pParam;
// Use the axis data that is furthest from zero
if( fabs(pInputDeviceState->fAxisRotateLR) > fabs(pUserInput->fAxisRotateLR) )
pUserInput->fAxisRotateLR = pInputDeviceState->fAxisRotateLR;
if( fabs(pInputDeviceState->fAxisRotateUD) > fabs(pUserInput->fAxisRotateUD) )
pUserInput->fAxisRotateUD = pInputDeviceState->fAxisRotateUD;
// Process the button data
if( pInputDeviceState->bButtonRotateLeft )
pUserInput->fAxisRotateLR = 1.0f;
else if( pInputDeviceState->bButtonRotateRight )
pUserInput->fAxisRotateLR = -1.0f;
if( pInputDeviceState->bButtonRotateUp )
pUserInput->fAxisRotateUD = 1.0f;
else if( pInputDeviceState->bButtonRotateDown )
pUserInput->fAxisRotateUD = -1.0f;
if( pInputDeviceState->bButtonPlaySoundButtonDown )
pUserInput->bPlaySoundButtonDown = TRUE;
}
}
Pause()
Pause clears the state of each input device. Since the action map system uses DISCL_FOREGROUND as its cooperative mode, device state
changes will not be detected when the application is not in focus. Therefore, when a dialog box opens (and focus is lost) any state change to an
input device, like releasing a key or joystick will not be detected by the system. Clearing the state guarantees a safe state when the application
regains focus.
VOID CMyD3DApplication::Pause( bool bPause )
{
CInputDeviceManager::DeviceInfo* pDeviceInfos;
DWORD dwNumDevices;
m_pInputDeviceManager->GetDevices( &pDeviceInfos, &dwNumDevices );
Graphics Section 13
©1991 – 2016 Garth Santor & Trinh Hān GATS Encyclopaedia 179 of 278
for( DWORD i=0; i<dwNumDevices; i++ )
{
InputDeviceState* pInputDeviceState = (InputDeviceState*) pDeviceInfos[i].pParam;
ZeroMemory( pInputDeviceState, sizeof(InputDeviceState) );
}
CD3DApplication::Pause( bPause );
}
CleanupDirectInput()
Called from FinalCleanup(). We must first delete each dynamically allocated InputDeviceState object.
VOID CMyD3DApplication::CleanupDirectInput()
{
if( NULL == m_pInputDeviceManager )
return;
// Get access to the list of semantically-mapped input devices
// to delete all InputDeviceState structs
CInputDeviceManager::DeviceInfo* pDeviceInfos;
DWORD dwNumDevices;
m_pInputDeviceManager->GetDevices( &pDeviceInfos, &dwNumDevices );
for( DWORD i=0; i<dwNumDevices; i++ )
{
InputDeviceState* pInputDeviceState = (InputDeviceState*) pDeviceInfos[i].pParam;
SAFE_DELETE( pInputDeviceState );
pDeviceInfos[i].pParam = NULL;
}
// Cleanup DirectX input objects
SAFE_DELETE( m_pInputDeviceManager );
}
TextHelper Object SDK 9.0c
CDXUTTextHelper is a component of the DirectX SDK 9.0c framework. It is provided to simplify the use of formatted text in an application.
Example
The following code writes two lines of text to the display.
if( SUCCEEDED( pd3dDevice->BeginScene() ) )
{
CDXUTTextHelper txtHelper( g_pFont, g_pTextSprite, 16 );
txtHelper.Begin();
txtHelper.SetInsertionPos( 5,5 );
txtHelper.DrawTextLine( L"Hello," );
txtHelper.DrawTextLine( L"world!" );
txtHelper.End();
V( pd3dDevice->EndScene() );
}
Graphics Section 13
©1991 – 2016 Garth Santor & Trinh Hān GATS Encyclopaedia 180 of 278
Texture Mapping
Alpha Channel Alpha channel texture mapping is a form of pixel blending that uses information stored in a texture’s alpha channel to determine how much of the
texel is visible in the destination raster.
The standard interpretation of the α-channel is as indicator of transparency or opacity, where the minimum value indicates full transparency and
the maximum value indicates full opacity.
The calculation of the destination pixel is: 1dp sp dp
Direct3D
Data IDirect3DTexture9* texture = NULL;
After device creation D3DXCreateTextureFromFile( pd3dDevice, L"ImageWithAlpha.dds", &texture );
Before rendering the textured primitive pd3dDevice->SetRenderState( D3DRS_ALPHABLENDENABLE, TRUE );
pd3dDevice->SetRenderState( D3DRS_SRCBLEND, D3DBLEND_SRCALPHA );
pd3dDevice->SetRenderState( D3DRS_DESTBLEND, D3DBLEND_INVSRCALPHA );
pd3dDevice->SetTexture( 0, texture );
Before device destruction texture->Release();
Blending OutPixel SrcPixel SrcBlend DstPixel DstBlend
Colour Keyed Colour keyed texture mapping transfers all pixels to the destination triangle except pixels that match the colour key. This technique is identical to
television green screens.
To use this technique in Direct3D follow these steps:
Loading the texture…
Replace D3DXCreateTextureFromFile() with D3DXCreateTextureFromFileEx(). The extended function allows you to set a colour key value.
e.g.
Graphics Section 13
©1991 – 2016 Garth Santor & Trinh Hān GATS Encyclopaedia 181 of 278
D3DXCreateTextureFromFileEx(
pd3dDevice, L"keyed_texture.bmp", D3DX_DEFAULT, D3DX_DEFAULT, 1, 0,
D3DFMT_A8R8G8B8, // This is a 32-bit alpha-enabled format
D3DPOOL_MANAGED, D3DX_DEFAULT,
D3DX_DEFAULT,
D3DCOLOR_ARGB(255,0,255,0), // This is the color key
NULL,
NULL, &pTexture ) );
This command loads the texture replace the pixels matching the color key value with transparent black.
Stage states
The texture stage states essentially program the pipeline to combine or copy the texels the way we want them. For transparency, we need to set the
following stage states for our texture.
pd3dDevice->SetTextureStageState( 0, D3DTSS_COLORARG1, D3DTA_TEXTURE );
This instructs the pipeline to use the texture as the source of the first colour argument. This setting is the default.
pd3dDevice->SetTextureStageState( 0, D3DTSS_COLOROP, D3DTOP_SELECTARG1 );
This instructs the pipeline to use the colour argument we just set as the colour argument in colour operations.
pd3dDevice->SetTextureStageState( 0, D3DTSS_ALPHAOP, D3DTOP_SELECTARG1 );
This instructs the pipeline to use that same colour argument in alpha operations.
pd3dDevice->SetTextureStageState( 0, D3DTSS_ALPHAARG1, D3DTA_TEXTURE );
Finally, we instruct the pipeline that the texture is also the source of the first alpha argument.
Render states
Now we set the rendering states of the pipeline to recognize the stage states we have set.
pd3dDevice->SetRenderState( D3DRS_ALPHABLENDENABLE, TRUE );
Enable alpha blending operations.
pd3dDevice->SetRenderState( D3DRS_SRCBLEND, D3DBLEND_SRCALPHA );
Set the source blend factor to the alpha argument, which in this case is the colour from the texture.
pd3dDevice->SetRenderState( D3DRS_DESTBLEND, D3DBLEND_INVSRCALPHA );
Set the destination blend factor to the inverse (1 sA ) of the source alpha value.
Render the texture normally… e.g.
pd3dDevice->SetTexture( 0, pTexture );
pd3dDevice->SetStreamSource( 0, pVB, 0, sizeof(TVertex) );
pd3dDevice->SetFVF( TVertex::FVF );
pd3dDevice->DrawPrimitive(D3DPT_TRIANGLEFAN, 0, 2 );
Graphics Section 13
©1991 – 2016 Garth Santor & Trinh Hān GATS Encyclopaedia 182 of 278
Disabling transparency
To shut of the transparency blending, toggle the D3DRS_ALPHABLENDENABLE render state to false.
Transformations Direct3D texture coordinates can be transformed by the render pipeline. This process allows texture coordinates to be “changed” during program
execution without requiring the vertex data to be physically modified.
A common application of this technique is a sprite engine.
Implementation
Create the vertices in the standard way for a textured surface. Call the following two methods prior to rendering the surface:
pd3dDevice->SetTransform( D3DTS_TEXTURE0, &transformMatrix );
pd3dDevice->SetTextureStageState( 0, D3DTSS_TEXTURETRANSFORMFLAGS, D3DTTFF_COUNT2 );
The first method registers the specific transform with the appropriate texture transform matrix – in this case, texture zero (D3DTS_TEXTURE0).
The second methods indicates that the only the first two coordinates generated by the texture transform should be passed through to the rasterizer.
This is the appropriate setting for a 2D texture mapping.
Transforms Types
The any transform can be applied to the texture coordinate transform engine, individually or in combination. However, some transforms are more
meaningful than others as the texture coordinate system is a two-dimension system. The transforms are registered by passing 4x4 matrices to the
system, but these matrices may be interpreted as 3x3 or 2x2 matrices depending on the dimensionality of the texture coordinates. 2D texture
coordinates, for example, interpret the transforms as 3x3 matrices.
Translation
Two dimensional translations of texture coordinates are somewhat difficult as we cannot use the built-in matrix operations provide by Microsoft.
We have to create them ourselves.
The standard 2D translation matrix is:
1 0 0
0 1 0
1x y
To package the 2D translation matrix into a 4x4 matrix we arrange the matrix in the following way:
1 0 0 0
0 1 0 0
1 0
0 0 0 1
x y
In code we would see:
Graphics Section 13
©1991 – 2016 Garth Santor & Trinh Hān GATS Encyclopaedia 183 of 278
D3DXMATRIX matTrans;
D3DXMatrixIdentity( &matTrans );
matTrans._31 = 2.0f;
matTrans._32 = 3.0f;
This produces a translation of 2 in x and 3 in y.
Rotation
The most meaningful rotation of 2D texture coordinates is a rotation about the Z axis (or a rotation in the X-Y plane.) The standard 3D rotation
produces a result that is correct in 2D.
Scaling
The standard 3D scaling matrix is correct in 2D if the z-scale is 1.0.
Two-dimensional Rendering The default state of a DirectX device is to have the depth buffer enabled as well as back-face culling of triangles. It is assumed that clock-wise
triangles are front face and anti-clock-wise triangles are back-face.
Two-dimensional rendering typically ignores back-face culling, although the depth buffer can be useful to leave enabled.
To disable back-face culling issue the command:
pd3dDevice->SetRenderState( D3DRS_CULLMODE, D3DCULL_NONE );
To disable z-buffering issue the command:
pd3dDevice->SetRenderState( D3DRS_ZENABLE, D3DZB_FALSE );
Both of these commands need only be called prior to rendering.
DX-SDK 9.0c: These commands can be safely issued in the OnResetDevice() callback function.
DX-SDK 9.0b: These command can be safely issued in the OnRestoreDevice() method.
Hardware
Adapters
3dfx Voodoo 3500
AGP Texturing
16MB SGRAM
183MHz clock and memory
366 Megatexels/s peak fill rate
8 Million polygons/s
Graphics Section 13
©1991 – 2016 Garth Santor & Trinh Hān GATS Encyclopaedia 184 of 278
Single-pass multi-texturing
128-bit 2D/3D processor
350MHz RAMDAC
D3D, Glide, OpenGL support
nVidia Riva TnT2
AGP Texturing
32MB SDRAM/SGRAM
9 million triangles/sec, 300 million pixels/s
2.9GiB/s bus
300MHz RAM DAC
128-bit Twin-Texel
Optimized Direct3D and OpenGL acceleration
SEGA Dreamcast
CPU Hitachi SH-4
200MHz clock
360MIPS
1400 MFLOPS (900MFLOPS with external memory)
64-bit data bus
100MHz bus
Capable of 5 million polygons/s
800MB/s bus
32-bit integer unit
128-bit floating point bus
GPU NEC PowerVRSG
100MHz clock
32-bit bus
9 billion operations/s
3.5 million polygons/s
120 million pixles/s fill rate
Perspective-correct texture mapping
Bilinear and trilinear filtering
Anisotropic filtering
Gourand shading
32-bit Z-buffer
Graphics Section 13
©1991 – 2016 Garth Santor & Trinh Hān GATS Encyclopaedia 185 of 278
Colored light sourcing
16 levels of transparency
Full-scene edge anti-aliasing
Fog vertex
Per-pixel fogging
Bump mapping
24-bit color
Sound Yamaha ARM7 ASIC
45MHz clock
40 MIPS
64 sound channels
Full 3D sound support
Modem Upgradable 33.6KB/s
CD-ROM Yamaha design
1GB data storage
12 speed
1800KB data transfer rate
Memory 16MB main RAM
8MB video RAM
2MB sound RAM
Video acceleration for DirectShow, MPEG1&2, and Indeo
Sony Playstation 2
CPU 128-bit “emotion engine”
300MHz system clock
16KB Instruction cache
8KB + 16KB (ScrP) Data cache
32MB Direct Rambus main memory (RDRAM)
3.2GiB/s memory bus
Co-processor FPU: Multiplier, Accumulator, Divider
2 Vector Units: Multiply, 9 Accumulators, 3 Dividers
6.2 GFLOPS
66 million polygons/s 3D CG geometric transformation
Graphics “Graphics Syntehsizer”
MPEG2 decoder
Graphics Section 13
©1991 – 2016 Garth Santor & Trinh Hān GATS Encyclopaedia 186 of 278
150MHz clock
48GiB/s DRAM bus
256-bit DRAM bus width
RGB: Alpha: Z-buffer (24:8:32) pixel configuration
75million polygons/s maximum rate
Sound “SPU2+CPU”
Number of voice ADPCM: 48ch on SPU2 plus definable, software-programmable voices
44.1KHz or 48KHz selectable sampling frequency
CPU
Core Playstation 1 CPU
33.8 MHz or 37.5 MHz selectable clock
32-bit sub bus
IEEE1394 and USB
PCMCIA
Disc CD-ROM and DVD-ROM
Terrain
Height Maps
Introduction
A height map is an indexed collection (array or vector) where each element contains the height of a particular vertex in the terrain grid. Some
height maps contain the height information of each grid as apposed to each vertex. Conceptually, the height map can be thought of as a matrix
where each element corresponds to a grid vertex.
Height maps are efficiently stored on disk as byte-maps. Using byte-maps permit 256 different elevations. The byte-maps can be created with a
bitmap editing tool such as Adobe Photoshop. Typically, darker regions are lower elevations and lighter regions higher elevations.
Graphics Section 13
©1991 – 2016 Garth Santor & Trinh Hān GATS Encyclopaedia 187 of 278
Data Structures
The data structures in the height map and vertex list are both one-dimensional data structures
representing two-dimensional objects. Therefore we need a mapping of 2D row-column
coordinates to 1D offsets.
colerRownVerticesProwoffset
erRownVerticesP
offsetrow
erRownVerticesPoffsetcol mod
The vertex buffer fills from left to right and back to front where consecutive elements are
on the same row.
Indices fill for each cell from left to right and back to front where each cell generates the
index pattern ABCBDC – for CW culled triangles or ACBBCD for CWW culled
triangles.
Textures coordinates fill from left to right and back to front. It is assumed that one texture
covers the entire surface.
Height information fills from left to right and back to front where consecutive elements
are on the same row. Each elevation value [0..255] is scaled by a preset value.
Walking on the terrain
We can examine the height map to gain information about what the height of the character
should be for any particular location on the terrain.
Given a location (x,z)
xwidth
x 2
, zdepth
z 2
1. Adjust the location to make the back-left the (0,0) location.
2. Normalize the coordinates, such that cellspacing = 1.
gcellspacin
zz
gcellspacin
xx ,
3. Locate the cell in which the normalized coordinates (x,y) is located.
zrowxcol ,
4. Get the heights of the four cell vertices from the height map. ),( colrowheightmapAy
)1,( colrowheightmapBy
(-w/2,+d/2)
(-w/2,-d/2) (+w/2,-d/2)
(+w/2,+d/2)cell spacing+z
+x
w = Width
C D
A B
[0,0] [1,0]
[0,1]
v0 v1 v2 v3 v4 v5
v6 v7 v11
v12
v35
v18
v24
v30
0,0:0 0,63:63
63,0:4032 63,63:4095
Graphics Section 13
©1991 – 2016 Garth Santor & Trinh Hān GATS Encyclopaedia 188 of 278
),1( colrowheightmapCy
)1,1( colrowheightmapDy
5. Calculate the deltas of the coordinate within the cell.
zzzxxx ,
6. Determine which triangle of the cell the coordinate (x, z) is located in.
If xz 1 then the point is located in upper triangle ABC, otherwise the point is located in lower triangle DCB.
7. Interpolate ∆x and ∆z.
btatatbalerp ),,(
If upper triangle: ),,0(),,0( zAClerpxABlerpAheight yyyyy
Simplified: zACxABAheight yyyyy
If lower triangle: )1,,0()1,,0( zDBlerpxDClerpDheight yyyyy
Simplified: zDBxDCDheight yyyyy 11
Lighting, Static Terrain lighting presents some performance opportunities that other objects do not. Terrain generally doesn’t move, nor does the global,
directional light source relative to the terrain. Of course this may not be true if the game continues for a long duration, but often scenarios or
missions are short enough for this to be true. As a result, we can pre-calculate the effects of lighting on the terrain surface (typically a texture)
then render the terrain without the lighting engine enabled.
Method
The general solution begins with calculating the angle between the light vector L̂8 and the surface normal N̂ . We will call this angle . We will
then calculate a shading scalar s, where 0 s 1. If the angle between the light vector and the normal vector is 0° the shading scalar is 1 – full
brightness. As the angle increases the shading scalar decreases to a value of 0 when the = 90°. Angles greater than 90° indicate a light-source
below the surface and therefore do not light the surface.
Given: abc 9 and L̂
abu
8 The lighting vector is a unit vector originating with the light source and pointing towards the surfaces to be lit. 9 ABC are clockwise ordered in a LH system, anti-clockwise ordered in a RH system.
Graphics Section 13
©1991 – 2016 Garth Santor & Trinh Hān GATS Encyclopaedia 189 of 278
acv
vun
n
nN ˆ
NL ˆˆcos s , where 11 s
Since negative angles indicate that the surface is being lit from the backside, we clamp s to zero when s is in the range )0,1[ .
We can now multiply each of the colour values for this surface by s.
Skyboxes (sky-domes) A skybox is simply a box that surrounds the viewer and has a picture of the sky and surrounding environment textured on to each of the sides.
A full skybox, is a six-sided cube complete with sky and ground textures on top and bottom and sky/horizon textures for each of the four walls.
Most games don’t require the bottom to be rendered and may omit that surface.
Alternatives to skyboxes are sky-domes, semi-spherical domes that sit above the viewer and have the sky and perhaps clouds textured to the
surface. Sky-domes are typically compressed in the y-axis to provide a more realistic perspective as clouds pass by the viewer. Sky-domes
generally don’t have horizons as part of the texture mapped to the dome.
Implementation
The skybox is rendered prior to all other shapes with either no world transformation and the camera transform striped of location, or translated to
the camera location and the full camera translation applied.
Which is of the two approaches to take depends on whether fog effects are present in your scene. If fog is present the second approach of
rendering the skybox in world coordinates must be taken. Otherwise the system will not calculate the pixel depths correctly. If fog is not present,
the first approach of rendering the skybox in local coordinates can be taken. This approach is typically faster, but requires the camera or view to
be set without position information.
Removing the position from the view matrix. D3DXMATRIX view;
pd3dDevice->GetTransform( D3DTS_VIEW, &view );
view._41 = view._42 = view._43 = 0;
pd3dDevice->SetTransform( D3DTS_VIEW, &view );
The position information is stored in the last row of the matrix. Setting these values to zero effectively removes the position information from the
matrix.
Graphics Section 13
©1991 – 2016 Garth Santor & Trinh Hān GATS Encyclopaedia 190 of 278
Turtle Graphics
Turtles or turtle graphics come from the LOGO language developed at MIT in the late 1960’s.
LOGO was used to interact with and command a turtle-like robot that had the capability to move
across the floor, turn in any direction and to raise and lower pen onto the floor. If the pen was
lowered when the turtle was instructed to move, a line would be drawn on the floor.
This a LOGO styled script for drawing a square:
pen down
step 10
turn 90
step 10
turn 90
step 10
turn 90
step 10
In graphics languages like OpenGL and Direct3D it is either impractical or inefficient to draw directly to the frame buffer using the turtle-graphics
paradigm. However, a pen-less turtle can be quit useful and quit efficient if used to generate vertices that will be stored in a vertex buffer.
Design
Turtles easily lend themselves to object-oriented programming. The LOGO commands become methods and the class attributes are easily derived
from the functionality of the class. That leaves us with one fundamental question about architecture: do we encapsulate the 2D vector representing
the turtle’s location or do we derive our turtle from a 2D vector class.
Encapsulated location Derived from location
Turtle
+location:D3DXVECTOR2
+direction:float
+speed:float
+step():
+turn(angle:float):
D3DXVECTOR2
Turtle
+direction:float
+speed:float
+step():
+turn(angle:float):
step 10
turn 90
turn 90turn
90
step 10
step
10 ste
p 10
Graphics Section 13
©1991 – 2016 Garth Santor & Trinh Hān GATS Encyclopaedia 191 of 278
Computations
Turn(angle) direction direction angle
Step cos ,sinlocation location speed direction direction
History Section 14
©1991 – 2016 Garth Santor & Trinh Hān GATS Encyclopaedia 192 of 278
History
DirectX
Introduction
DirectX has gone through many version, some released – some not, and even a few name changes. Here, I hope to record what changed, when and
how we benefit from those changes.
~1994: WinG
WinG was an early attempt by Microsoft to bring game developers to the Windows platform.
Windows could blt a bitmap to a window with a bandwidth comparable to an equivalent DOS program running on the same hardware. The
primary problem was that the efficient blting routine BitBlt could only blt from an HBITMAP which was not stored in application memory.
Therefore the application could not directly touch the pixels of an HBITMAP, it would have to go through the GDI with routines like SetPixel and
LineTo. DIBs which are stored in application memory are as much as 20 times slower than BitBlt.
WinG provided a set of objects, most notably WinGBitmap that can be blted directly from application memory. The performance of WinG’s blt is
comparable to DOS’s best time.
December 1994?: WinToon
WinToon is Microsoft’s animation playback tool for Windows. It uses the Video for Windows architecture integrated into the Windows 95 OS. It
would support the WinG API.
1995: DirectX 1.0 (Microsoft Game SDK)
Originally called the Microsoft Game SDK, Microsoft now uses its better accepted name DirectX version 1.0. The critical offering in this SDK is
DirectDraw 1.0, a technology that permits direct access to a video adapter’s memory in a device independent manner.
One of the first games to use DirectX was Descent, from Parallax Software
1996: DirectX 2.0
APIs
DirectDraw API provides direct access to bitmaps. Bitmaps may be in on-screen or off-screen video memory. Hardware bit-block transfer and
buffer-flipping is supported.
DirectSound API provides hardware and software sound mixing and playback.
DirectPlay API provides connectivity via modem or network.
Direct3D API provides direct low-level access to 3D hardware. DirectDraw surfaces can be used as render targets or source texture maps.
History Section 14
©1991 – 2016 Garth Santor & Trinh Hān GATS Encyclopaedia 193 of 278
DirectInput API provides abstractions for keyboard, mouse and joystick in a framework that is extensible to future devices.
Direct3D
Based on Reality Lab technology acquired from Render-Morphics in 1995.
Hardware Support
Video hardware features:
Overlays
Page flipping
Sprite engines
Stretching with interpolation
Alpha blending
Z buffer-aware bit-block transfers
1996: DirectX 3.0
1997: DirectX 5.0
1998: DirectX 6.0
1999: DirectX 7.0
2000: DirectX 8.0
Following the release of this SDK, Microsoft releases the first Xbox.
2001: DirectX 8.1
2002: DirectX 9.0
2003: DirectX 9.0b
2004: DirectX 9.0c
One of the finest examples of a DirectX 9.0c is Half-Life 2, by Valve Software
History Section 14
©1991 – 2016 Garth Santor & Trinh Hān GATS Encyclopaedia 194 of 278
2005: Xbox 360
2006: DirectX 10
Microsoft lists the design goals for DirectX 10 as:
improving small-batch performance
reducing validation overhead
in-GPU multipass
the elimination of capability bits
unify shader cores
strictly define behaviour across chipsets
more expressive programming
geometry shader
texture compression formats for normals
resource views
Recognizing that Direct3D 9 is a mature API, Microsoft decided to completely re-architect the system. This also allows Direct3D 10 to use
Vista’s new WDDM (Windows Display Driver Model)
Features:
Common shader core – all shaders use the same instructions.
Guaranteed feature set. All cards support all features.
Programmable shader model – all rendering uses shaders using HLSL SM 4.0.
Resources are now two logical pieces – buffers and views.
GPU and Memory is virtualized – ‘LOST DEVICE’ condition no longer occurs. Multiple applications can use Direct3D.
State/resource validation restricted to specific times (such as creation)
FAQS
The first good DirectX 10 game is Crysis, by Crytek.
Microsoft sees the Direct3D9 as the replacement to GDI for core windows graphics and Direct3D 10 as the path for high-performance graphics.
Mathematics Section 15
©1991 – 2016 Garth Santor & Trinh Hān GATS Encyclopaedia 195 of 278
Mathematics
General
Factorial The continued product 12321 nnn is called the factorial. It is the number of permutations of n things. We denote factorial using a
suffixed exclamation symbol. The factorial of zero is a special case with its value being 1. This is due to there being one arrangement of
1!0
12321!
nnnn
If n is large, an approximation of n! can be obtained using Stirling’s Theorem.
ne
nn
n
2!
Implementation
function FACTORIAL( n ) returns natural number
if 0 n 1
then return 1
else return n FACTORIAL( n – 1 )
A simple and elegant algorithm! But a poor performer in terms of memory and sometimes execution speed. An iterative implementation should
be preferred.
function FACTORIAL( n ) returns natural number
fact 1
for i 2 to n do
fact fact i
return fact
Fibonacci Numbers A number from the Fibonacci sequence: 1, 1, 2, 3, 5, 8, 13, 21, 34, 55, …
The general term nF can be found with the formula:
112
21
FF
FFF nnn
Mathematics Section 15
©1991 – 2016 Garth Santor & Trinh Hān GATS Encyclopaedia 196 of 278
Jacque Philippe Marie Binet (1776 – 1856) in 1843 derived a formula capable of calculating any specific Fibonacci number. This is called Binet’s
Form.
52
5151
n
nn
nF
Implementation
function FIBONACCI ( n ) returns natural number
if 0 < n 2
then return 1
else return FIBONACCI( n – 1 ) + FIBONACCI( n – 2 )
While a recursive solution is simple, it is a poor performer on both memory and time. The recursive calls branch out to a tree of function calls!
An iterative approach is to be preferred.
function FIBONACCI( n ) returns natural number
if 0 < n 2
then return 1
first second 1
for i 3 to n – 1 do
fib first + second
first second
second fib
return first + second
While the iterative approach is an improvement over the recursive approach, large Fibonacci numbers still require considerable processing time.
Such Fibonacci numbers can be calculated in constant time using Binet’s form.
Fibonacci and Euclid
Fibonacci numbers have an interesting relationship with the Euclidean Algorithm (HCF). For each successive pair of Fibonacci numbers the
following holds true;
1, 1 ii FFHCF
11 mod iii FFF
These relationships where investigated by Thomas Fantet de Lagny (1660 – 1734).
Golden Ratio The golden ratio is also known as the divine proportion, golden mean and the golden section.
It is denoted , or sometimes (abbr. Gk. “tome” meaning “to cut”).
The golden ratio possesses the following properties.
Mathematics Section 15
©1991 – 2016 Garth Santor & Trinh Hān GATS Encyclopaedia 197 of 278
1
1
012
The golden ratio can be calculated by the following means:
512
1
10csc
2
1
5
2sec
2
1
5cos2
032
1
4!!2
!121
8
13
nn
n
nn
n
1 1
11
1n nn
n
FF Where
nF is a Fibonacci number.
11111
Logarithms A logarithm is a function that gives value of the exponent in the equation xa b . The typical notation for a logarithm is logax b .
Numbers
Natural Numbers
Natural numbers are non-negative integers; i.e. 0, 1, 2, 3, … 42, …,
Notation: ¥ denotes the set of all natural numbers.
Pi π – pi.
1arccos
0 21
41
11
4
9
4
7
4
5
4
3
4
1
4
i
i
i
Mathematics Section 15
©1991 – 2016 Garth Santor & Trinh Hān GATS Encyclopaedia 198 of 278
Implementation – iterative
function PI( x ) returns a real number
last ← 0
p ← 4
denominator ← 1
sign ← –4
while p last do
last ← p
denominator ← denominator + 2
p ← p + sign denominator
sign ← –sign
return p
Note ε is the difference between the value 1 and the least value greater than one.
The primary problem with this method is floating-point error and the length of time required to produce an accurate result. Personally, I prefer to
use a pre-calculated constant in actual code.
Implementation – recursive
function PI( n ) returns a real number
if n = 0
then return 4
else return −1𝑛
1+2𝑛+ 𝑃𝑖(𝑛 − 1)
Algebra
Binomial Coefficient The binomial coefficient is the number of ways of picking k unordered outcomes from n possibilities. In terms of sets, the binomial coefficient
gives the number of k-subsets possible out of n distinct items. We write the binomial coefficient with the either the notation
k
n or
kn C and are
read as “n choose k”.
The value of the binomial coefficient is given explicitly by the formula: !!
!
knk
n
k
nCkn
The binomial coefficient is also known as combination or a combinatorial number.
Pascal’s Triangle The binomial coefficients form the rows of Pascal’s triangle.
Mathematics Section 16
©1991 – 2016 Garth Santor & Trinh Hān GATS Encyclopaedia 199 of 278
0
0
0
1
1
1
0
2
1
2
2
2
0
3
1
3
2
3
3
3
1
1 1
1 2 1
1 3 3 1
Permutation A permutation is an ordered arrangement of the elements of a set.
Example: ACBD, CBDA and DCBA are all permutations of the set {A, B, C, D}
The number of possible permutations (possible arrangements) is represented by n
rP where n is the number of different things and r is the number
of things in the arrangement.
Examples
The set {A, B, C} has the following 3-element arrangements: ABC, ACB, BCA, BAC, CAB, and CBA. The number of arrangement if given by
the expression: 3
3 6P .
The set {A, B, C, D} has the following 2-element arrangements: AB, AC, AD, BA, BC, BD, CA, CB, CD, DA, DB, DC. The number of
arrangement if given by the expression 4
2 12P .
Computing
!
!
n
r
nP
n r
Uses
Permutations are used the study of theories of equations, group theory and statistics.
Sum of Natural Numbers The sum of all the numbers from 1 up to a given upper limit:
Mathematics Section 17
©1991 – 2016 Garth Santor & Trinh Hān GATS Encyclopaedia 200 of 278
12
1
1321
1
nn
i
nnS
n
i
n
2D/3D Algebra
Coordinate Transforms Coordinate transformations are used to convert an object’s local coordinate system to the graphics engine’s world coordinate system.
Both 2D and 3D transformations are created by combining a rotation transform that aligns the axes of the local coordinate system with the axes of
the world’s coordinate system and a translation transform that aligns the local origin with the world origin.
Solution – 2D
Let the vectors u, v represent the local axes within the world coordinate system. You can think of these as the right and up vectors. Let L be the
location of the local coordinates system’s origin expressed in world coordinates.
We construct a rotation matrix by locating a matrix with the following properties:
11 12
21 22
11 12
21 22
1 0
0 1
x y
x y
a a
a a
a a
a a
u u
v v
Since these systems have the same coefficient matrix A, we can solve them at once.
11 12
21 22
1 0
0 1
x y
x y
a a
a a
u u
v v
The answer is obvious; the coefficient matrix is the result! We can now rewrite the transform as a homogeneous matrix R.
Mathematics Section 17
©1991 – 2016 Garth Santor & Trinh Hān GATS Encyclopaedia 201 of 278
0
0
0 0 1
x y
x y
u u
R v v
Now we need a homogeneous translation matrix that maps the local origin to the world origin.
1 0 0
0 1 0
1x y
T
L L
The complete coordinate transformation is just the product of the two matrices.
0 1 0 0 0
0 0 1 0 0
0 0 1 1 1
x y x y
x y x y
x y x y
u u u u
R T v v v v
L L L L
Coordinates the local system can be multiplied by this matrix to produce coordinates in the world system.
Solution – 3D
Let the vectors r, u, k represent the local axes within the world coordinate system. You can think of these as the right, up and look vectors. Let L
be the location of the local coordinates system’s origin expressed in world coordinates.
We construct a rotation matrix by locating a matrix with the following properties:
11 12 13
21 22 23
31 32 33
11 12 13
21 22 23
31 32 33
11 12 13
21 22 23
31 32 33
1 0 0
0 1 0
0 0 1
x y z
x y z
x y z
a a a
a a a
a a a
a a a
a a a
a a a
a a a
a a a
a a a
r r r
u u u
k k k
Since these systems have the same coefficient matrix A, we can solve them at once.
11 12 13
21 22 23
31 32 33
1 0 0
0 1 0
0 0 1
x y z
x y z
x y z
a a a
a a a
a a a
r r r
u u u
k k k
The answer is obvious; the coefficient matrix is the result! We can now rewrite the transform as a homogeneous matrix R.
v
u
L
Y
XO
Mathematics Section 17
©1991 – 2016 Garth Santor & Trinh Hān GATS Encyclopaedia 202 of 278
0
0
0
0 0 0 1
x y z
x y z
x y z
r r r
u u uR
k k k
Now we need a homogeneous translation matrix that maps the local origin to the world origin.
1 0 0 0
0 1 0 0
0 0 1 0
1x y z
T
L L L
The complete coordinate transformation is just the product of the two matrices.
1 0 0 0 00
0 1 0 0 00
0 0 1 0 00
1 10 0 0 1
x y zx y z
x y zx y z
x y zx y z
x y z x y z
r r rr r r
u u uu u uR T
k k kk k k
L L L L L L
Coordinates the local system can be multiplied by this matrix to produce coordinates in the world system.
Quaternion (Garth Santor, January 2007)
Quaternions are non-commutative extensions of complex numbers. They take the form of a 4-dimensional normed division algebra over real
numbers (H). It is useful to think of quaternions as having a real part w, and an imaginary part v, which is a 3-component vector. q w v
where v x y z . The real part w, represents an angle of rotation, and the vector part v, represents the axis in 3-space around which the
rotation occurs.
1843 Sir William Rowan Hamilton describes quaternions.
Avoids the ‘gimble-lock’ problem
Quaternion from axis-angle pair
cos sin cos sin sin sin2 2 2 2 2 2
x y z
q n n n n
Where n is a unit vector.
Mathematics Section 17
©1991 – 2016 Garth Santor & Trinh Hān GATS Encyclopaedia 203 of 278
Direct3D
D3DXQUATERNION* D3DXQuaternionRotationAxis(
D3DXQUATERNION* pOut,
D3DXVECTOR3* pAxis,
FLOAT angle );
Direct3D normalizes the axis vector.
Quaternion negation
w w x y z
w w x y z
q v
v
Direct3D
D3DXQUATERNION D3DXQUATERNION::operator – () const;
Quaternion identity
1 1 0 0 0 q 0
Direct3D
D3DXQUATERNION* D3DXQuaternionIdentity( D3DXQUATERNION* pOut );
Quaternion magnitude
22 2 2 2 2
w w x y z
w w x y z
q v
v
Direct3D
FLOAT D3DXQuaternionLength( CONST D3DXQUATERNION* pQ );
Quaternion Conjugate The conjugate of a quaternion is obtained by negating the vector portion of the quaternion. It is denoted by *
q .
*** w w x y z
w w x y z
q v
v
Mathematics Section 17
©1991 – 2016 Garth Santor & Trinh Hān GATS Encyclopaedia 204 of 278
Direct3D
D3DXQUATERNION* D3DXQuaternionConjugate( D3DXQUATERNION* pOut, CONST D3DXQUATERNION* pQ );
Quaternion Inverse The quaternion inverse is defined by the conjugate divided by its magnitude. It is denoted by 1
q .
*1
q
Direct3D
D3DXQUATERNION* D3DXQuaternionInverse( D3DXQUATERNION* pOut, CONST D3DXQUATERNION* pQ );
Quaternion from Euler angles (Tait-Bryan angles)
cos 2 cos 2 cos 2 sin 2 sin 2 sin 2
cos 2 sin 2 cos 2 sin 2 cos 2 sin 2
sin 2 cos 2 cos 2 cos 2 sin 2 sin 2
cos 2 cos 2 sin 2 sin 2 sin 2 cos 2
q , where is yaw, is pitch, and is roll.
Direct3D
D3DXQUATERNION* D3DXQuaternionRotationYawPitchRoll(
D3DXQUATERNION * pOut,
FLOAT Yaw,
FLOAT Pitch,
FLOAT Roll );
Euler angles (Tait-Bryan) from Quaternion
Let be yaw, be pitch, and be roll.
Mathematics Section 17
©1991 – 2016 Garth Santor & Trinh Hān GATS Encyclopaedia 205 of 278
2 2
2 2
2 2
arctan cos 01
2
arctan1
2
arcsin 2
arctan cos 01
2
0
xz wyif
x y
xz wyotherwise
y z
yz wx
xy wzif
x z
otherwise
Transformations In 3D graphics, transformations are operations that map vectors from one system to another. Transformations are commonly used to map vertices
from world coordinates to view coordinates, or view coordinates to screen coordinates.
Transformations can be represented by matrices. For a 3D system, the matrices are 4×4. The most common transformations are:
Identity
Scaling
Translation
Rotation
Projection
View
Common Transforms
Name Description Symbol Matrix d3dx function
Identity Neutral transform. Maps the value
to itself. I 1 0 0 0
0 1 0 0
0 0 1 0
0 0 0 1
D3DXMatrixIdentity()
Scale Stretch, compress, mirror. S 0 0 0
0 0 0
0 0 0
0 0 0 1
x
y
z
s
s
s
D3DXMatrixScaling()
Mathematics Section 17
©1991 – 2016 Garth Santor & Trinh Hān GATS Encyclopaedia 206 of 278
Translation Move. T 1 0 0 0
0 1 0 0
0 0 1 0
1x y zt t t
D3DXMatrixTranslation()
Z-Rotation Rotates about the origin in the XY
plane. Also called roll. Z
R , ZR cos sin 0 0
sin cos 0 0
0 0 1 0
0 0 0 1
D3DXMatrixRotationZ()
Y-Rotation Rotates about the origin in the XZ
plane. Also called yaw. Y
R , YR cos 0 sin 0
0 1 0 0
sin 0 cos 0
0 0 0 1
D3DXMatrixRotationY()
X-Rotation Rotates about the origin in the YZ
plane. Also called pitch. X
R , XR 1 0 0 0
0 cos sin 0
0 sin cos 0
0 0 0 1
D3DXMatrixRotationX()
Common Composite Transformations
Description Formula
Rotation (R) about an arbitrary point (T) -1M = T × R θ ×T
How is the rotation matrix formed?
Imagine a vector that will be rotated in the XY plane by the angle .
The absolute angle , of the initial vector ,x y can be found using trigonometry.
cos sinx r y r
The final vector ,x y can also be found using trigonometry.
cos
cos cos sin sin
cos sin
x r
x r r
x x y
sin
cos sin sin cos
sin cos
y r
y r r
y x y
The final formulas are then arranged into the columns of the matrix.
cos sin 0 0
sin cos 0 0
0 0 1 0
0 0 0 1
ZR
Mathematics Section 17
©1991 – 2016 Garth Santor & Trinh Hān GATS Encyclopaedia 207 of 278
Vector (geometric)
Cross Product
Cross product is produces a vector that is perpendicular to the two original vectors.
y z z y z x x z x y y x u× v u v -u v u v u v u v u v
x x y z z y
y y z x x z
z z x y y x
u v u v u v
u v u v u v
u v u v u v
The direction of the perpendicular is dependent upon the order in which the original vectors are multiplied.
Example:
,u = 1 0 0 v = 0 1 0
y z z y z x x z x y y xu× v = u v - u v u v - u v u v - u v
= 0×0 - 0×1 0×0 -1×0 1×1- 0×0
= 0 0 1
y z z y z x x z x y y xv ×u = v u - v u v u - v u v u - v u
= 1×0 - 0×0 0×1- 0×0 0×0 -1×1
= 0 0 -1
The cross product of vectors multiplied with a counter-clockwise order produce a vector pointing towards the viewer in a right-hand system or
away from the viewer in a left-handed system.
The cross product of vectors multiplied with a clockwise order produce a vector pointing away from the viewer in a right-hand system or toward
the viewer in a left-handed system.
Properties of cross products
Length sin a b a b
Inner Product
Inner product is the magnitude of the projection of one vector upon another. The inner product is the sum of the products of corresponding
elements of two vectors. Inner product is denoted by a small dot placed between two vectors. vu is the inner product of vectors u and v.
The value of an inner product of vectors u and v is ii vuvu where u v ¡ .
Alternatively, the inner product can be calculated using trigonometry.
u× v
u
v
Mathematics Section 17
©1991 – 2016 Garth Santor & Trinh Hān GATS Encyclopaedia 208 of 278
cosvuvu where is the angle between the direction vectors u and v, and | 0 ¡ .
Properties of inner products
Associative vuvuvu kkk
Commutative uvvu
Distributive wuvuwvu
Square 2vvv for
2v V
Magnitude
The magnitude of a vector is the scalar length of a vector.
The value of vector magnitude of vector v is i
i
2vv
Calculus
Euler’s Constant – e e – the base of the natural (hyperbolic or Naperian) logarithms.
0 !
1
!3
1
!2
1
!1
11
i ie
0
32
!!3!2!11
i
ix
i
xxxxe
function E( x ) returns real number
last 0
e denominator term 1
numerator x
while e – last > do
e e + numerator denominator
term term + 1
denominator denominator term
numerator numerator x
Note is the difference between the value 1 and the least value greater than one.
Mathematics Section 17
©1991 – 2016 Garth Santor & Trinh Hān GATS Encyclopaedia 209 of 278
Geometry
Euler Angles (Garth Santor, January 2007)
The spatial orientation of an object can be represented by a sequence of rotations about three mutually perpendicular axes. The angles of the three
rotations are collectively called Euler angles after Leonard Euler, who developed them.
Euler angles may be expressed using many conventions, the most common being the x-convention (z-x-z) and the y-convention (z-y-z).
Interpretation To interpret these conventions, imagine an object in left-hand coordinate system that contains look-vector pointing straight forward, a right-vector
pointing 90 to the right, and an up-vector orthogonal to the previous two and pointing up.
x-convention
To resolve the direction of the object using its Euler angle , , :
1. Rotate the object degrees about the world up-axis. (right- and look-axes are transformed).
2. Rotate the object degrees about the transformed right-axis. (up- and look-axes are transformed).
3. Rotate the object degrees about the transformed up-axis.
Disambiguation Yaw-pitch-roll rotations used by aerospace engineers are often called Euler angles. They are a special case of the Euler angle (y-x-z) more
appropriately called Tait-Bryan angles.
Lines – 2D
Terminology
Normal axis of a line in 2-space. A line l in 2-spae determines a unique line l’ through the origin and perpendicular to l. l’ is called the normal
axis of l.
Representation
Lines can be represented in a variety of ways.
End-point representation: A pair of vertices. (e.g. AB )
Mathematics Section 17
©1991 – 2016 Garth Santor & Trinh Hān GATS Encyclopaedia 210 of 278
Vector representation: yx ,v for 2D lines and zyx ,,v for 3D lines. Note that this representation assumes one end located at the
origin.
Parametric representation: tt vPP 0)( where 10 t for a line segment.
Linear equation representation: cbyax for 2D lines and dczbyax for 3D lines. Note that this representation has no ending points.
Slope-intercept representation: bmxy for 2D lines. Note that this representation has no ending points.
Converting Between Representations
End-point to parametric (both 2D and 3D):
AB v
Parametric (2D) to linear (2D):
xy
x
y
yxc
b
a
vPvP
v
v
0
0
Linear (2D) to slope-intercept:
b
cb
b
am
Lines – Intersection in 2 dimensions
Give two lines represented by the linear equations:
111 cybxa
222 cybxa
We can solve the system of equations for x and y producing the equations:
0 AP
Mathematics Section 17
©1991 – 2016 Garth Santor & Trinh Hān GATS Encyclopaedia 211 of 278
1221
1221
1221
2112
baba
cacay
baba
cbcbx
Note that a denominator of zero indicates that the lines are either parallel or coincident.
Finding the time of intersection of two 2D lines
Given two lines in end-point form: AB and CD
1. Create two parametric equations, one for line AB and one for line CD .
2. Create linear equations for each of the two lines.
3. Solve the system of linear equations for x and for y.
4. Find the t value of the parametric equation that produces yxt ,P .
5. t is the time of intersection.
Polyhedra Polyhedra are solids bound by faces (plane polygons); the intersection of three or more edges are called vertices. The number of faces, edges and
vertices in polyhedra obey Euler’s law: 2 evf .
Polyhedra – Regular Regular polyhedra are solids bounded by regular polygons with all vertices on a circumscribing sphere. They are also known as the Platonic
Solids.
Platonic convex solids are the regular polyhedra: tetrahedron, hexahedron (cube), octahedron, dodecahedron, and icosahedron.
Polyhedron Faces Edges Vertices Face Type
Tetrahedron 4 6 4 equilateral
triangle
Hexahedron 6 12 8 square
Octahedron 8 12 6 equilateral
triangle
Dodecahedron 12 30 20 pentagon
Icosahedron 20 30 12 equilateral
triangle
Mathematics Section 17
©1991 – 2016 Garth Santor & Trinh Hān GATS Encyclopaedia 212 of 278
Tetrahedron
Metrics
Let a be the length of an edge.
Let R be the radius of the circumscribing sphere.
Let r be the inradius – the radius of the inscribing sphere.
Number of faces 4
Number of vertices 4
Number of edges 6
Face type Equilateral triangle
bottom view
30
xd
r
R
side view
aa
aa
a
perspective view
12 33
cos6
a
x a
2
2 1 13
2 6d x a a
Area of base 21 1
32 4
A a R x a
Surface Area 23S a
Dihedral angle
1 1arctan 2 2 2arcsin 3 arccos 70.53
3 3
o
Mathematics Section 17
©1991 – 2016 Garth Santor & Trinh Hān GATS Encyclopaedia 213 of 278
Height 2 2 16
3h a x a
Radius from edge length 2 2 16
2 4
x hR a
h
Inradius 1 1 16
12 4 3r R h a h R
Angle between bottom plane and centre 1arctan arctan 2
4
r
x
Edge length from Radius 4
6
Ra
Origami
Algebraic
1 6
3 12r R a
1 43
3 3 2
Rx a
1
2d x
Vertex Table (LHR) 0 0, ,0R
0
1
23
Mathematics Section 17
©1991 – 2016 Garth Santor & Trinh Hān GATS Encyclopaedia 214 of 278
1 0, ,r x
2 , ,
2
ar d
3 , ,
2
ar d
Edge Table
0 V[0], V[1]
1 V[0], V[2]
2 V[0], V[3]
3 V[1], V[2]
4 V[1], V[3]
5 V[2], V[3]
Face Table (LHR – Clockwise visible) 0 (right) V[0], V[1], V[2]
1 (front) V[0], V[2], V[3]
2 (left) V[0], V[3], V[1]
3 (bottom) V[1], V[3], V[2]
Geometric
Construct a cube use opposing vertices on the top and bottom faces of the cube as the vertices of the tetrahedron.
Cube – Hexahedron
Metrics
Let a be the length of an edge.
Let R be the radius of the circumscribing sphere.
Mathematics Section 17
©1991 – 2016 Garth Santor & Trinh Hān GATS Encyclopaedia 215 of 278
Let r be the in-radius – the radius of the inscribing sphere.
Number of faces 6
Number of vertices 8
Number of edges 12
Face type Square
Surface area 26aS
Volume 3aV
In-radius a
2
1
Radius a3
2
1
Dihedral angle
2
1
Edge length from radius
3
2Ra
Edge length from in-radius ra 2
Origami
Which of the origami patterns can be rendered by triangle strips? Which can be rendered by triangle fans?
Mathematics Section 17
©1991 – 2016 Garth Santor & Trinh Hān GATS Encyclopaedia 216 of 278
Algebraic
32
1 Rar
Vertex Table (LHR) 0 ),,( rrr
1 rrr ,,
2 rrr ,,
3 rrr ,,
4 rrr ,,
5 rrr ,,
6 rrr ,,
7 rrr ,,
Edge Table 0 0,1
1 0,3
2 0,7
3 1,2
4 1,6
5 2,3
6 2,5
7 3,4
8 4,5
9 4,7
10 5,6
11 6,7
Face Table (LHR – clockwise visible)
0 (front) 0,1,2,3
1 (right) 3,2,5,4
2 (top) 1,6,5,2
3 (back) 4,5,6,7
4 (left) 7,6,1,0
5 (bottom) 7,0,3,4
0
1 2
3
4
56
7
Mathematics Section 17
©1991 – 2016 Garth Santor & Trinh Hān GATS Encyclopaedia 217 of 278
Octahedron
Metrics
Let a be the length of an edge.
Let R be the radius of the circumscribing sphere.
Let r be the inradius – the radius of the inscribing sphere.
Number of faces 8
Number of vertices 6
Number of edges 12
Radius from edge length 12
2R a
Edge length from radius 2a R
Inradius 16
6
13
3
r a
r R
Origami
Algebraic
Vertex Table (LHR)
0 – top )0,,0( R
1 – front ),0,0( R
Mathematics Section 17
©1991 – 2016 Garth Santor & Trinh Hān GATS Encyclopaedia 218 of 278
2 – right )0,0,( R
3 – back ),0,0( R
4 – left )0,0,( R
5 – bottom )0,,0( R
Edge Table 0 0,1
1 0,2
2 0,3
3 0,4
4 1,2
5 1,4
6 1,5
7 2,3
8 2,5
9 3,4
10 3,5
11 4,5
Face Table (LHR – clockwise visible) 0 – top, front, right 0,2,1 – top, right, front
1 – top, front, left 0,1,4 – top, front, left
2 – top, back, left 0,4,3 – top, left, back
3 – top, back, right 0,3,2 – top, back, right
4 – bottom, front, right 5,1,2 – bottom, front, right
5 – bottom, front, left 5,4,1 – bottom, left, front
6 – bottom, back, left 5,3,4 – bottom, back, left
7 – bottom, back, right 5,2,3 – bottom, right, back
Dodecahedron
Metrics
Let a be the length of an edge.
Let R be the radius of the circumscribing sphere.
Let r be the inradius – the radius of the inscribing sphere.
Number of faces 12
Number of vertices 20
Number of edges 30
Mathematics Section 17
©1991 – 2016 Garth Santor & Trinh Hān GATS Encyclopaedia 219 of 278
Radius from edge length 150 10 5
10R a
Edge length from radius 10
50 10 5
Ra
Inradius from edge length 125 10 5
10r a
Origami
Algebraic
The standard (simple) form of a dodecahedron assumes an edge length of 5 1a . This gives a dodecahedron of radius 3 . The vertices of this
dodecahedron are 10, , , 1,0, , 1, ,0 , and 1, 1, 1 , where is the golden ratio.
Vertex Table 0 ( 1, 1, 1)
1 ( 1, 1, 1)
2 ( 1, 1, 1)
3 ( 1, 1, 1)
4 ( 1, 1, 1)
5 ( 1, 1, 1)
6 ( 1, 1, 1)
7 ( 1, 1, 1)
8 10, ,
Mathematics Section 17
©1991 – 2016 Garth Santor & Trinh Hān GATS Encyclopaedia 220 of 278
9 10, ,
10 10, ,
11 10, ,
12 1,0,
13 1,0,
14 1,0,
15 1,0,
16 1, ,0
17 1, ,0
18 1, ,0
19 1, ,0
Face Table – LH 0 13, 15, 7, 11, 3
1 15, 13, 1, 9, 5
2 15, 5, 18, 19, 7
3 18, 5, 9, 8, 4
4 6, 10, 11, 7, 19
5 0, 12, 14, 4, 8
6 0, 16, 17, 2, 12
7 0, 8, 9, 1, 16
8 1, 13, 3, 17, 16
9 4, 14, 6, 19, 18
10 2, 10, 6, 14, 12
11 2, 17, 3, 11, 10
Face Table – RH 0 3, 11, 7, 15, 13
1 5, 9, 1, 13, 15
2 7, 19, 18, 5, 15
3 4, 8, 9, 5, 18
4 19, 7, 11, 10, 6
5 8, 4, 14, 12, 0
6 12, 2, 17, 16, 0
Mathematics Section 17
©1991 – 2016 Garth Santor & Trinh Hān GATS Encyclopaedia 221 of 278
7 16, 1, 9, 8, 0
8 16, 17, 3, 13, 1
9 18, 19, 6, 14, 4
10 12, 14, 6, 10, 2
11 10, 11, 3, 17, 2
Icosahedron
Metrics
Let a be the length of an edge.
Let R be the radius of the circumscribing sphere.
Let r be the inradius – the radius of the inscribing sphere.
Number of faces 20
Number of vertices 12
Number of edges 30
Radius from edge length
15 5
8R a
Algebraic
The standard (simple) form of an icosahedron assumes an edge length of 2a . This gives a icosahedron of radius 1
2 5 58
. The vertices of
this icosahedron are 0, , 1 , 1,0, , and , 1,0 , where is the golden ratio.
Vertex Table 0 (0, , 1)
1 (0, , 1)
2 (0, , 1)
3 (0, , 1)
4 ( 1,0, )
5 ( 1,0, )
6 ( 1,0, )
7 ( 1,0, )
8 ( , 1,0)
9 ( , 1,0)
10 ( , 1,0)
11 ( , 1,0)
Mathematics Section 17
©1991 – 2016 Garth Santor & Trinh Hān GATS Encyclopaedia 222 of 278
Face Table - LH 0 0,1,8
1 0,8,4
2 0,4,6
3 0,6,10
4 0,10,1
5 1,10,7
6 1,7,5
7 1,5,8
8 2,3,11
9 2,11,6
10 2,6,4
11 2,4,9
12 2,9,3
13 3,9,5
14 3,5,7
15 3,7,11
16 4,8,9
17 5,9,8
18 6,11,10
19 7,10,11
Mathematics Section 17
©1991 – 2016 Garth Santor & Trinh Hān GATS Encyclopaedia 223 of 278
Origami
Sphere
Spheres can be generated using a regular icosahedron, quadric functions and trigonometry.
Trigonometry solution
Fill a vertex/index buffer with a sphere measured by slices (longitude) and stacks (latitude).
Mathematics Section 17
©1991 – 2016 Garth Santor & Trinh Hān GATS Encyclopaedia 224 of 278
procedure SPHERE( V, X, slices, stacks, R )
input: slices is the number of vertical partitions of the sphere
stacks is the number of horizontal partitions of the sphere
r is the radius of the sphere
output: V is a vertex buffer where the vertices contain a 3D coordinate – pos, a normal – nor, and a 2D texture coordinate – tex
X is an index buffer
1 1length V slices stacks
for iStack ← 0 to stacks do
𝑙𝑎𝑡𝑖𝑡𝑢𝑑𝑒 ← 𝜋2∙𝑖𝑆𝑡𝑎𝑐𝑘−𝑠𝑡𝑎𝑐𝑘𝑠
2∙𝑠𝑡𝑎𝑐𝑘𝑠
for iSlice ← 0 to slices do
𝑙𝑜𝑛𝑔𝑖𝑡𝑢𝑑𝑒 ← 𝜋2∙𝑖𝑆𝑙𝑖𝑐𝑒−𝑠𝑙𝑖𝑐𝑒𝑠
𝑠𝑙𝑖𝑐𝑒𝑠
𝑖 ← 𝑙𝑎𝑡𝑖𝑡𝑢𝑑𝑒(𝑠𝑙𝑖𝑐𝑒𝑠 + 1) + 𝑙𝑜𝑛𝑔𝑖𝑡𝑢𝑑𝑒
cos cos ,sin ,cos sinnor V i
pos V i R nor V i
,1longitude latitude
tex V islices stacks
0j
for latitude ← 0 to stacks – 1 do
for longitude ← 0 to slices – 1 do
1offset latitude slices longitude
X j offset
1 1X j offset slices
2 1 1X j offset slices
3X j offset
4 1 1X j offset slices
5 1X j offset
6j j
Tait-Bryan Angles (Garth Santor, January 2007)
Tait-Bryan angles are special-case Euler angles used in aerospace engineering and computer graphics amongst other disciplines. As will Euler
angles, an object’s orientation is expressed as a sequence of angles representing angular displacement from axes. In the Tait-Bryan system, the
angles represent roll, pitch and yaw. In a left-hand coordinate system, a z-x-y Euler angle system.
Mathematics Section 17
©1991 – 2016 Garth Santor & Trinh Hān GATS Encyclopaedia 225 of 278
Graphs
Definitions
The pictorial representative of a relation between variables.
From Gk. graphē, writing.
A graph EVG , where V is a set of vertices and E is a set of edges. Each edge is a pair wv, , where Vwv , . Vertices are often
referred to as nodes, and edges as arcs.
Arcs or edges are assumed to navigable in both directions. Such graphs are called undirected graphs.
Graphs in which the edge pairs are ordered are called directed graphs or digraphs. An alternate name is unidirectional graph.
A vertex v is said to be adjacent to vertex w if and only if Ewv , .
Some graphs have edges with a third component called a weight. The weight usually represents the cost of traversing that edge. These graphs
are called weighted graphs or weighted digraphs if unidirectional.
A path is a sequence of vertices that are connected by edges.
A cycle is a path in a digraph that begins and ends at the same vertex and contains at least one edge.
A graph is dense if the number of edges is large. 2VE .
A graph is sparse if the number of edges is small. VE .
Representations Graphs can be represented graphically. Circles indicate vertices or nodes – arrows indicate edges or arcs. Bi-directional graphs have arrows at
either end of the arcs, whereas digraphs have arrows only at one end.
Mathematics Section 17
©1991 – 2016 Garth Santor & Trinh Hān GATS Encyclopaedia 226 of 278
Digraph
Adjacency Tables
Adjacency tables (also called adjacency matrices) are 2-dimensional arrays each axis enumerates all the nodes in the graph. Adjacency is
represented by storing a Boolean value – true – at the cross-reference of the two nodes. Weighted graphs would store the arc weight in the cross-
referenced element.
The weighted graph above would have the following adjacency tables (left is weighted, right is un-weighted):
A B C D E
A -1 5 45 -1 -1
B 5 -1 30 20 -1
C 45 30 -1 10 7
D -1 20 10 -1 8
E -1 -1 7 8 -1
A B C D E
A f t t f f
B t f t t f
C t t f t t
D f t t f t
E f f t t f
Empty spots would be initialized to a value of zero or negative one.
You may have noticed that the information in the graph is symmetrical (i.e. the entry (x,y) contains the same information as entry (y,x) ). Memory
can be minimized by allocating rows that are no-longer than the row index. Row one has one element, row two has two elements, row n has n
elements. Any lookup into the table sorts the pairs before referencing the table element. If your algorithm can avoid lookups where the row and
column index are equal (i.e. where x = y) then only rowIndex – 1 elements need to be stored for each row of the table.
In a digraph, one axis would represent the origin node and the other axis the destination node.
8
Weighted Graph
b
c
d
30
10
20
a
5
45
e
7
Mathematics Section 19
©1991 – 2016 Garth Santor & Trinh Hān GATS Encyclopaedia 227 of 278
This general form for an adjacency table is useful for representing graphs in which any node could be connected to any other node.
The storage efficiency improves when the graph is dense but suffers when the graph is sparse.
To locate the neighbours of a given node, you examine each element in that node’s row of the table. This is relatively efficient for dense graphs,
but inefficient for sparse graphs.
Adjacency tables are often used to model airline graphs, phone and computer networks, or jump-gates in space games.
Adjacency Lists
Adjacency tables can be represented using linked lists. Each node maintains a list of the nodes that are adjacent to it.
The preceding adjacency table represented as an adjacency list would be:
B
A
A
B
C
C
C
B
C
D
D
D E
E
Direction Tables
Many games, most notably dungeon stomps have very sparse adjacency tables. Typically, a room will only connect to physically adjacent rooms.
Thus an adjacency table with 100 rooms would require a 100 by 100 matrix – 10,000 elements. We typically find that dungeon rooms can only be
exited in one of four directions – east, west, north, south. Since each room could only have a maximum of 4 adjacent rooms the most dense the
table could be is 400 used entries of the 10,000 total elements, or 0.4%.
A much more compact data structure, but much more limiting would be to store the numbers of the rooms accessible from the current room in
each of the 4 compass directions.
Example, given the following dungeon:
Mathematics Section 19
©1991 – 2016 Garth Santor & Trinh Hān GATS Encyclopaedia 228 of 278
0 1
2 3 4
5 6
We could produce a 7 by 7 adjacency table:
0 1 2 3 4 5 6
0 0 1 1 0 0 0 0
1 1 0 0 1 0 0 0
2 1 0 0 1 0 0 0
3 0 1 1 0 1 1 0
4 0 0 0 1 0 0 0
5 0 0 0 1 0 0 1
6 0 0 0 0 0 1 0
Storage efficiency is 29%.
Using a direction table, we would store:
N E S W
0 -1 1 2 -1
1 -1 -1 3 0
2 0 3 -1 -1
3 1 4 5 2
4 -1 -1 -1 3
5 3 6 -1 -1
6 -1 -1 -1 5
Storage efficiency is 50%.
Of course we could always store the adjacency matrix as a bitmap since all of the information is a true/false.
The direction table can also be stored as a bitmap, by renumbering rooms to correspond to cells in a complete grid.
Mathematics Section 20
©1991 – 2016 Garth Santor & Trinh Hān GATS Encyclopaedia 229 of 278
0 1 2
3 4 5
6 7 8
N E S W
0 0 1 1 0
1 0 0 1 1
2 0 0 0 0
3 1 1 0 0
4 1 1 1 1
5 0 0 0 1
6 0 0 0 0
7 1 1 0 0
8 0 0 0 1
Path-finding Graph path-finding determines a sequence of edges and nodes that connect a source node in the graph with a destination node in the graph. Path-
finding algorithms come in many varieties trading performance for path quality. Dijkstra’s single-source, shortest-path algorithm guarantees an
optimal path, but at the expense of time. The A* algorithm is a fast algorithm that finds good paths most of the time, but not all of the time.
Random Search Random search is virtually useless. It cannot determine whether a path to the destination is possible. Nor does it eliminate cycles in the path it
generates.
procedure RANDOM-SEARCH( Graph, s, e ) returns Queue
Q ← { s }
while s ≠ e do
randomly choose child such that ][, GEchilds
s ← child
ENQUEUE( Q, s )
return Q
Depth-first Search
Depth first search is a very natural search technique commonly employed by people solving maze problems, that is the “take every right turn until
you get stuck or cross your own path, then back up and take the other turn” approach. Depth-first search does exactly that – constantly moving
away from the source.
Mathematics Section 21
©1991 – 2016 Garth Santor & Trinh Hān GATS Encyclopaedia 230 of 278
The graph requires two extra elements, a colour for marking the explored vertices and a link to the parent node.
1. colour all the vertices white and set the parent links to nil.
2. investigate vertex start
The investigate procedure Tcolours each vertex TGREY when first visited and then TBLACK when all of the adjacent vertices have been visited
(although marking the vertex TBLACK is optional). Each newly visited vertex has its Tparent link set to the source vertex.
procedure DEPTH-FIRST-SEARCH( G, s )
for each vertex ][GVu do
color[u] ← white
parent[u] ← nil
DFS-INVESTIGATE( s )
procedure DFS-INVESTIGATE( u )
colour[u] ← grey
for each vertex ][uadjv do
if colour[v] = white
then parent[v] ← u
DFS-INVESTIGATE( v )
colour[u] ← black
Extracting the Path
The path from any vertex to the source vertex is stored in the graph. You can extract the path by following the parent links back from the
destination vertex to the source vertex.
procedure EXTRACT-PATH( G, s, t, P )
if s = t then
P ← s
else if parent[t] = NIL then
P ← Φ
else
P ← EXTRACT-PATH( G, s, parent[t], P ) + t
Breadth-first Search
This breadth-first search algorithm presented here requires that the graph store three additional attributes: a colour, a distance and a link to another
vertex.
1. We start by colouring all of the vertices WHITE to indicate that they have not been processed. The distance from the source is unknown is
represented by an impossible value (such as –1) or ∞. The parent links are set to NIL.
2. Set the source vertex colour to GREY, indicating that the node has been visited but not that vertices adjacent to it have not been explored.
Set its distance to zero. Indicating that it is zero hops from the source.
3. Add the source vertex to a queue of GREY vertices (i.e. vertices we are visiting, but not finished with).
Mathematics Section 21
©1991 – 2016 Garth Santor & Trinh Hān GATS Encyclopaedia 231 of 278
4. While the queue contains grey vertices, do
a. get and remove the vertex from the front of the queue
b. add each adjacent WHITE vertex to the queue after set its distance to one hop more than the current vertex and setting its parent to
the current vertex
c. colour the current vertex BLACK
procedure BREADTH-FIRST-SEARCH( G, s ) inputs: G, a graph
s, the path source vertex
outputs: G, modified graph (colours, distance and parents updated)
for each Tvertex u V G s
Tdo color[u] ← WHITE
distance[u] ← ∞
parent[u] ← NIL
color[s] ← GREY
distance[s] ← 0
parent[s] ← NIL
Q ← { s }
while Q do
u ← head[Q]
for each [ ]v Adj u do
if colour[v] = WHITE
then colour[v] ← GREY
distance[v] ← distance[u] + 1
parent[v] ← u
ENQUEUE( Q, v )
DEQUEUE( Q )
colour[u] ← BLACK
As with the depth-first search the path can be extracted using the EXTRACT-PATH procedure.
Dijkstra’s Algorithm
Created by Dr. Edsger Wybe Dijkstra (1930-2002), this single-source, shortest-path algorithm is amazingly efficient.
procedure SHORTEST-PATH( G, s, d )
INITIALIZE-SINGLE-SOURCE( G, s )
Q ← V[G]
while Q ≠ Φ do
u ← EXTRACT-MIN( Q )
for each vertex ][uadjv do
RELAX( u, v, w )
Mathematics Section 21
©1991 – 2016 Garth Santor & Trinh Hān GATS Encyclopaedia 232 of 278
procedure RELAX( u, v, weight )
if cost[v] > cost[u] + weight(u,v)
then cost[v] ← cost[u] + weight(u,v)
parent[v] ← u
procedure INITIALIZE-SINGLE-SOURCE( G, s )
for each vertex ][GVv do
cost[v] ← ∞
parent[v] ← nil
cost[s] ← 0
A* Algorithm
One of the greatest problems with DFS, BFS and Dijkstra’s algorithm is that they all search the entire graph for a solution. This can be prohibitive
in a real-time application with a large graph. The A* star algorithm is a variation of DFS that borrows some features from Dijkstra’s algorithm. In
essence, it’s a depth-first search that guesses at the best direction to search. It quits as soon as a solution is found.
The heuristic used to guess at the best direction can be tuned to exhibit seemingly complex behaviour such as preferring the same altitude to higher
altitudes when navigating through mountainous terrain.
The graph vertex requires three cost attributes g, h, f that indicate:
1. the current cost to get to the current vertex (g),
2. the best guess cost to get to goal vertex (h),
3. the best guess at the final total cost (f = g + h)
and a link to the parent vertex in the search path.
Mathematics Section 21
©1991 – 2016 Garth Santor & Trinh Hān GATS Encyclopaedia 233 of 278
procedure A-STAR-SEARCH( G, s, e )
g[s] ← 0
h[s] ← HEURISTIC( s, e )
f[s] ← g[s] + h[s]
ENQUEUE( OpenList, s )
while OpenList ≠ Φ do
find b OpenList such that [ ] [ ],f b f x x OpenList
if b = e return ∆path has been found
for each [ ]c adj b do
g ← g[b] + DISTANCE( b, c )
h ← HEURISTIC( c, e )
f ← g + h
if c OpenList and f > f[c] then continue
if c ClosedList and f > f[c] then continue
OpenList OpenList c
ClosedList ClosedList c
parent[c] ← b
h[c] ← h
g[c] ← g
f[c] ← f
OpenList OpenList c
ClosedList ClosedList b
Logic & Boolean Algebra There are three major systems of logic:
Syllogistic logic – 19 correct argument forms identified by Aristotle.
Propositional logic – building block approach of English mathematician George Boole.
Predicate logic – combination of syllogistic and propositional logic created by Gottlob Frege.
Mathematical Induction Mathematical induction is method for proving that a proposition (such as a formula) is true for all possible values.
Theorem (First Principle of Mathematical Induction)
Let ( )P n be a predicate and 0n be an integer for which the following conditions are satisfied.
1. Every integer greater than or equal to 0n belongs to the domain of ( )P n ;
Mathematics Section 21
©1991 – 2016 Garth Santor & Trinh Hān GATS Encyclopaedia 234 of 278
2. 0P n is true;
3. for every integer 0n n , ( )P n implies ( 1)P n .
Then ( )P n is true for each integer 0n n .
Example: sum of a series of integers
0
1
2
n
i
n ni
Let 1
2
n nP n
where n¥
0
0
0 0 10 0
2 i
P i
, which satisfies point 2 of the theorem.
To satisfy point 3 of the theorem we assume that P n is true and show that 1P n necessarily follows.
2
2 2
2 2
( 1) 1 ( )
1 1 1 11
2 2
1 2 2 1
2 2 2
3 2 2 2
2 2 2
3 2 3 2
2 2
P n n P n
n n n nn
n n n n n
n n n n n
n n n n
Theorem (Second Principle of Mathematical Induction)
Let ( )P n be a predicate and 0n be an integer for which the following conditions are satisfied.
1. Every integer greater than or equal to 0n belongs to the domain of ( )P n ;
2. 0P n is true;
3. for every integer 0n n , 0.. ,k n n P k implies ( 1)P n .
Then ( )P n is true for each integer 0n n .
Propositional Logic Proposition logic connectives
Name Meaning Notation
Mathematics Section 21
©1991 – 2016 Garth Santor & Trinh Hān GATS Encyclopaedia 235 of 278
negation not
conjunction and
disjunction or
implication if … then …
equivalence (biconditional) if and only if
Negation
A negation p is true if and only if p is false.
p p
True false
False true
English interpretations:
not p
p does not hold
it is not the case that p
p is false
Conjunction
A conjunction qp is true if and only if both p and q are true.
p q qp
true true true
true false false
false true false
false false false
English interpretations:
p and q
p but q
Mathematics Section 21
©1991 – 2016 Garth Santor & Trinh Hān GATS Encyclopaedia 236 of 278
not only p but q
p while q
p despite q
p yet q
p although q
Disjunction
A disjunction qp is true if and only if p is true or q is true. That is, either p or q is true or both are true.
p q qp
true true true
true false true
false true true
false false false
English interpretations:
p or q
p or q or both
p and/or q
p unless q
Implication
An implication qp is false if and only if p is true and q is false.
p q qp
true true true
true false false
false true true
false false true
English interpretations:
Mathematics Section 21
©1991 – 2016 Garth Santor & Trinh Hān GATS Encyclopaedia 237 of 278
if p then q
q if p
p only if q
q when p
p is sufficient for q
q is necessary for p
p implies q
p materially implies q
Equivalence
An equivalence, qp is true if and only if both p and q have the same truth value.
p q qp
true true true
true false false
false true false
false false true
English interpretations:
p if and only if q
q iff p
p is necessary and sufficient for q
p exactly if q
p is materially equivalent to q
Mathematics Section 21
©1991 – 2016 Garth Santor & Trinh Hān GATS Encyclopaedia 238 of 278
Number Systems
Two’s Complement
Fast Conversion – for humans Two’s complements numbers can be quickly converted to its negative by:
1. Copying all the zeros from the LSB until the first one is reached.
2. Copy that one.
3. Flip the remaining bits.
Example:
0001 1100 → 1110 0100
0001 1100 → 1110 0011 + 1 → 1110 0100
Sign Extension When increasing the number of bits in a two’s complement representation extend the sign bit (MSB) into the extra bits.
Statistics
Arithmetic Mean Mean is the statistic that most people call ‘average’ and is a measure of central tendency.
1
1 N
i
i
x xN
The symbol μ is often used to represent the mean.
Frequency distribution A frequency distribution tabulates raw data by dividing the range of the data values in even intervals and then counting the number of samples that
fall into each interval. The frequencies are typically expressed as absolute counts or as a relative count (percentage of overall data set).
Example:
{1,2,3,3,4,5,5,5,6,7,7,8}S
Mathematics Section 21
©1991 – 2016 Garth Santor & Trinh Hān GATS Encyclopaedia 239 of 278
Class interval Absolute frequency Relative frequency
1.0 – 2.9 2 0.167
3.0 – 4.9 3 0.250
5.0 – 6.9 4 0.333
7.0 – 8.9 3 0.250
Histogram A graphical representation of a frequency distribution where the frequency is plotted against the interval classes. Typically a bar chart is used.
Mode The mode of a set is the most commonly occurring value in that set.
For example:
mode
{1,2,3,3,4,5,5,5,6,7,7,8}
5
S
S
When two values appear as the most commonly occurring value, the set is called bi-modal and when there are more than two most-commonly
occurring values the set is called multi-modal.
mode
{1,2,3,3,4,5,5,5,6,7,7,7,8}
{5,7}
S
S
Standard Deviation & Variance Variance is the mean of the squares of the deviations from the data set’s mean.
N
X
2
2
is the formula for the population variance.
Standard deviation is the square root of the variance.
N
X
2
2
is the formula for the population standard deviation.
Notes:
X is data set.
N is size of data set.
μ is the mean of X
Mathematics Section 21
©1991 – 2016 Garth Santor & Trinh Hān GATS Encyclopaedia 240 of 278
Implementation
function VARIANCE( X ) returns a real number
← MEAN( X )
accumulator ← 0
for each x X do
2
accumulator accumulator x
return accumulator length X
Statistical Median A measure of central tendency and an ordering statistic that gives the ‘middle’ value of a sample. It is the value for which ½ of the samples have a
lower value and ½ of the samples have a greater value.
2 1
2 2 1
1mod 22
0mod 22
i
i i
XX
xX X
X
%
Mathematics Section 21
©1991 – 2016 Garth Santor & Trinh Hān GATS Encyclopaedia 241 of 278
Trigonometry (from Greek: trigonon = three angles, metro = measure)
Trigonometry is the branch of mathematics dedicated to angles, triangles and the
functions that describe their relationships. Many consider trigonometry the
computational component of geometry and therefore a subtopic of geometry.
Trigonometric Functions
The trigonometric functions represent ratios of right- angle triangles.
sinopposite
hypotenuse
1csc
sin
hypotenuse
opposite
cosadjacent
hypotenuse
1sec
cos
hypotenuse
adjacent
sintan
cos
opposite
adjacent
coscot
sin
adjacent
opposite
Inverse functions
Many students often confuse the trigonometric inverse functions with arithmetic inverse functions. This is an unfortunate problem with the
notation.
The arithmetic inverse of the sine function is: 1 1
sin cscsin
hypo
tenu
se op
posite
P(x,y)
+x
+y
θ
Mathematics Section 21
©1991 – 2016 Garth Santor & Trinh Hān GATS Encyclopaedia 242 of 278
The trigonometric inverse produces the angle from the ratio (as opposed to the trig. functions that produce the ratio from the angle). The
unfortunate notation uses an exponent squeezed in between the function name and the angle variable.
e.g. 1sinopposite
hypotenuse This is distinctly different from
1
sinopposite
hypotenuse
It is for this reason that I suggest using the older notation:
arcsin arccos arctanopposite adjacent opposite
hypotenuse hypotenuse adjacent
This notation has two additional advantages:
1. It constantly reminds us that the inverse trigonometric functions produce an angular measure of arc.
2. It matches the notation used by most computer math libraries. e.g. atan() is the arc tangent function in the C-Standard library.
Just to make things confusing…
The same is not true of positive exponents. Mathematicians do write the squares of trigonometric functions as:
22sin sin sin sin
Useful formulae
Given, ,P x y is a point on a circle of radius r.
r hypotenuse The radius of the circle is the same as the magnitude (or length) of the
hypotenuse.
cosx r The x-component can be calculated as a function of angle and radius.
siny r The y-component can be calculated as a function of angle and radius.
arctany
x
The angle from the origin to point P.
2 2sin cos 1 From the Pythagorean theorem. Usually written as
2 2tan 1 sec This follows from the Pythagorean theorem above.
2 21 cot csc This follows from the Pythagorean theorem above.
2 2
2 2
sin sin sin sin
cos cos
An often useful identity.
Mathematics Section 21
©1991 – 2016 Garth Santor & Trinh Hān GATS Encyclopaedia 243 of 278
2 2
2 2
cos cos cos sin
cos sin
An often useful identity.
cos cos cos sin sin
sin cos sin sin cos
Operating Systems Section 22
©1991 – 2016 Garth Santor & Trinh Hān GATS Encyclopaedia 244 of 278
Operating Systems
Windows Vista
Automatic Log In 1. Launch a more advanced user accounts management application by typing ‘control userpasswords2’ in the start menu’s search box.
2. Uncheck ‘Users must enter a user name and password to use this computer’.
3. Click OK.
4. Open Power Options window in Control Panel.
5. Click: ‘Change plan settings’.
6. Click ‘Change advanced power settings’.
7. Under addition settings, set ‘Require a password on wakeup’ to ‘no’.
8. Open ‘Personalization’ window in Control Panel.
9. Click ‘Screen Saver’.
10. Uncheck ‘On resume, display logon screen’.
Physics Section 23
©1991 – 2016 Garth Santor & Trinh Hān GATS Encyclopaedia 245 of 278
Physics
General
Bounce (Garth Santor, January 2007)
Some energy retention rates of common balls bouncing on a steel plate.
Ping-pong ball 15%
Baseball 32%
Golf ball 36%
Soccer ball 40%
Tennis ball 49%
Basket ball 56%
Super ball 81%
Steel ball 98%
Gravity Acceleration due to gravity 9.8 / /g m s s
Distance an object falls 21
2d g t
Time to fall a given distance 2dt
g
Instantaneous velocity after time t iv g t
Instantaneous velocity after distance d 2iv gd
Average velocity over time t 1
2av g t
Physics Section 23
©1991 – 2016 Garth Santor & Trinh Hān GATS Encyclopaedia 246 of 278
Average velocity over distance d 2
2a
gdv
Material Properties
Description
Material properties describe the light response properties of a material. Light response is separated into 5 categories; ambient colour, diffuse
colour, specular colour, emissive colour and shininess. All colour properties are expresses as four-component clamped colours. The colour
components are red, green, blue and transparency, with values range of 0.0 to 1.0. The value 0.0 represents black for the colour components and
fully transparent for the transparency component.
Light Source Materials
name ambient diffuse specular emission shininess
white 0, 0, 0, 0 0, 0, 0, 0 0, 0, 0, 0 1, 1, 1, 1 0.0
Physics Section 23
©1991 – 2016 Garth Santor & Trinh Hān GATS Encyclopaedia 247 of 278
Metals
Physics Section 23
©1991 – 2016 Garth Santor & Trinh Hān GATS Encyclopaedia 248 of 278
name ambient diffuse specular emission shininess
brass 0.329412,
0.223529,
0.027451,
1.0
0.780392,
0.568627,
0.113725,
1.0
0.992157,
0.941176,
0.807843,
1.0
0,
0,
0,
0
27.8974
bronze 0.2125,
0.1275,
0.054,
1.0
0.714,
0.4284,
0.18144,
1.0
0.393548,
0.271906,
0.166721,
1.0
0,
0,
0,
0
25.6
bronze (polished)
0.25,
0.148,
0.06475,
1.0
0.4,
0.2368,
0.1036,
1.0
0.774597,
0.458561,
0.200621,
1.0
0,
0,
0,
0
76.8
chrome 0.25,
0.25,
0.25,
1.0
0.4,
0.4,
0.4,
1.0
0.774597,
0.774597,
0.774597,
1.0
0,
0,
0,
0
76.8
copper 0.19125,
0.0735,
0.0225,
1.0
0.7038,
0.27048,
0.0828,
1.0
0.256777,
0.137622,
0.086014,
1.0
0,
0,
0,
0
12.8
copper (polished)
0.2295,
0.08825,
0.0275,
1.0
0.5508,
0.2118,
0.066,
1.0
0.580594,
0.223257,
0.0695701,
1.0
0,
0,
0,
0
51.2
gold 0.24725,
0.1995,
0.0745,
1.0
0.75164,
0.60648,
0.22648, 1.0
0.628281,
0.555802,
0.366065,
1.0
0,
0,
0,
0
51.2
gold (polished)
0.24725,
0.2245,
0.0645,
1.0
0.34615,
0.3143,
0.0903,
1.0
0.797357,
0.723991,
0.208006,
1.0
0,
0,
0,
0
83.2
pewter 0.105882,
0.058824,
0.113725,
1.0
0.427451,
0.470588,
0.541176,
1.0
0.333333,
0.333333,
0.521569,
1.0
0,
0,
0,
0
9.84615
silver 0.19225,
0.19225,
0.19225, 1.0
0.50754,
0.50754,
0.50754, 1.0
0.508273,
0.508273,
0.508273,
1.0
0,
0,
0,
0
51.2
Physics Section 23
©1991 – 2016 Garth Santor & Trinh Hān GATS Encyclopaedia 249 of 278
silver (polished)
0.23125,
0.23125,
0.23125, 1.0
0.2775,
0.2775,
0.2775,
1.0
0.773911,
0.773911,
0.773911,
1.0
0,
0,
0,
0
89.6
Miscellaneous Substances
name ambient diffuse specular emission shininess
rubber (black)
0.02,
0.02,
0.02,
1.0
0.01,
0.01,
0.01,
1.0
0.4,
0.4,
0.4,
1.0
0,
0,
0,
0
10.0
rubber (cyan)
0.0,
0.05,
0.05,
1.0
0.4,
0.5,
0.5,
1.0
0.04,
0.7,
0.7,
1.0
0,
0,
0,
0
10.0
rubber (green)
0.0,
0.05,
0.0,
1.0
0.4,
0.5,
0.4,
1.0
0.04,
0.7,
0.04,
1.0
0,
0,
0,
0
10.0
rubber (red) 0.05,
0.0,
0.0,
1.0
0.5,
0.4,
0.4,
1.0
0.7,
0.04,
0.04,
1.0
0,
0,
0,
0
10.0
rubber (white)
0.05,
0.05,
0.05,
1.0
0.5,
0.5,
0.5,
1.0
0.7,
0.7,
0.7,
1.0
0,
0,
0,
0
10.0
rubber (yellow)
0.05,
0.05,
0.0,
1.0
0.5,
0.5,
0.4,
1.0
0.7,
0.7,
0.04,
1.0
0,
0,
0,
0
10.0
shiny (white) 1,1,1,1 1,1,1,1 1,1,1,1 0,0,0,0 100.0
Physics Section 23
©1991 – 2016 Garth Santor & Trinh Hān GATS Encyclopaedia 250 of 278
Plastics
name ambient diffuse specular emission shininess
black 0.0,
0.0,
0.0,
1.0
0.01,
0.01,
0.01,
1.0
0.5,
0.5,
0.5,
1.0
0,
0,
0,
0
32.0
cyan 0.0,
0.1,
0.06,
1.0
0.0,
0.50980392,
0.50980392,
1.0
0.50196078,
0.50196078,
0.50196078,
1.0
0,
0,
0,
0
32.0
green 0.0,
0.0,
0.0,
1.0
0.1,
0.35,
0.1,
1.0
0.45,
0.55,
0.45,
1.0
0,
0,
0,
0
32.0
red 0.3,
0,
0,
1
0.6,
0,
0,
1
0.8,
0.6,
0.6,
1
0,
0,
0,
0
32.0
white 0,
0,
0,
1
0.55,
0.55,
0.55,
1
0.70,
0.70,
0.70,
1
0,
0,
0,
0
32.0
yellow 0,
0,
0,
1
0.5,
0.5,
0,
1
0.60,
0.60,
0.5,
1
0,
0,
0,
0
32.0
Physics Section 23
©1991 – 2016 Garth Santor & Trinh Hān GATS Encyclopaedia 251 of 278
Stones
name ambient diffuse specular emission shininess
emerald 0.0215,
0.1745,
0.0215,
1.0
0.07568,
0.61424,
0.07568,
1.0
0.633,
0.727811,
0.633,
1.0
0,
0,
0,
0
76.8
jade 0.135,
0.2225,
0.1575,
1.0
0.54,
0.89,
0.63,
1.0
0.316228,
0.316228,
0.316228,
1.0
0,
0,
0,
0
12.8
obsidian 0.05375,
0.05,
0.06625,
0.82
0.18275,
0.17,
0.22525,
0.82
0.332741,
0.328634,
0.346435,
0.82
0,
0,
0,
0
38.4
pearl 0.25,
0.20725,
0.20725,
0.922
1.0,
0.829,
0.829,
0.922
0.296648,
0.296648,
0.296648,
0.922
0,
0,
0,
0
11.264
ruby 0.1745,
0.01175,
0.01175,
0.55
0.61424,
0.04136,
0.04136,
0.55
0.727811,
0.626959,
0.626959,
0.55
0,
0,
0,
0
76.8
turquoise 0.1,
0.18725,
0.1745,
0.8
0.396,
0.74151,
0.69102,
0.8
0.297254,
0.30829,
0.306678,
0.8
0,
0,
0,
0
12.8
Game
Collision Detection Collision detection is an expensive stage in a game’s logic/physics system. The number of possible collisions grows significantly as more objects
are introduced into the model. Examine the following table.
# of objects # of possible collisions/interactions
1 0
2 1
3 3
4 6
Physics Section 23
©1991 – 2016 Garth Santor & Trinh Hān GATS Encyclopaedia 252 of 278
5 10
n
1
0
11
2
n
i n n
Clearly, collisions/interactions are 2O n .
Any technique that can reduce the number of interactions could potentially save huge amounts of processing.
Bounding circle/sphere collision detection
One of the simplest forms of collision detection is bounding circle (2D) or bounding sphere (3D). The idea is
to measure the distance between the centre points of the two objects being tested for collision. If the distance
between the two objects is less than the sum of radii of the smallest circle/sphere that fully encloses the
object, then a collision has occurred.
2 2 2
x y z
r r
D A B
d D D D
d A B
The presence of a square root in the distance formula is a short-coming since square root calculations are
rarely cheap.
However, the actual distance is not required, just the whether or not a collision occurred. Therefore, the square of the distance can be compared to
the square of the sum of the radii.
2 2 2 2
22
x y z
r r
D A B
d D D D
d A B
The new calculation can be computed using only adds and multiplies and is potentially much faster.
Metric
Prefixes
micro-
Combining form: one millionth of a specified unit. E.g. microsecond is a millionth of a second. [ < Gk. micros small]
milli-
Combining form: one thousandth of a specified unit. E.g. millisecond is a thousandth of a second. [ < L. mille thousand]
r
r
d
A
B
Physics Section 23
©1991 – 2016 Garth Santor & Trinh Hān GATS Encyclopaedia 253 of 278
nano-
Combining form: one billionth of a specified unit. E.g. nanosecond is a billionth of a second. [ < Gk. nanos dwarf]
pico-
Combining form: one trillionth of a specified unit. E.g. picosecond is a trillionth (1E-12) of a second. [ < Sp. small quantity, peak]
Programming Concepts Section 24
©1991 – 2016 Garth Santor & Trinh Hān GATS Encyclopaedia 254 of 278
Programming Concepts
Concurrent Programming
Best Practices
Avoid Calling Unknown Code While Inside a Critical Section See Dr. Dobb’s Journal: Issue 403 – December 2007.
To summarize Herb Sutter:
Avoid calling library functions that cannot promise the absence of locks.
Avoid calling plug-ins.
Avoid calling other callbacks, function pointers, function delegates, etc.
Avoid calling virtual methods.
Avoid calling generic methods, or methods on a generic type.
Use Lock Hierarchies to Avoid Deadlock See Dr. Dobb’s Journal: Issue 404 – January 2008.
To quote Herb Sutter:
Write a wrapper around each of your favourite language- or platform-specific mutex types, and let the wrapper’s constructor(s) take a
level number parameter that is in a myLevel member. Use these wrappers everywhere.
Give the wrapper class a thread-local static variable called currentLevel, initialized to a value higher than any valid lock level.
In the wrapper’s lock method, assert that currentLevel is greater than myLevel, the level of the mutex that you’re about to try to acquire.
Remember, if the previous value of currentLevel is using another member variable, then set currentLevel = myLevel; and acquire the lock.
In the wrapper’s unlock method, restore the previous value of currentLevel.
As needed, also wrap other necessary methods you need to be able to use, such as try_lock. Any of these methods that might try to acquire
the lock should do the same things lock does.
Finally, write a “lock-multiple” method lock( m1, m2, … ) that takes a variable number of lockable objects, asserts that they are all at the
same level, and locks them in their address order (or their GUID order, or some other globally consistent order).
Programming Concepts Section 24
©1991 – 2016 Garth Santor & Trinh Hān GATS Encyclopaedia 255 of 278
Internal vs. External Locking When a function or method is a critical section (such as the enqueue and deque operations of a shared queue), we must decide whether to have the
method establish the lock or the caller establish the lock.
Internal Locking
Pros
Easy to use – the lock is applied to the critical section by the function/method automatically.
Less code – lock is implemented once in the function/method and not at each call location.
Reliability – the correct lock is always applied – no mix ups.
Cons
Efficiency – repeated calls to the function cause multiple locking/unlocking cycles.
Lack of transparency – lock is not obvious to the caller.
Risk of deadlock – in a multiple lock scenario, the lack of transparency makes it difficult for the caller to notice the possibility of
deadlock.
External Locking
Pros
Transparency – the lock is visible to the coder.
Deadlocks – easier to prevent deadlocks in a multiple-lock scenario.
Efficiency – can lock once and perform repeated calls.
Cons
More code – every call must have its own locking code.
Reliability – could forget lock, or use the wrong lock.
Efficiency – could apply lock for a longer duration then necessary (although this is relatively easy to avoid.)
Conclusions If you don’t know, use external locking. It provides good performance and safety.
If you can guarantee that the object will never be used in a multiple lock scenario, use internal locking.
Programming Concepts Section 24
©1991 – 2016 Garth Santor & Trinh Hān GATS Encyclopaedia 256 of 278
Zombie Process A zombie process is a process that has finished processing but has not yet been deallocated by the parent process.
Zombie processes occur as a natural part of a process’ life cycle. Processes typically end when they call the exit() or abort() routines or their
main() function returns. At this time the kernel releases any resources allocated to the process, but it maintains the exit status and process ID in
the process table. This dead but not buried state is called the zombie state. This state is identifiable using Unix’s ps command and is indicated by
a ‘Z’ in the status column. (Linux requires ‘ps j’ to get the status listing.)
A process remains in the zombie state until its parent process checks for the completion of the process by checking its exit status.
But what if the parent doesn’t check the child’s exit status (via wait() )? The zombie process cannot be killed with kill -9. Zombie aren’t
processes, therefore they can’t response to the kill signal. The way to kill a zombie is to kill its parent. In computers, parricide = infanticide. If
the parent terminates with zombie connected to it, the zombie children die too.
A zombie process is more properly, but less popularly called a defunct process.
Development Process
Code Changes – Big/Little A big-change is a change to a function or object that breaks existing user code.
A little-change is a change to a function or object that does not break existing user code. The two principles of a little-change are:
Require no more. The change to the function or object should not impose new requirements on caller. For example an image file loader function
that originally only read Windows Bitmap files, but now reads JPEG and PNG files qualifies as a little change. If doing so requires the caller to
add a ‘file-type’ parameter, the change would be a big change as the call would need to be rewritten.
Promise no less. The change to the function or object should not remove a capability from or restrict the range of values it can operate on. For
example if during the preceding example the maximum image file size loadable decreased from 100MB to 99MB, the change would be a big-
change.
GOF – Gang of Four Gang-Of-Four, the four authors of Design Patterns: Elements of Reusable Object-Oriented Software [DP-95]. They are:
Erich Gamma
Richard Helm
Ralph Johnson
John Vlissides
They use the acronym GOF since listing all their names individually is tiresome.
Programming Concepts Section 24
©1991 – 2016 Garth Santor & Trinh Hān GATS Encyclopaedia 257 of 278
Reuse
Black-box Black-box reuse refers to the construction of new objects from existing objects by employing object composition. It is called black-box because
the internal details of the new object are not visible to the users of the object. The objects appear as “black boxes”.
Black-box First Part
Second Part
1
-fp
1
-sp
Object composition has the following benefits (as compared to inheritance):
Composition can occur at run-time (dynamic binding).
Encapsulation is respected – internal objects can be changed at any time without changing the host class’ interface.
Lower coupling – fewer implementation dependencies.
Classes tend to be smaller and better focused.
Composition vs. Inheritance Background: Putting Reuse Mechanisms to Work – Inheritance versus Composition [DP-95: pages 18-20]
In this section of the HTUGOFUTH’s book, they discuss the relative merits of both inheritance as a mechanism of object reuse as well as composition as a
mechanism of object reuse. They also provide two principles of reusable object-oriented design:
1. Program to an interface, not an implementation.
2. Favour object composition over class inheritance.
I would caution the designer to first examine their beliefs about object-oriented design, by choosing the statement that best reflects their beliefs:
Object-oriented design is a methodology whose purpose is to facilitate code reuse.
or…
Object-oriented design is a methodology whose purpose is to help a programmer model the problem domain more directly.
It is unfortunate that object-oriented design is so good at producing reusable code, since many (perhaps most) believe that is its purpose. Code
reuse is just a benevolent side-effect of good object-oriented design.
Programming Concepts Section 24
©1991 – 2016 Garth Santor & Trinh Hān GATS Encyclopaedia 258 of 278
When choosing between composition and inheritance, the first question that should be asked is, “What better models the real object in the problem
domain – composition or inheritance?” If the real objects in the problem domain have a has-a relationship, then object composition should be
preferred. (e.g. a car has a motor. a car object should contain a motor object.) If the real objects in the problem domain have an is-a
relationship, then inheritance should be preferred. (e.g. an apple is a fruit. an apple object should inherit from a fruit object.)
If the design truly represents the real world objects as they are in the problem domain, then reuse becomes natural and almost automatic. (e.g. if
your fruit abstraction truly and accurately models all that is common to all fruit, then every fruit type object can safely be derived from it.
Bananas, pineapples, oranges and tomatoes.)
The real debate between composition and inheritance usually arises when the objects in the problem domain can be viewed as having either a has-
a or an is-a relationship. Or possibly both! (e.g. XIconWindow vs. a GDIIconWindow. Both classes are Windows and specifically IconWindows
– the is-a relationship. Yet both also have an implementation – X or GDI. Which to choose? Try the Bridge Pattern [DP-95: page 151] which
helps you represent both relationships.
White-box White-box reuse refers to the construction of new objects from existing object by employing subclassing. It is called white-box because the
internal details of the new object are often visible to the users of the object.
White-box
Subclass
Object subclassing has the following benefits (as compared to object composition):
Subclassing occurs at compile time (static binding). More opportunities for compiler optimization.
Easier to modify the implementation.
Maintains object type. The new object can be used by any function that understands the base type.
Errors Error handling is a difficult task for which the programmer needs all the help that can be provided. – Bjarne Stroustrup [STRO1995]
There are two ways to write error-free programs; only the third one works. – Alan Perlis
It’s hard enough to find an error in your code when you’re looking for it; it’s even harder when you’ve assumed your code is error-free. –
Steve McConnell
Programming Concepts Section 24
©1991 – 2016 Garth Santor & Trinh Hān GATS Encyclopaedia 259 of 278
What is an error? The Merriam-Webster dictionary defines an error as “5: a deficiency or imperfection in structure or function” – a good general
definition but too vague to be a useful definition for programming.
The most useful definition of a program error that we have found was expressed by Herb Sutter in his column from the C/C++ User’s Journal.
(‘Sutter’s Mill: When and How to Use Exceptions’, CUJ August 2004)
Sutter starts by declaring that “a function is a unit of work and failures should be viewed as errors.” In other words “an error is any failure that
prevents a function from succeeding.”
In design-by-contract programming, we document the preconditions, postconditions and invariants which specify the conditions under which
successful execution should occur. Therefore we have three types of errors:
Precondition errors: any condition that prevents a function from satisfying its precondition is an error.
Postcondition errors: any condition that prevents a function from satisfying any postcondition is an error. Failing to produce a valid return value
is a postcondition error.
Invariant errors: any condition that prevents the function from re-establishing an invariant that the function (or method) is responsible for
maintaining is an error.
Definition
A program error is any failure that prevents a function from succeeding. Function success is defined by the program satisfying all of the
preconditions, postconditions and invariants specified for that function.
Types of Errors
Syntax Errors
Syntax errors are errors in source code that prevent the code from being compiled or interpreted. Syntax errors are not considered to be critical
errors as they manifest during development. I would suggest that compiling on the compiler’s highest warning level is recommended as it will
identify questionable code (which doesn’t always do what we intend.)
Logic Errors
Logic errors are errors that should never occur. An example of a logic error is passing a negative number to a square-root function. The logic of
the program should prevent this circumstance from ever occurring. Logic errors are typically caught by assertions.
Run-time Errors
Run-time errors are errors that occur during the execution of a program whose timing is unpredictable or caused by factors external to the
program. An example of a run-time error is running out of memory, failing to open a file (because it doesn’t exist) or bad input.
Design Principles
When coding, programmers should endeavour to code in such a way as to implement as many of the following principles:
1. Not-my-problem principle. Satisfying preconditions are not the responsibility of the called function. These are program logic errors and
should not occur during run-time. Treat these errors as bugs that are to be eliminated during development. Hence, not my problem!
Programming Concepts Section 24
©1991 – 2016 Garth Santor & Trinh Hān GATS Encyclopaedia 260 of 278
2. Sanity principle. Always maintain invariants! If an error occurs, the invariant state should continue to be satisfied. The object’s or system’s
sanity is maintained.
3. Atomic principle. Treat functions as atomic operations. The function should either fully complete (i.e. satisfy all conditions/contracts) or fully
fail (i.e. satisfy no postcondition, but maintain the invariants). This principle necessarily requires a rollback approach to design. If the function
fails half way, rollback to the state that existed at the beginning of the function.
4. No-fail/No-throw principle. The ideal function will never fail. This is impossible to enforce for most functions, but some functions require a
no-fail/throw guarantee. Destructors and deallocation functions must never fail. Standard swap functions don’t require this but can easily be
implemented as a no-fail/no-throw function.
The not-my-problem principle can always be implemented. Preconditions are by definition testable and therefore can be implemented as an
assertion.
The sanity principle is the most basic run-time principles to maintain and is required for the succeeding principles to be enforced.
The atomic principle is usually easy to implement on small functions, but can be difficult to implement on larger functions. In some situations we
may be compelled to dismiss this principle for reasons of performance or memory use.
Error handling technologies
Once an error has been detected we have several options as to how we may respond to the error. They are:
1. Terminate (with or without report).
2. Return an error code.
3. Return a legal value and leave the program in an error state.
4. Call a function specifically designed to handle the error.
5. Throw an exception.
Terminate
This doesn’t really handle the error; so much as it informs you why the program is terminating. This is a suitable response for the not-my-problem
principle. Or errors so severe that recovering would be impractical.
This can be thought of as a ‘run-time’ assertion.
Return an Error Code
Returning an error code from a function (as either the return value or an output parameter) is a traditional approach to error handling that can be
found in many libraries such as the C-Runtime Library.
The positive:
Easy to code a thread-safe implementation.
The negative:
Single level of granularity. Each and every function must be tested individually.
Programming Concepts Section 24
©1991 – 2016 Garth Santor & Trinh Hān GATS Encyclopaedia 261 of 278
Error detection code can impose substantial overhead. Some estimates suggest that error handling code can triple the size of the code since
every function must be tested individually.
Errors don’t automatically propagate down the call stack. If the error needs to be detected at a higher level then the error code must be explicitly
returned to each caller until the appropriate level has been reached.
This approach is deprecated by most modern languages.
Return a Legal Value and Leave the Program in an Error State
This approach uses a global error state variable to hold the error code from the last failing function. This traditional approach to error handling is
also found in many libraries including the C-Runtime Library.
The negative:
Easy to ignore errors.
Errors don’t automatically propagate down the call stack.
Making the library thread-safe requires that the global error variable be instantiated for each thread that accesses the library.
The positive:
Error detection granularity is user defined. The programmer can test after each call or after each block of code.
Call a Function Specifically Designed to Handle the Error
While this is one of the most powerful approaches to error handling it is one of the least used. An example of the this approach is the
Tset_new_handlerT from the C++ Standard Library which allows the programmer to provide a function to be called whenever the TnewT operator
cannot allocated the requested block of memory.
The negative:
Very difficult to implement. The programmer must devise a reasonable response that can be invoked without knowledge of the caller context.
Propagating the error down the call stack is not handled by this approach. One of the other techniques must be applied.
The error handling context is largely divorced from the calling context.
The positive:
Lowest runtime overhead. If the handler is capable of resolving the problem the calling code need take no special action to deal with the error.
Once a handler is hooked, all errors are responded to by the system. Errors cannot be ignored!
Throw an Exception
Most modern languages offer structured exception handling as an error handling mechanism. Many languages prefer this approach: Java, .NET
and Standard C++.
The negative:
Not well understood by the programming community.
Programming Concepts Section 24
©1991 – 2016 Garth Santor & Trinh Hān GATS Encyclopaedia 262 of 278
The positive:
Minimal overhead to the normal execution path.
Automatically propagates down the call stack.
Thread safe
Cannot be ignored.
Error detection granularity is determined by the programmer.
Bug A defect or fault in a machine, design, plan or most commonly software.
Most people believe that the term originates with the discovery by Grace Murray Hopper of a moth that had short-circuited the Harvard computer
in the middle of the 20P
thP century, but the term is actually quite a bit older. The Oxford English Dictionary documents a letter written in 1889 by
Pall Mall Gaz. He writes:
“Mr. Edison, I was informed, had been up the two previous nights discovering ‘a bug’ in his phonograph – an expression for solving a difficulty,
and implying that some imaginary insect has secreted itself inside and is causing all the trouble.”
Exception Handling Prefer to use exceptions to report errors. – Herb Sutter & Andrei Alexandrescu [CCS-05]
An exception is an event that occurs during the execution of program, and requires the execution of code outside the normal flow of control
[MSDN2004]. Exception handling is the technologies provided by programming languages and operation systems to create, detect and respond to
these events.
Exception events can be generated by either hardware or by software. Hardware exceptions are typically generated by the CPU and are triggered
by attempts to divide by zero, or access invalid memory. Software exceptions are generated by application code or the operating system. End-of-
file and container range errors are typical software exceptions.
Examples of exception handling systems include:
C++ exceptions.
Windows structured exception handling.
Java exceptions.
.NET exceptions.
Benefits of exception handling There are many benefits to using exception handling as your primary means of responding to run-time errors.
Programming Concepts Section 24
©1991 – 2016 Garth Santor & Trinh Hān GATS Encyclopaedia 263 of 278
Exceptions cannot be ignored.
Uncaught exceptions are usually reported by the host operating system and cause the termination of the program. Some languages will not
compile the source code until all the exceptions that could occur in a given scope have a catch written for them.
No values are lost to error codes.
In the return an error code approach to reporting an error the program would have to choose a value that will be treated as an error, even if the
code chosen is a value from the output domain. Exceptions remove the need to make such a choice as exceptions provide a completely separate
mechanism for returning from a failed routine.
Exceptions reduce code bloat.
Error handlers (try / catch blocks) can be applied to blocks of code safely. The first offending function will terminate the block of code, transfer
control to the appropriate catch block.
The usual error handling case is to rollback processing to the beginning of a function if a error occurs. Traditional error handling techniques
require that each function be tested and error handling invoked by either a jump or a call to a common error handling function (which removes the
error handling code from the context of the error!) A single try / catch can wrap the entire function. See HTUtransactional programming styleUTH.
Exceptions are extensible without breaking old code.
Classes can be thrown instead of primitive data types. Exception classes can provide a name that clearly identifies the error condition (e.g.
std::bad_alloc), and can be localized within the scope of the classes issuing the exception or a namespace.
Exception classes for new error conditions can be derived from existing exception classes. Catch blocks parameterized by the base exception type
are capable of catching exception classes derived from the existing base class. Specialized catch blocks can then be added at a later time.
Software Design Issues Structured exception handling is often applied to situations for which it has not been designed nor is well suited.
Exceptions are a good choice for error handling in the following general situations:
Code containing an error condition that must not be ignored.
Code that follows the transactional programming style.
Situations where exceptions should not be used include:
Asynchronous events such as network signals, hardware interrupt handling, etc.
Alternative to standard flow-control statements. Loops can be terminated by throwing an exception inside the loop and catching it outside of
the loop. This is inefficient programming since the overhead of handling an exception is costly compared to the well-understood and well-
optimized control statements such as for, loop, while and switch.
Code where the performance of the error handling code is critical.
Programming Concepts Section 24
©1991 – 2016 Garth Santor & Trinh Hān GATS Encyclopaedia 264 of 278
Exception Safety
We can minimize the confusion that inexperienced programmers may suffer from when using exceptions by declaring one of three guarantees for
any function in a system that uses exception handling. [BOOST]
1. The basic guarantee: Class invariants are preserved and no resources are leaked if an exception is thrown.
2. The strong guarantee: The function has either completed successfully, or thrown an exception and the program is in the same state as when
the function was called. This is the same guarantee as the HTUtransactional program styleUTH.
3. The no-throw guarantee: The operation will not throw anything.
Why do so many people dislike exceptions? Many people consider exception harmful and lump them with gotos on the heap of bad programming practices. Some of the detractors’ arguments
are:
1. Exception handling implements a goto-like jump from one part of the code to another, but does so invisibly. It is difficult (or impossible)
to see which exceptions might be thrown without examining every function in the call chain. Even then the operating system may issue the
exception.
2. Exception handling creates invisible exit points in your functions. Any call that could throw an exception becomes a possible exit point to
your function. You would have to wrap every function call with a try / catch to regain control over your function’s exit point.
3. “Templates and exceptions were not designed to work together.” In fact it is impossible to write an exception safe generic container.
4. Exception handling code generates too much overhead and slows down my code.
Analysis
1. Every control statement implements an invisible goto-like jump from one part of the code to another. That was the whole point of structured
programming.
2. I believe that the concern expressed here is the cleanup of temporary or local variables and resources. A thrown exception has the potential to
terminate the execution of your function at any point during its execution. Objects with destructors will clean themselves up safely, our problem
is with the objects and variables that don’t. The use of auto_ptr-like class that automatically deallocate any owned resource can be employed
to solve this problem for data types that don’t have destructors.
3. This myth seems to have started after the publication of Tom Cargill’s article: “Exception Handling: A False Sense of Security,” C++ Report,
Nov-Dec 1994 where he points out many issues that arise when creating a container that throws exceptions. Cargill finishes the article by saying
that, “I am not confident that I can produce an exception-correct version.” Many took this article as proof that it could not be done – a classic
fallacy of logic! If fact, it can, as STL has demonstrated. We must understand that there is no specific template – exception issue. All templates
resolve to a concrete class when compiled, and it is that class that interacts with the exception system.
4. Good C++ compilers generate code that will not waste a single clock cycle if the exception is not thrown. These compilers also generate throw-
catch code that executes at a speed comparable to calling a function. [Stroustrup-94] Therefore, programs with exception handling are at least
as fast as code that ignores errors.
Programming Concepts Section 24
©1991 – 2016 Garth Santor & Trinh Hān GATS Encyclopaedia 265 of 278
Generic Programming
Generic Programming Techniques (Garth Santor, December 2006)
“Generic programming is about generalizing software components so that they can be easily reused in a wide variety of situations.” [BOOST]
Generic programming seeks to remove all non-essential details from code leaving only the essential elements of the algorithm, data type or
architecture.
Concept – Model A [generic] concept is a set of requirements consisting of valid expressions, associated types, invariants, and complexity guarantees. A type that
satisfies the set of requirements is said to model the concept. [BOOST] A refinement is a concept that extends the requirements of another
concept.
1. Valid expressions are language specific expressions that must compile successfully for the objects involved to be considered models of
the concept.
Example: an object modeling a forward iterator must successfully compile ++iter.
2. Associated types are types related to the modeling type in that they participate in one or more of the valid expressions.
Example: std::vector<T> has the associated types, std::vector<T>::iterator, std::vector<T>::value_type, etc.
3. Invariants are run-time characteristics of the objects that must always be true, that is, the functions involving the objects must preserve
these characteristics.
Example: std::vector<T>::iterator::operator*(), the dereferencing operator requires that the vector begin iterated not
reallocate. The iterator provided by std::vector<T>::begin() may not be valid after a call to
std::vector<T>::push_back(), std::vector<T>::insert() or std::vector<T>::operator=().
4. Complexity guarantees are maximum limits on how long the execution of one the valid expressions will take, or how much of various
resources it computation will use.
Example: std::vector<T>::insert() works in linear time.
Traits The traits class concept was created by Nathan C. Myers to solve the problem of an ever growing number of template parameters in C++’s
generics. Many of these extra parameters – both types and operations – could be naturally inferred by the generic’s base parameter’s type. Myers
technique collects these naturally inferable types and operations into a class templated on that base parameter type. This class he calls a traits
class.
Programming Concepts Section 24
©1991 – 2016 Garth Santor & Trinh Hān GATS Encyclopaedia 266 of 278
Policies Policy classes are similar to traits classes in that they provide an alternative method of extending the behaviour of generic software components.
The difference with traits classes is that they are generally orthogonal to the primary parameters of the generic.
Example: the choice of a pool allocator as opposed to a standard allocator for a std::vector<T> is a choice completely independent of the
vector being a container of integers or a container of strings.
Traits Classes (Garth Santor, December 2006)
Traits classes are generic classes that provide information or behaviours that can be naturally inferred from a class’ base parameter type.
The concept was created by Nathan C. Myers to solve the problem of an ever growing number of template parameters in C++’s generics. Having
noted that many of these types and values could be naturally inferred from another parameter, Myers collected these types and values into a
companion class of traits, or traits class.
Example The naïve template:
template <typename T> T sum( T const* beg, T const* end ) {
T s = T(0);
while( beg != end ) {
s += *beg;
++beg;
}
return s;
}
Works well if the parameterized type is an int, float or double. However, it performs poorly if T is a char or string. ‘unsigned
char’ will soon overflow as its range is 0 to 255. For type string, the += operator will be interpreted as catenation-assignment, but what does
T(0) mean to a string?
These problems can be solved by introducing a traits class that clarify the zero value and the data type of the sum.
template <typename T> class sum_traits {
public:
typedef T sum_type;
static T zero_value() { return T(0); }
};
template <typename T> typename sum_traits<T>::sum_type sum( T const* beg, T const* end ) {
typename sum_traits<T>::sum_type s = sum_traits<T>::zero_value();
while( beg != end ) {
s += *beg;
Programming Concepts Section 24
©1991 – 2016 Garth Santor & Trinh Hān GATS Encyclopaedia 267 of 278
++beg;
}
return s;
}
The special cases of chars and strings can be handled by specializing the sum_traits class.
template <> class sum_traits<unsigned char> {
public:
typedef unsigned int sum_type;
static sum_type zero_value() { return 0; }
};
template <> class sum_traits<std::string> {
public:
typedef std::string sum_type;
static sum_type zero_value() { return std::string(""); }
};
The assignment addition operator could also be made customizable by placing a sum method into the traits class.
References: [VJ03] (Chapter 15).
Promotion Traits [In progress]
Object-Oriented Programming
Class Invariants
A class invariant is a test or condition that must always evaluate to true for all values of that class in a visible state. (i.e. Tstring::size() ≥
0T is a class invariant for Tstd::stringT.) Class invariants may be compound conditions.
Contract Classes Contract classes are classes that are used to test or enforce a contract without burdening the actual runtime class with all the overhead of the
debug-build assertions and code.
Example: vector::insert()
void vector::insert( iterator where, size_type count, const Type& value ) {
#ifdef CHECK_CONTRACTS
int newSize = size() + count;
#endif
_Insert_n( where, count, value );
assert( size() == newSize );
Programming Concepts Section 24
©1991 – 2016 Garth Santor & Trinh Hān GATS Encyclopaedia 268 of 278
}
It is obvious that as the complexity of tests increase the amount of test code within the method could skyrocket! And it is hard enough to read and
debug code without confusing the work code with the test code.
Contract classes are a technique that will allow you to separate the test code from the work code, placing the test code into a separate class.
Example: std::vector<T>
template <typename T>
class vector_contract : public T {
public:
vector_contract( typename T::size_type n ) : T(n) {
assert( size() == n );
}
void resize( typename T::size_type n ) {
T old( *this );
T::resize( n );
bool same = true;
T::size_type nElements = std::min( old.size(), size() );
for( int i = 0; i != nElements; ++i )
same &= old[i] == (*this)[i];
assert( same );
}
};
void main() {
vector_contract< vector<int> > v(10);
for( int i = 0; i != v.size(); ++i )
v[i] = i;
v.resize( 20 );
}
Functor Classes A functor is an object that can be invoked in the manner of a function.
Functors can be are used to implement safer function callback mechanisms. The features and advantages provided by functors are:
1. Functors behave like functions.
2. Functors are proper objects.
a. Functors can carry state.
b. Functors can have unique instances.
c. Functors can be managed using standard object-oriented approaches (they are objects).
3. Consistent with object-oriented coding and design practices.
Programming Concepts Section 24
©1991 – 2016 Garth Santor & Trinh Hān GATS Encyclopaedia 269 of 278
4. Functors integrate well with generic programming (C++ templates).
5. Functors tend to have a far less cryptic syntax then function pointers or pointer to member functions.
6. Functors easily implement the strategy pattern.
Terminator Class A terminator class is a class that has no subclasses (classes derived from them). Most objects are instances of terminator classes.
Zombie Object A zombie object is an object that has died (it is irreversibly incapable of executing) but still exists in memory and is still referenced.
When an object zombies programmers have traditionally set a flag to indicate the zombied state. This would require the caller to check the
object’s status before or after each call. A preferable alternative is to have the zombie throw an exception indicating its demise and allowing the
calling function to kill or avoid the zombie.
Testing & Reliability “An effective way to test code is to exercise it at its natural boundaries”
– Brian Kernighan.
Testing methodologies can be examined from several perspectives:
The scope of a test.
The intrusiveness of a test.
The focus of a test.
The scope of a test refers to amount of the system or code that is being tested. Unit testing, integration testing, and system testing all refer to test
of differing scope.
The intrusiveness of a test refers to whether or not the test examines the internals of the unit being tested or whether the module is considered to be
impenetrable. Black-box testing or white-box testing indicates the intrusiveness of a test.
The focus of a test refers to aspect of the module being tested. Functional testing, load testing, performance testing, stress testing, security testing
and usability testing each examine a different characteristic of the software.
These terms are often mixed to indicate the overall test. For example, we may a black-box functional unit test or a system performance test.
The one oddball is regression testing which may refer to any of the previous tests. Regression testing is the reapplication of a test after a
refactoring of the code. The purpose of the test is to ensure that no new errors have been introduced into as a result of refactoring the code.
Regression testing is usually performed on functional tests.
Programming Concepts Section 24
©1991 – 2016 Garth Santor & Trinh Hān GATS Encyclopaedia 270 of 278
Unit Testing
Unit testing validates the post-condition of every function or object method in a module of source code (only non-trivial functions or methods need
be tested.)
The benefit of a unit test is to gain assurances that an individual part of a system is working properly. This knowledge would allow a programmer
to focus their efforts on integration or system testing.
The presence of a unit test assists in refactoring as a programmer can quickly determine whether the new, refactored code also satisfies the post-
conditions of the module.
Ideally, unit tests will be automated and used during regression testing.
Integration Testing
Integration testing tests groups of related modules to validate higher-order functionality. It is also called string testing since modules are “strung”
together to perform these tests.
Integration testing is typically performed after unit testing and before system testing.
System Testing
System testing tests the complete system.
System tests validate Use-Case scenarios in a Unified Process project.
Load Testing
Load testing focuses on a system’s or module’s ability to operate under expected usage. Typically we seek to validate correct behaviour is
maintained as memory allocation increases or the number of users of the system increases.
Load testing is often associated with performance testing.
Load testing is differentiated from stress testing in that load testing tests the system under expected usage whereas stress testing tests the system
under extreme usage.
Performance Testing
Performance testing attempts to measure the time or space utilization of a module, system or sub-system.
Performance testing is often performed in conjunction with load testing.
Stress Testing
Stress testing determines the stability of a module or system under extreme conditions (beyond normal).
Stress testing often includes testing the system under low-memory conditions, a high number of users or a high number of open files or handles.
Usability Testing
Usability testing does not test for correctness, but for ease of use.
Programming Concepts Section 24
©1991 – 2016 Garth Santor & Trinh Hān GATS Encyclopaedia 271 of 278
Ease of use can be measured via the metrics:
Time on Task – how long does it take a user to complete the given task?
Accuracy – how often does the user succeed in completing the given task?
Recall – how often does the user forget how to complete the given task?
Emotional Response – how positive does the user feel after completing the give task? (Assured? Confident? Stressed? Angry?)
Test Doubles Test doubles are function or object implementations used in the development or testing of code. Test doubles are typically used during unit testing
although they can also be useful during the early stages of integration testing. They allow for the testing of the unit or system to begin without a
complete implementation.
Test doubles range from trivial implementations that minimally satisfy the call (the function returned) to complex functions that implement a large
amount of the functionality.
The types of test doubles can be categorized by the following five definitions:
1. Dummy
2. Stub
3. Spy
4. Fake
5. Mock
Dummy
Dummies have no implementation – neither method bodies nor state data. They are interfaces. During testing they are used when as procedural
parameters.
Stub
Stubs are minimal implementations or interfaces or base classes. Methods and functions return hard-coded values.
Spy
Spies are stubs that log which members were invoked.
Fake
A fake is a partial implementation. Typically it handles interactions between members of the types it is inheriting.
Programming Concepts Section 24
©1991 – 2016 Garth Santor & Trinh Hān GATS Encyclopaedia 272 of 278
Mock
A mock is a dynamically create implementation, usually created from a mock library. Mocks are configurable to provide the correct data types
and values. They can be used in place of dummies, stubs, spies and fakes, although fakes are more difficult to simulate.
Testing Styles
Code Inspection
Reading the code…
Some studies have shown that have two people read the code triples the rate of finding errors as compared to one person reading the code.
Desk Check
The ‘desk check’ is an almost defunct approach to software testing in which the tester reads through the source code imagining the program state
and mentally tracing the program’s control flow. This approach was more popular in the 1960’s and 1970’s before full-screen editors and
interactive source-level debuggers.
Dry Run
An intense form of desk check in which the tester records the state of each variable as she proceeds through the code. This is only practical for
small routines or code segments. This approach was more recently been super ceded by visual debugger walkthroughs.
Walkthrough (w/visual debugger)
Using a visual debugging tool, stepping through a program line-by-line.
White-Box/Black Box Testing
White-box testing permits the examination of the source code, black-box testing does not.
Transactional Programming Style Transactional programming style emphasizes the principle that a function should either do everything or nothing. Transactional programming
supports the HTUatomic principle of programming.
Example – non-atomic.
TvoidT double_size( TintT*& p, TintT size ) {
TdeleteT [] p;
p = TnewT TintT [size * 2];
}
What happens if TnewT throws a memory allocation exception? p is left pointing to a block of memory we no-longer own.
TvoidT atomic_double_size( TintT*& p, TintT size ) {
TintT* pResized = TnewT TintT[ size * 2 ];
TdeleteT [] p;
p = pResized;
Programming Concepts Section 24
©1991 – 2016 Garth Santor & Trinh Hān GATS Encyclopaedia 273 of 278
}
Now, if new throws the original array is left untouched.
Sometimes more work is required to enforce the atomic principle.
Example:
Object* g_pGood = 0;
…
void foo() {
TdeleteT g_pGood;
g_pGood = new Object;
g_pGood->init(); T// could throwT
}
This is the atomic version:
Object* g_pGood = 0;
…
void atomic_foo() {
Object* p = new Object;
try {
p->init(); T// could throwT
TdeleteT g_pGood;
g_pGood = p;
}
catch( exception& e ) {
delete p;
}
}
The global object Tg_pGoodT will only be initialized if the entire allocation and initialization process succeeds. If an exception is thrown at any point
during the function, the program state is effectively rolled-back to the program state when function ‘TfT’ was called.
The use of smart pointers can simplify coding in a transactional style.
boost::scoped_ptr<Object> g_pGood;
…
void simple_atomic_foo() {
boost::scoped_ptr<Object> p( new Object );
p->init();
g_pGood.reset( p );
}
The Rules
To make a function atomic:
1. Create all of the new resources before you destroy the old resources being replaced.
Programming Concepts Section 24
©1991 – 2016 Garth Santor & Trinh Hān GATS Encyclopaedia 274 of 278
2. Use smart_ptr or objects with destructors to automatically clean up when an exception is thrown.
3. See HTUexception handling.
Issues
The preceding rules don’t handle the problem of rolling-back a set of functions.
void host() {
foo();
bar();
}
What if foo() completes successfully but bar() doesn’t? How do you rollback foo()?
Several methods have been devised to deal with this problem, but all incur overhead. The most common are modeled on database transactions,
such as those found in Transact-SQL.
Invariants
Loop Invariant
A loop invariant is a condition that does not vary during the execution of a loop.
Example:
TforT( TintT i = 0; i != n; ++i )
a[i] = i;
In this trivial example, the invariant is ‘i < n’. We can explicitly test for this using an assertion.
TforT( TintT i = 0; i != n; ++i ) {
a[i] = i;
assert( i < n );
}
Class Invariant
A class invariant is a condition that does not vary during the life of an object. Class invariants should test positively at:
at the end of object construction
at the start of object destruction
at the start and end of any method
Example:
A referencing-counting smart pointer may have a class invariant with the following condition:
p = nil or (p ≠ nil and count{p} > 0)
Example:
Programming Concepts Section 24
©1991 – 2016 Garth Santor & Trinh Hān GATS Encyclopaedia 275 of 278
bool invariant( char* file, char* func, int line ) {
//… test and report
}
#ifndef NDEBUG
#define TEST_INVARTIANT() invariant( __FILE__, __FUNCTION__, __LINE )
#else
#define TEST_INVARTIANT()
#endif
Role in testing
The role of invariants in testing is sanity checking (i.e. enforcing the HTUSanity Principle).
References Section 25
©1991 – 2016 Garth Santor & Trinh Hān GATS Encyclopaedia 276 of 278
Appendices
Acronyms AABB Math/Graphics Axis-Aligned Bounding Box
OBB Math/Graphics Oriented Bounding Box
POD C++ Jargon Plain-Old-Data. Non-pointer primitives or structures / classes made up of non-pointer
primitives. Essentially – a variable that can be safely copied with a binary copy.
References [AIS77] Christopher Alexander, Sara Ishikawa, Murray Silverstein, Max Jacobson, Ingrid Fiksdahl-King, and Shlomo Angel.
A Pattern Language: Towns/Buildings/Construction. Oxford University Press, 1977.
[BOOST] BOOST Documentation www.boost.org
[CUJ] C/C++ User’s Journal
[DP95] Erich Gamma, Richard Helm, Ralph Johnson and John Vlissides. Design Patterns: Elements of Reusable Object-
Oriented Software. Addison-Wesley, 1995
[IA90] Corman, Thomas H., Leiserson, Charles E., & Rivest, Ronald L. (1990) Introduction to algorithms (1st ed.) The MIT
Press [0-262-03141-8]
[K06] Karlsson, Björn (2006) Beyond the C++ standard library: an introduction to Boost. Reading MA: Addison Wesley
[0-321-13354-4]
[MSDN2004] Microsoft Developer’s Network Library 2004.
[SA04] Sutter, Herb & Alexandrescu, Andrei (2004) C++ Coding Standards
[STRO1995] Stroustrup, Bjarne (1995) The design and evolution of C++. Reading, MA: Addison Wesley.
[STRO2000] Stroustrup, Bjarne (2000) The C++ programming language. Reading, MA: Addison Wesley.
[VJ03] David Vandevoorde & Nicolai M. Josuttis (2003) C++ Templates: The Complete Guide Addison Wesley
[0-201-73484-2]
References Section 26
©1991 – 2016 Garth Santor & Trinh Hān GATS Encyclopaedia 277 of 278
Index
A* algorithm, 225
algorithm, 13, 14, 15, 16, 17, 21, 22, 24, 25, 26, 27, 28, 32, 36,
37, 38, 40, 65, 66, 87, 88, 134, 152, 192, 222, 225, 226, 227,
228, 258, 269
asymptotic analysis, 13, 15
atomic principle, 253, 265
audio, 43, 44, 45, 46, 47, 126
backface culling. See culling: backface
BeginScene(), 136, 145, 149, 151, 170, 177
big-oh, 13, 14
Binet, Jacque Philippe Marie, 193
binomial coefficient, 195
bit block transfer, 129, 136
blit, 129
breadth-first search, 226
bridge pattern, 83, 86, 110
camera, 129, 131, 132, 133, 187
Camera, 129
collision detection, 245
combination. See binomial coefficient
combinatorial number. See binomial coefficient
culling, 132, 133, 181
backface, 132
D3DPOOL_SYSTEMMEM, 136, 140
D3DPRESENTFLAG_LOCKABLE_BACKBUFFER, 150,
151
DCLP, 111
de Lagny, Thomas Fantet, 193
depth-first search, 227, 228
design pattern, 111
bridge pattern, 110
bridge pattern, 83, 86
bridge pattern, 110
bridge pattern, 110
observer pattern, 111
Dialog Box, 165
Direct3D
memory pool, 136, 140
dodecahedron, 208, 216
DXUTCreateDevice(), 151, 162
Euclid’s Algorithm. See Highest Common Factor
factorial, 192
Factorial, 192
Fibonacci numbers, 87, 192, 193, 194
file formats
raw, 47, 53, 91
x-file, 155
fog, 139, 187
function
permutation, 196
functions
binomial coefficient, 195
factorial, 192
Fibonacci numbers, 87, 192, 193, 194
inner product, 133, 204
gang of four, 249, 250
golden ratio, 193, 194, 216, 218
Greatest Common Divisor.. See Highest Common Factor
GUI Controls, 165
height maps, 184, 185
hexahedron, 208
Hoare, Anthony, 37, 39
icosahedron, 208, 218, 219
IDirect3DSurface9, 136, 140, 151
inner product, 133, 204
invariants, 252, 253, 257, 260, 267, 268
Invariants, 50, 63, 64, 252, 253, 257, 258, 260, 267, 268
lighting, 141, 143, 147, 148, 151, 152, 186
References Section 27
©1991 – 2016 Garth Santor & Trinh Hān GATS Encyclopaedia 278 of 278
ambient, 151, 152
directional, 140, 152, 186
point, 140, 142, 152
spot, 140, 143, 152
matrix, 129
Matrix, 129, 202
memory pool, 136, 140
Direct3D, 136, 140
numbers
natural, 14, 16, 17, 106, 194
observer pattern, 111
octahedron, 208
path finding
A*, 225
breadth-first, 226
depth-first, 227, 228
pattern
DCLP, 111
Permutation, 24, 37, 196
permutations, 192, 196
polyhedron, 135, 207, 208
RAM model of computation, 13, 15
sanity principle, 253, 268
searching
A*, 225
breadth-first, 226
depth-first, 227, 228
skybox, 187
sphere, 207, 208, 211, 213, 215, 218, 220, 245
sprite, 134, 150, 180
sprites, 134, 150, 180
surface, 133, 135, 136, 139, 140, 148, 151, 152, 180, 185, 186,
187
surface normal, 133, 135, 139, 148, 186
surfaces, 133, 186, 189
templates, 52, 55, 58, 62, 63, 70, 73, 81, 86, 88, 94, 96, 97,
155, 156, 257, 258, 259, 260, 261
tetrahedron, 208, 211
Texture, 150
transactional programming, 256, 265
transforms, 122, 129, 130, 131, 132, 134, 148, 150, 180, 183,
187, 197, 198, 199, 201, 202
turtle graphics, 187, 188
vector
surface normal, 133, 135, 139, 148, 186
vector, geometric
inner product, 133, 204
vertex, 133, 135, 136, 138, 139, 141, 143, 145, 146, 147, 148,
149, 156, 157, 158, 180, 182, 184, 185, 188, 201, 206, 207,
208, 211, 213, 215, 216, 218, 220, 221, 225, 226, 227, 228
winding, 133, 135
view, 129, 131, 132, 139, 148, 150, 187, 201
View, 129