Remove heading ids, let pandoc generate them

This commit is contained in:
James Gregory 2014-01-06 22:51:26 +11:00
commit 8b63f1f1a5
75 changed files with 631 additions and 631 deletions

View file

@ -8,7 +8,7 @@ category: 'Web and Software Development: Game Development,Web and Software Devel
Graphics and Multimedia Development'
---
# Foreword {#Heading1}
# Foreword
I got my start programming on Apple II computers at school, and almost
all of my early work was on the Apple platform. After graduating, it

View file

@ -8,7 +8,7 @@ category: 'Web and Software Development: Game Development,Web and Software Devel
Graphics and Multimedia Development'
---
# Acknowledgments {#Heading1}
# Acknowledgments
There are many people to thank—because this book was written over many
years, in many different settings, an unusually large number of people

View file

@ -8,7 +8,7 @@ category: 'Web and Software Development: Game Development,Web and Software Devel
Graphics and Multimedia Development'
---
# Afterword {#Heading1}
# Afterword
If you've followed me this far, you might agree that we've come through
some rough country. Still, I'm of the opinion that hard-won knowledge is

View file

@ -8,7 +8,7 @@ category: 'Web and Software Development: Game Development,Web and Software Devel
Graphics and Multimedia Development'
---
# Index {#Heading1}
# Index
`Numbers`

View file

@ -13,9 +13,9 @@ pages: 004-019
# Part I
## Chapter 1\
The Best Optimizer Is between Your Ears {#Heading1}
The Best Optimizer Is between Your Ears
### The Human Element of Code Optimization {#Heading2}
### The Human Element of Code Optimization
This book is devoted to a topic near and dear to my heart: writing
software that pushes PCs to the limit. Given run-of-the-mill software,
@ -51,7 +51,7 @@ this book, we're going to work some of those wonders, starting...
...now.
### Understanding High Performance {#Heading3}
### Understanding High Performance
Before we can create high-performance code, we must understand what high
performance is. The objective (not always attained) in creating
@ -93,7 +93,7 @@ touch, however.
"What's a fast slow program?" you ask. That's a good question, and a
brief (true) story is perhaps the best answer.
#### When Fast Isn't Fast {#Heading4}
#### When Fast Isn't Fast
In the early 1970s, as the first hand-held calculators were hitting the
market, I knew a fellow named Irwin. He was a good student, and was
@ -123,7 +123,7 @@ grand scheme of things—and they scarcely matter at all unless they're
used in the context of a good design and a thorough understanding of
both the task at hand and the PC.
### Rules for Building High-Performance Code {#Heading5}
### Rules for Building High-Performance Code
We've got the following rules for creating high-performance software:
@ -148,7 +148,7 @@ the real world. For my money, examining some actual working code is
always a good way to get a handle on programming concepts, so let's look
at some of the performance rules in action.
#### Know Where You're Going {#Heading6}
#### Know Where You're Going
If we're going to create high-performance code, first we have to know
what that code is going to do. As an example, let's write a program that
@ -161,7 +161,7 @@ with the checksum value other than print it out, however; right now
we're only interested in generating that checksum value as rapidly as
possible.
#### Make a Big Map {#Heading7}
#### Make a Big Map
How are we going to generate a checksum value for a specified file? The
logical approach is to get the file name, open the file, read the bytes
@ -169,7 +169,7 @@ out of the file, add them together, and print the result. Most of those
actions are straightforward; the only tricky part lies in reading the
bytes and adding them together.
#### Make Lots of Little Maps {#Heading8}
#### Make Lots of Little Maps
Actually, we're only going to make one little map, because we only have
one program section that requires much thought—the section that reads
@ -390,7 +390,7 @@ design, optimization just creates fast slow code.
Well, then, how are we going to improve our design? Before we can do
that, we have to understand what's wrong with the current design.
#### Know the Territory {#Heading9}
#### Know the Territory
Just why is Listing 1.1 so slow? In a word: overhead. The C library
implements the `read()` function by calling DOS to read the desired
@ -481,7 +481,7 @@ main(int argc, char *argv[]) {
}
```
#### Know When It Matters {#Heading10}
#### Know When It Matters
The last section contained a particularly interesting phrase: *the
time-critical portions of your code*. Time-critical portions of your
@ -514,7 +514,7 @@ Besides, we don't want to optimize until the design is refined to our
satisfaction, and that won't be the case until we've thought about other
approaches.
#### Always Consider the Alternatives {#Heading11}
#### Always Consider the Alternatives
Listing 1.4 is good, but let's see if there are other—perhaps less
obvious—ways to get the same results faster. Let's start by considering
@ -658,7 +658,7 @@ At any rate, Listing 1.5 isn't much more complicated than Listing
1.4—and it's a *lot* faster. Always consider the alternatives; a bit of
clever thinking and program redesign can go a long way.
#### Know How to Turn On the Juice {#Heading12}
#### Know How to Turn On the Juice
I have said time and again that optimization is pointless until the
design is settled. When that time comes, however, optimization can
@ -808,7 +808,7 @@ specific case.
All this is basically a way of saying: Know where you're going, know the
territory, and know when it matters.
### Where We've Been, What We've Seen {#Heading13}
### Where We've Been, What We've Seen
What have we learned? Don't let other people's code—even DOS—do the work
for you when speed matters, at least not without knowing what that code
@ -825,7 +825,7 @@ light of Table 1.1, does it? Your organic optimizer matters much more
than your compiler's optimizer, and there's always assembly for those
usually small sections of code where performance really matters.
#### Where We're Going {#Heading14}
#### Where We're Going
This chapter has presented a quick step-by-step overview of the design
process. I'm not claiming that this is the only way to create

View file

@ -11,9 +11,9 @@ pages: 021-030
---
## Chapter 2\
A World Apart {#Heading1}
A World Apart
### The Unique Nature of Assembly Language Optimization {#Heading2}
### The Unique Nature of Assembly Language Optimization
As I showed in the previous chapter, optimization is by no means always
a matter of "dropping into assembly." In fact, in performance tuning
@ -33,7 +33,7 @@ assembly specific dynamics.
As usual, the best way to wade in is to present a real-world example.
### Instructions: The Individual versus the Collective {#Heading3}
### Instructions: The Individual versus the Collective
Some time ago, I was asked to work over a critical assembly subroutine
in order to make it run as fast as possible. The task of the subroutine
@ -97,7 +97,7 @@ fastest...and more. You must also learn to look at your programming
problems from a variety of perspectives so that you can put those fast
instructions to work in the most effective ways.
### Assembly Is Fundamentally Different {#Heading4}
### Assembly Is Fundamentally Different
Is it really so hard as all that to write good assembly code for the PC?
Yes! Thanks to the decidedly quirky nature of the x86 family CPUs,
@ -115,7 +115,7 @@ implements a routine to search a list of 100,000 sorted items with a
linear rather than binary search will end up with a disappointingly slow
program.
#### Transformation Inefficiencies {#Heading5}
#### Transformation Inefficiencies
No matter how well an implementation is derived from the corresponding
design, however, high-level languages like C/C++ and Pascal inevitably
@ -166,7 +166,7 @@ specification to machine language entirely on his or her own. (The
assembler merely handles the *direct* translation from assembly to
machine language.)
#### Self-Reliance {#Heading6}
#### Self-Reliance
The first part of assembly language optimization, then, is self. An
assembler is nothing more than a tool to let you design machine-language
@ -181,7 +181,7 @@ High-level languages handle most of this transparently to the
programmer, but in assembly everything is fair—and necessary—game, which
brings us to another aspect of assembly optimization: knowledge.
#### Knowledge {#Heading7}
#### Knowledge
In the PC world, you can never have enough knowledge, and every item you
add to your store will make your programs better. Thorough familiarity
@ -214,7 +214,7 @@ out such knowledge.
> Be forewarned, though: No matter how much you learn about programming
> the PC in assembly, there's always more to discover.
### The Flexible Mind {#Heading8}
### The Flexible Mind
Is the never-ending collection of information all there is to the
assembly optimization, then? Hardly. Knowledge is simply a necessary
@ -316,7 +316,7 @@ the context of a solid overall framework unique to each program, and the
flexible mind is the key to creating that framework and holding it
together.
#### Where to Begin? {#Heading9}
#### Where to Begin?
To summarize, the skill of assembly language optimization is a
combination of knowledge, perspective, and a way of thought that makes

View file

@ -11,9 +11,9 @@ pages: 031-073
---
## Chapter 3\
Assume Nothing {#Heading1}
Assume Nothing
### Understanding and Using the Zen Timer {#Heading2}
### Understanding and Using the Zen Timer
When you're pushing the envelope in writing optimized PC code, you're
likely to become more than a little compulsive about finding approaches
@ -40,7 +40,7 @@ with the optimized version of the routine....
It ran slower than the original version!
### The Costs of Ignorance {#Heading3}
### The Costs of Ignorance
As diligent as the author had been, he had nonetheless committed a
cardinal sin of x86 assembly language programming: He had assumed that
@ -94,7 +94,7 @@ video wait states as well, so the code they discussed was actually
have been to run the code to see if snow resulted, since the only true
measure of code performance is observing it in action.
### The Zen Timer {#Heading4}
### The Zen Timer
Clearly, one key to mastering Zen-class optimization is a tool with
which to measure code performance. The most accurate way to measure
@ -558,7 +558,7 @@ Code ends
end
```
#### The Zen Timer Is a Means, Not an End {#Heading5}
#### The Zen Timer Is a Means, Not an End
We're going to spend the rest of this chapter seeing what the Zen timer
can do, examining how it works, and learning how to use it. I'll be
@ -573,7 +573,7 @@ Consequently, you shouldn't worry if you don't fully grasp the inner
workings of the Zen timer. Instead, focus on learning how to *use* it,
and you'll be on the right road.
#### Starting the Zen Timer {#Heading6}
#### Starting the Zen Timer
`ZTimerOn` is called at the start of a segment of code to be timed.
`ZTimerOn` saves the context of the calling code, disables interrupts,
@ -596,7 +596,7 @@ any hardware interrupts to occur during the interval between any call to
`ZTimerOn` and the corresponding call to `ZTimerOff`, and should not
enable interrupts during that time.
### Time and the PC {#Heading7}
### Time and the PC
A second interesting point about `ZTimerOn` is that it may introduce
some small inaccuracy into the system clock time whenever it is called.
@ -742,7 +742,7 @@ Nonetheless, it's a good idea to reboot your computer at the end of each
session with the Zen timer in order to make sure that the system clock
is correct.
### Stopping the Zen Timer {#Heading8}
### Stopping the Zen Timer
At some point after `ZTimerOn` is called, `ZTimerOff` must always be
called to mark the end of the timing interval. `ZTimerOff` saves the
@ -774,7 +774,7 @@ this chapter, though, we'll see that timer 0 can be stopped after all.)
We simply tell the 8253 to latch the current count, and the 8253 does so
without breaking stride.
### Reporting Timing Results {#Heading9}
### Reporting Timing Results
`ZTimerReport` may be called to display timing results at any time
after both `ZTimerOn` and `ZTimerOff` have been called.
@ -829,7 +829,7 @@ You may well want to devise still other approaches better suited to your
needs than those I've presented. Go to it! I've just thrown out a few
possibilities to get you started.
### Notes on the Zen Timer {#Heading10}
### Notes on the Zen Timer
The Zen timer subroutines are designed to be near-called from assembly
language code running in the public segment `Code`. The Zen timer
@ -890,7 +890,7 @@ useful—quite the contrary. The Zen timer is an excellent tool for
evaluating code performance over the entire spectrum of PC-compatible
computers.
### A Sample Use of the Zen Timer {#Heading11}
### A Sample Use of the Zen Timer
Listing 3.2 shows a test-bed program for measuring code performance with
the Zen timer. This program sets DS equal to CS (for reasons we'll
@ -1114,7 +1114,7 @@ the test-bed program of Listing 3.2, simply insert calls to `ZTimerOn,
ZTimerOff`, and `ZTimerReport` in the appropriate places and link
PZTIMER to your program.
### The Long-Period Zen Timer {#Heading12}
### The Long-Period Zen Timer
With a few exceptions, the Zen timer presented above will serve us well
for the remainder of this book since we'll be focusing on relatively
@ -1171,7 +1171,7 @@ major inaccuracy into the system clock time during a single timing run
since it leaves interrupts enabled and therefore allows the system clock
to update normally.
#### Stopping the Clock {#Heading13}
#### Stopping the Clock
There's a potential problem with the long-period Zen timer. The problem
is this: In order to measure times longer than 54 ms, we must maintain
@ -1897,7 +1897,7 @@ Finally, please note that the *precision* Zen timer works perfectly well
on both PS/2 and non-PS/2 computers. The PS/2 and 8253 considerations
we've just discussed apply *only* to the longZen timer.
### Example Use of the Long-Period Zen Timer {#Heading14}
### Example Use of the Long-Period Zen Timer
The long-period Zen timer has exactly the same calling interface as the
precision Zen timer, and can be used in place of the precision Zen timer
@ -2113,7 +2113,7 @@ PC if you are using MASM, with most of that time spent assembling
Listing 3.8. Why? Because MASM is notoriously slow at assembling
`REPT` blocks, and the block in Listing 3.8 is repeated 20,000 times.
### Using the Zen Timer from C {#Heading15}
### Using the Zen Timer from C
The Zen timer can be used to measure code performance when programming
in C—but not right out of the box. As presented earlier, the timer is
@ -2169,7 +2169,7 @@ precision timer, but the long-period timer is very similar.
The full listings for the C-callable Zen timers are presented in Chapter
K on the companion CD-ROM.
#### Watch Out for Optimizing Assemblers! {#Heading16}
#### Watch Out for Optimizing Assemblers!
One important safety tip when modifying the Zen timer for use with large
code model C code: Watch out for optimizing assemblers! TASM actually
@ -2221,7 +2221,7 @@ I've tested the changes shown in Figures 3.2 and 3.3 with TASM and
Borland C++ 4.0, and also with the latest MASM and Microsoft C/C++
compiler.
#### Further Reading {#Heading17}
#### Further Reading
For those of you who wish to pursue the mechanics of code measurement
further, one good article about measuring code performance with the 8253
@ -2242,7 +2242,7 @@ how the Zen timer works. All you really need to know is what the Zen
timer can do and how to use it, and we've accomplished that in this
chapter.
#### Armed with the Zen Timer, Onward and Upward {#Heading18}
#### Armed with the Zen Timer, Onward and Upward
The Zen timer is not perfect. For one thing, the finest resolution to
which it can measure an interval is at best about 1µs, a period of time

View file

@ -11,9 +11,9 @@ pages: 075-109
---
## Chapter 4\
In the Lair of the Cycle-Eaters {#Heading1}
In the Lair of the Cycle-Eaters
### How the PC Hardware Devours Code Performance {#Heading2}
### How the PC Hardware Devours Code Performance
This chapter, adapted from my earlier book, *Zen of Assembly Language*
located on the companion CD-ROM, goes right to the heart of my
@ -47,7 +47,7 @@ changed over time, but do take the time to at least skim through this
chapter to give yourself a good start on the material in the rest of
this book.
### Cycle-Eaters {#Heading3}
### Cycle-Eaters
Programming has many levels, ranging from the familiar (high-level
languages, DOS calls, and the like) down to the esoteric things that lie
@ -81,7 +81,7 @@ properly improve the performance of our code.
Which brings us to cycle-eaters.
### The Nature of Cycle-Eaters {#Heading4}
### The Nature of Cycle-Eaters
Cycle-eaters are gremlins that live on the bus or in peripherals (and
sometimes within the CPU itself), slowing the performance of PC code so
@ -101,7 +101,7 @@ understand the simplest among them, those that haunted the original
the newer generation of cycle-eaters in terms of those ancestral
cycle-eaters—but we have to get the groundwork down first.
#### The 8088's Ancestral Cycle-Eaters {#Heading5}
#### The 8088's Ancestral Cycle-Eaters
Internally, the 8088 is a 16-bit processor, capable of running at full
speed at all times—unless external data is required. External data must
@ -131,7 +131,7 @@ but do read it all even if the going gets a bit tough. Cycle-eaters play
a key role in later chapters, so some familiarity with them is highly
desirable.
### The 8-Bit Bus Cycle-Eater {#Heading6}
### The 8-Bit Bus Cycle-Eater
*Look! Down on the motherboard! It's a 16-bit processor! It's an 8-bit
processor! It's...*
@ -194,7 +194,7 @@ a full 16-bit word at a time. The 386SX can process 32 bits (a
doubleword) at a time, however, and loses a lot of time fetching that
doubleword from memory in two halves.
#### The Impact of the 8-Bit Bus Cycle-Eater {#Heading7}
#### The Impact of the 8-Bit Bus Cycle-Eater
One obvious effect of the 8-bit bus cycle-eater is that word-sized
accesses to memory operands on the 8088 take 4 cycles longer than
@ -255,7 +255,7 @@ operands. More ominously, as we will see shortly, the 8-bit bus
cycle-eater can cause performance problems with other sorts of code as
well.
#### What to Do about the 8-Bit Bus Cycle-Eater? {#Heading8}
#### What to Do about the 8-Bit Bus Cycle-Eater?
The obvious implication of the 8-bit bus cycle-eater is that byte-sized
memory variables should be used whenever possible. After all, the 8088
@ -426,7 +426,7 @@ and there's one sort of word-sized memory access we haven't discussed
yet: instruction fetching. The ugliest manifestation of the 8-bit bus
cycle-eater is in fact the prefetch queue cycle-eater.
### The Prefetch Queue Cycle-Eater {#Heading9}
### The Prefetch Queue Cycle-Eater
In an 8088 context, here's the prefetch queue cycle-eater in a nutshell:
The 8088's 8-bit external data bus keeps the Bus Interface Unit from
@ -492,7 +492,7 @@ external data bus, that's a glaring omission—but, alas, an unavoidable
one. Let's look at why the official execution times are wrong, and why
that can't be helped.
#### Official Execution Times Are Only Part of the Story {#Heading10}
#### Official Execution Times Are Only Part of the Story
The sequence of 5 `SHR` instructions in the last example is 10 bytes
long. That means that it can never execute in less than 24 cycles even
@ -538,7 +538,7 @@ wrong, and why Intel can't provide better specifications. You also know
now why it is that you must time your code if you want to know how fast
it really is.
#### There Is No Such Beast as a True Instruction Execution Time {#Heading11}
#### There Is No Such Beast as a True Instruction Execution Time
The effect of the code preceding an instruction on the execution time of
that instruction makes the Zen timer trickier to use than you might
@ -738,7 +738,7 @@ executes on the PC just by looking at it! Get used to the idea that
execution times are only meaningful in context, learn the rules of thumb
in this book, and use the Zen timer to measure your code.
#### Approximating Overall Execution Times {#Heading12}
#### Approximating Overall Execution Times
Don't think that because overall instruction execution time is
determined by both instruction fetch time and Execution Unit execution
@ -767,7 +767,7 @@ instruction in a particular context to start when the first byte of the
instruction is sent to the Execution Unit and end when the first byte of
the next instruction is sent to the EU.
#### What to Do about the Prefetch Queue Cycle-Eater? {#Heading13}
#### What to Do about the Prefetch Queue Cycle-Eater?
Reducing the impact of the prefetch queue cycle-eater is one of the
overriding principles of high-performance assembly code. How can you do
@ -809,7 +809,7 @@ then time your code to see how fast it really is. You should experiment
freely, but always remember that actual, measured performance is the
bottom line.
#### Holding Up the 8088 {#Heading14}
#### Holding Up the 8088
In this chapter I've taken you further and further into the depths of
the PC, telling you again and again that you must understand the
@ -849,7 +849,7 @@ were programming in ignorance.
Let's start with DRAM refresh, which affects the performance of every
program that runs on the PC.
### Dynamic RAM Refresh: The Invisible Hand {#Heading15}
### Dynamic RAM Refresh: The Invisible Hand
Dynamic RAM (DRAM) refresh is sort of an act of God. By that I mean that
DRAM refresh invisibly and inexorably steals a certain fraction of all
@ -881,7 +881,7 @@ within 4 µs of the last refresh. Since there's no guarantee that a given
program will access each and every DRAM block once every 4 µs, the PC
contains special circuitry and programming for providing DRAM refresh.
#### How DRAM Refresh Works in the PC {#Heading16}
#### How DRAM Refresh Works in the PC
On the original 8088-based IBM PC, timer 1 of the 8253 timer chip is
programmed at power-up to generate a signal once every 72 cycles, or
@ -920,7 +920,7 @@ memory.
![**Figure 4.5**  *The PC bus dynamic RAM (DRAM) refresh.*](images/04-05.jpg)
#### The Impact of DRAM Refresh {#Heading17}
#### The Impact of DRAM Refresh
Let's look at examples from opposite ends of the spectrum in terms of
the impact of DRAM refresh on code performance. First, consider the
@ -1005,7 +1005,7 @@ ranging as high as 8.33 percent—is far more likely to occur. This is
especially true for high-performance assembly code, which uses fast
instructions that tend to cause non-stop instruction fetching.
#### What to Do About the DRAM Refresh Cycle-Eater? {#Heading18}
#### What to Do About the DRAM Refresh Cycle-Eater?
*Hmmm.* When we discovered the prefetch queue cycle-eater, we learned to
use short instructions. When we discovered the 8-bit bus cycle-eater, we
@ -1059,7 +1059,7 @@ two timing results that differ less or more than they seemingly should,
that's usually DRAM refresh too. Thanks to DRAM refresh, variations of
up to 8.33 percent in PC code performance are par for the course.
### Wait States {#Heading19}
### Wait States
Wait states are cycles during which a bus access by the CPU to a device
on the PC's bus is temporarily halted by that device while the device
@ -1121,7 +1121,7 @@ the PC. While any adapter *can* insert wait states, in the PC only
display adapters do so to the extent that performance is seriously
affected.
### The Display Adapter Cycle-Eater {#Heading20}
### The Display Adapter Cycle-Eater
Display adapters must serve two masters, and that creates a fundamental
performance problem. Master \#1 is the circuitry that drives the display
@ -1212,7 +1212,7 @@ the foreseeable future, and since it is the hardest graphics adapter to
wring performance from, we'll restrict our discussion to the VGA (and
its close relative, the EGA) for the remainder of this chapter.
#### The Impact of the Display Adapter Cycle-Eater {#Heading21}
#### The Impact of the Display Adapter Cycle-Eater
Even on the EGA and VGA, the effect of the display adapter cycle-eater
depends on the display mode selected. In text mode, the display adapter
@ -1366,7 +1366,7 @@ PC. Remember, the limited speed of access to a graphics adapter is an
inherent characteristic of the adapter, so the fastest computer around
can't access display memory one iota faster than the adapter will allow.
#### What to Do about the Display Adapter Cycle-Eater? {#Heading22}
#### What to Do about the Display Adapter Cycle-Eater?
What can we do about the display adapter cycle-eater? Well, we can
minimize display memory accesses whenever possible. In particular, we
@ -1422,7 +1422,7 @@ significant. There is only one way to discover just how significant the
impact of the display adapter cycle-eater is for any particular graphics
code, and that is of course to measure the performance of that code.
#### Cycle-Eaters: A Summary {#Heading23}
#### Cycle-Eaters: A Summary
We've covered a great deal of sophisticated material in this chapter, so
don't feel bad if you haven't understood everything you've read; it will
@ -1446,7 +1446,7 @@ This basic knowledge about cycle-eaters puts you in a good position to
understand the results reported by the Zen timer, and that means that
you're well on your way to writing high-performance assembler code.
#### What Does It All Mean? {#Heading24}
#### What Does It All Mean?
There you have it: life under the programming interface. It's not a
particularly pretty picture for the inhabitants of that strange realm

View file

@ -11,9 +11,9 @@ pages: 111-123
---
## Chapter 5\
Crossing the Border {#Heading1}
Crossing the Border
### Searching Files with Restartable Blocks {#Heading2}
### Searching Files with Restartable Blocks
*We just moved.* Those three little words should strike terror into the
heart of anyone who owns more than a sleeping bag and a toothbrush. Our
@ -66,7 +66,7 @@ more effort and forethought, but would have paid off handsomely.
And with that, let's look at a fairly complex application of restartable
blocks.
#### Searching for Text {#Heading3}
#### Searching for Text
The application we're going to examine searches a file for a specified
string. We'll develop a program that will search the file specified on
@ -112,7 +112,7 @@ all-important inner loop of our searching program, where the program
will spend virtually all of its time (aside from the unavoidable disk
access overhead).
### Avoiding the String Trap {#Heading4}
### Avoiding the String Trap
The easiest approach would be to use a C/C++ library function. The
closest match to what we need is `strstr()`, which searches one string
@ -136,7 +136,7 @@ for our application, from unnecessary overhead.
> it, and relate that to their performance in the context you're
> interested in.
### Brute-Force Techniques {#Heading5}
### Brute-Force Techniques
Given that no C/C++ library function meets our needs precisely, an
obvious alternative approach is the brute-force technique that uses
@ -169,7 +169,7 @@ match for the first character, stopping to check for a match with the
rest of the string *only* when the first character matches, as shown in
Figure 5.2.
### Using memchr() {#Heading6}
### Using memchr()
There's yet a better way to implement this approach, however. Use the
`memchr()` function, which does nothing more or less than find the
@ -201,7 +201,7 @@ Now that we've selected a searching approach, let's integrate it with
file handling and searching through multiple blocks. In other words,
let's make it restartable.
#### Making a Search Restartable {#Heading7}
#### Making a Search Restartable
As it happens, there's no great trick to putting the pieces of this
search program together. Basically, we'll read in a buffer of data
@ -407,7 +407,7 @@ main(int argc, char *argv[]) {
}
```
### Interpreting Where the Cycles Go {#Heading8}
### Interpreting Where the Cycles Go
To boost the overall performance of Listing 5.1, I would normally
convert `SearchForString()` to assembly language at this point.
@ -461,7 +461,7 @@ work.
Not likely.
#### Knowing When Assembly Is Pointless {#Heading9}
#### Knowing When Assembly Is Pointless
So that's why we're not going to go to assembly language in this
example—which is not to say it would never be worth converting the
@ -516,7 +516,7 @@ search engine is by no means fully optimized, it's nonetheless as fast
as there's any reason for it to be, given the balance of performance
among the components of this program.
### Always Look Where Execution Is Going {#Heading10}
### Always Look Where Execution Is Going
I've explained two important lessons: Know when it's worth optimizing
further, and use restartable blocks to process large data sets as a

View file

@ -11,9 +11,9 @@ pages: 125-133
---
## Chapter 6\
Looking Past Face Value {#Heading1}
Looking Past Face Value
### How Machine Instructions May Do More Than You Think {#Heading2}
### How Machine Instructions May Do More Than You Think
I first met Jeff Duntemann at an authors' dinner hosted by *PC Tech
Journal* at Fall Comdex, back in 1985. Jeff was already reasonably
@ -95,7 +95,7 @@ disadvantage every time you sit down to program.
In short, the x86 family can do much more than you think—if you'll use
everything it has to offer. Give it a shot!
#### Memory Addressing and Arithmetic {#Heading3}
#### Memory Addressing and Arithmetic
Years ago, I saw a clip on the David Letterman show in which Letterman
walked into a store by the name of "Just Lamps" and asked, "So what do
@ -169,7 +169,7 @@ calculations are free on the Pentium, however. I'll discuss 486
performance issues in Chapters 12 and 13, and the Pentium in Chapters 19
through 21.
### Math via Memory Addressing {#Heading4}
### Math via Memory Addressing
You're probably not particularly wowed to hear that you can use
addressing modes to perform memory addressing arithmetic that would
@ -235,7 +235,7 @@ and Pentium, `LEA` can also be slowed down by addressing interlocks.
![**Figure 6.1**  *Operation of ADD Reg,Reg vs. LEA Reg,{Addr}.*](images/06-01.jpg)
#### The Wonders of LEA on the 386 {#Heading5}
#### The Wonders of LEA on the 386
`LEA` really comes into its own as a "super-ADD" instruction on the
386, 486, and Pentium, where it can take advantage of the enhanced
@ -282,7 +282,7 @@ add edi,offset TableBase
when pointing to an entry in a doubly indexed table.
### Multiplication with LEA Using Non-Powers of Two {#Heading6}
### Multiplication with LEA Using Non-Powers of Two
Are you impressed yet with all that `LEA` can do on the 386? Believe
it or not, one more feature still awaits us. `LEA` can actually

View file

@ -11,9 +11,9 @@ pages: 136-148
---
## Chapter 7\
Local Optimization {#Heading1}
Local Optimization
### Optimizing Halfway between Algorithms and Cycle Counting {#Heading2}
### Optimizing Halfway between Algorithms and Cycle Counting
You might not think it, but there's much to learn about performance
programming from the Great Buffalo Sauna Fiasco. To wit:
@ -88,7 +88,7 @@ possible given the capabilities of the x86 family instruction set.
And yes, in case you're wondering, the above story is indeed true. Was I
there? Let me put it this way: If I were, I'd never admit it!
#### When LOOP Is a Bad Idea {#Heading3}
#### When LOOP Is a Bad Idea
Let's examine first an instruction that is less than it appears to be:
`LOOP`. There's no mystery about what `LOOP` does; it decrements CX
@ -144,7 +144,7 @@ jz SkipLoop ;If field is 0, don't bother
will do just fine and is faster on all processors. Use `JCXZ` only
when the Zero flag isn't already set to reflect the status of CX.
### The Lessons of LOOP and JCXZ {#Heading4}
### The Lessons of LOOP and JCXZ
What can we learn from `LOOP` and `JCXZ`? First, that a single
instruction that is intended to do a complex task is not necessarily
@ -167,7 +167,7 @@ published cycle times are closer to actual execution times on the 386
and 486 than on the 8088, and are reasonably reliable indicators of the
relative performance levels of x86 instructions.
#### Avoiding LOOPS of Any Stripe {#Heading5}
#### Avoiding LOOPS of Any Stripe
Cycle counting and directly substituting instructions (`DEC CX/JNZ`
for `LOOP`, for example) are techniques that belong at the lowest
@ -180,7 +180,7 @@ caught up in counting cycles because that's a small (albeit important)
part of the optimization picture, and not the area in which your
greatest advantage lies.
### Local Optimization {#Heading6}
### Local Optimization
One level at which assembly language programming pays off handsomely is
that of *local optimization;* that is, selecting the best *sequence* of
@ -327,7 +327,7 @@ SearchMaxLengthendp
end Start
```
### Unrolling Loops {#Heading7}
### Unrolling Loops
Listing 7.2 takes a different tack, unrolling the loop so that four
bytes are checked for each `LOOP` performed. The same instructions are
@ -490,7 +490,7 @@ avenues.
> as building blocks with unique characteristics rather than as
> instructions dedicated to specific tasks.
#### Rotating and Shifting with Tables {#Heading8}
#### Rotating and Shifting with Tables
As another example of local optimization, consider the matter of
rotating or shifting a mask into position. First, let's look at the
@ -558,7 +558,7 @@ BIT_PATTERN=BIT_PATTERN SHL 1
> optimization rule: Move as much work as possible out of your critical
> code by whatever means necessary.
#### NOT Flips Bits—Not Flags {#Heading9}
#### NOT Flips Bits—Not Flags
The `NOT` instruction flips all the bits in the operand, from 0 to 1
or from 1 to 0. That's as simple as could be, but `NOT` nonetheless
@ -586,7 +586,7 @@ and which flags are set, for example—can be critical when you're trying
to optimize a code sequence and you're running out of registers, or when
you're trying to minimize branching.
#### Incrementing with and without Carry {#Heading10}
#### Incrementing with and without Carry
Another case in which there are two slightly different ways to perform a
task involves adding 1 to an operand. You can do this with `INC`, as

View file

@ -11,9 +11,9 @@ pages: 149-166
---
## Chapter 8\
Speeding Up C with Assembly Language {#Heading1}
Speeding Up C with Assembly Language
### Jumping Languages When You Know It'll Help {#Heading2}
### Jumping Languages When You Know It'll Help
When I was a senior in high school, a pop song called "Seasons in the
Sun," sung by one Terry Jacks, soared up the pop charts and spent, as
@ -59,7 +59,7 @@ language output and tweaking it.
Apropos of which, when was the last time you heard of Terry Jacks?
#### Billy, Don't Be a Compiler {#Heading3}
#### Billy, Don't Be a Compiler
The key to optimizing C programs with assembly language is, as always,
writing good assembly language code, but with an added twist. Rule 1
@ -99,7 +99,7 @@ assembly language optimization.
> future changes and debugging more difficult, slowing you down and
> limiting your options.
### Don't Call Your Functions on Me, Baby {#Heading4}
### Don't Call Your Functions on Me, Baby
In order to think differently from a compiler, you must understand both
what compilers and C programmers tend to do and how that differs from
@ -130,7 +130,7 @@ extra cycles they take don't affect performance, then the code they're
in probably isn't critical, and perhaps you've chosen to convert too
much code to assembly, eh?
### Stack Frames Slow So Much {#Heading5}
### Stack Frames Slow So Much
C compilers work within the stack frame model, whereby variables reside
in a block of stack memory and are accessed via offsets from BP.
@ -149,7 +149,7 @@ sometimes useful indeed.
That doesn't mean you shouldn't use stack frames, which are useful and
often necessary. Just don't fall victim to their undeniable charms.
### Torn Between Two Segments {#Heading6}
### Torn Between Two Segments
C compilers are not terrific at handling segments. Some compilers can
efficiently handle a single far pointer used in a loop by leaving ES set
@ -166,7 +166,7 @@ address to be reloaded each time either pointer is used.
In assembly language you have full control over segments. Use it, and,
if necessary, reorganize your code to minimize segment loading.
#### Why Speeding Up Is Hard to Do {#Heading7}
#### Why Speeding Up Is Hard to Do
You might think that the most obvious advantage assembly language has
over C is that it allows the use of all forms of instructions and all
@ -219,7 +219,7 @@ jz Match
It's a simple example—but, I hope, a convincing one. Stretch your brain
when you optimize.
### Taking It to the Limit {#Heading8}
### Taking It to the Limit
The ultimate in assembly language optimization comes when you change the
rules; that is, when you reorganize the entire program to allow the use
@ -260,7 +260,7 @@ code into optimized assembly language:
That said, let me show some of these precepts in action.
#### A C-to-Assembly Case Study {#Heading9}
#### A C-to-Assembly Case Study
Listing 8.1 is the sample C application I'm going to use to examine
optimization in action. Listing 8.1 isn't really complete—it doesn't

View file

@ -11,9 +11,9 @@ pages: 167-188
---
## Chapter 9\
Hints My Readers Gave Me {#Heading1}
Hints My Readers Gave Me
### Optimization Odds and Ends from the Field {#Heading2}
### Optimization Odds and Ends from the Field
Back in high school, I took a pre-calculus class from Mr. Bourgeis,
whose most notable characteristics were incessant pacing and truly
@ -76,7 +76,7 @@ and many readers have sent me a slew of those over the years. So in this
chapter, I think I'll return the favor by devoting a chapter to reader
feedback.
#### Another Look at LEA {#Heading3}
#### Another Look at LEA
Several people have pointed out that while `LEA` is great for
performing certain additions (see Chapter 6), it isn't a perfect
@ -136,7 +136,7 @@ on what you're trying to do.
But there sure are a lot of interesting options, aren't there?
#### The Kennedy Portfolio {#Heading4}
#### The Kennedy Portfolio
Reader John Kennedy regularly passes along intriguing assembly
programming tricks, many of which I've never seen mentioned anywhere
@ -247,7 +247,7 @@ SHL AX,2 ;*64
ADD AX,BX ;*80
```
#### Speeding Up Multiplication {#Heading5}
#### Speeding Up Multiplication
That brings us to multiplication, one of the slowest of x86 operations
and one that allows for considerable optimization. One way to speed up
@ -302,7 +302,7 @@ that's always in the range of, say, 2 to 10; because the scale value
will always be small and the array elements may have any value, the
scale value is the logical choice for the multiplier.
#### Optimizing Optimized Searching {#Heading6}
#### Optimizing Optimized Searching
Rob Williams writes with a wonderful optimization to the `REPNZ
SCASB`-based optimized searching routine I discussed in Chapter 5. As a
@ -617,7 +617,7 @@ the difference lies not in elbow grease or cycle counting but in the
organic integrating optimizer technology we all carry around in our
heads.
#### Short Sorts {#Heading7}
#### Short Sorts
David Stafford (recently of Borland and Borland Japan) who happens to be
one of the best assembly language programmers I've ever met, has written
@ -666,7 +666,7 @@ _sort: pop dx ;get return address (entry point)
end
```
#### Full 32-Bit Division {#Heading8}
#### Full 32-Bit Division
One of the most annoying limitations of the x86 is that while the
dividend operand to the `DIV` instruction can be 32 bits in size, both
@ -802,7 +802,7 @@ main() {
}
```
#### Sweet Spot Revisited {#Heading9}
#### Sweet Spot Revisited
Way back in Volume 1, Number 1 of *PC TECHNIQUES*, (April/May 1990) I
wrote the very first of that magazine's HAX (\#1), which extolled the
@ -844,7 +844,7 @@ a large one) by several K—not bad, when you consider that the "sweet
spot" optimization is essentially free, with no code reorganization,
change in logic, or heavy thinking involved.
#### Hard-Core Cycle Counting {#Heading10}
#### Hard-Core Cycle Counting
Next, we come to an item that cycle counters will love, especially since
it involves apparently incorrect documentation on Intel's part.
@ -876,7 +876,7 @@ No great lesson here, just a caution to be leery of multibit `RCR` and
`RCL` when performance matters—and to take cycle-time documentation
with a grain of salt.
#### Hardwired Far Jumps {#Heading11}
#### Hardwired Far Jumps
Did you ever wonder how to code a far jump to an absolute address in
assembly language? Probably not, but if you ever do, you're going to be
@ -949,7 +949,7 @@ If the obvious doesn't work (and it usually doesn't), just try
everything you can think of, no matter how ridiculous, until you find
something that does—a rule with plenty of history on its side.
#### Setting 32-Bit Registers: Time versus Space {#Heading12}
#### Setting 32-Bit Registers: Time versus Space
To finish up this chapter, consider these two items. First, in 32-bit
protected mode,

View file

@ -11,9 +11,9 @@ pages: 190-203
---
## Chapter 10\
Patient Coding, Faster Code {#Heading1}
Patient Coding, Faster Code
### How Working Quickly Can Bring Execution to a Crawl {#Heading2}
### How Working Quickly Can Bring Execution to a Crawl
My grandfather does *The New York Times* crossword puzzle every Sunday.
In ink. With nary a blemish.
@ -84,7 +84,7 @@ will be much better—and you'll never even have the chance to decide
whether they're better or not if you take the first thing that comes
into your head and run with it.
#### The Case for Delayed Gratification {#Heading3}
#### The Case for Delayed Gratification
Once upon a time, I set out to read *Algorithms*, by Robert Sedgewick
(Addison-Wesley), which turned out to be a wonderful, stimulating, and
@ -110,7 +110,7 @@ The problem at hand, then, is simply this: Find the largest integer
value that evenly divides two arbitrary positive integers. That's all
there is to it. So warm up your pattern matchers...and go!
### The Brute-Force Syndrome {#Heading4}
### The Brute-Force Syndrome
I have a funny feeling that you'd already figured out how to find the
GCD before I even said "go." That's what I did when reading
@ -217,7 +217,7 @@ unsigned int gcd(unsigned int int1, unsigned int int2) {
}
```
#### Wasted Breakthroughs {#Heading5}
#### Wasted Breakthroughs
Sedgewick's first solution to the GCD problem was pretty much the one I
came up with. He then pointed out that the GCD of iL and iS is the same
@ -364,7 +364,7 @@ your ears does its best work not at the implementation stage, but at the
very beginning, when you try to imagine how what you want to do and what
a computer is capable of doing can best be brought together.
### Recursion {#Heading6}
### Recursion
Euclid's algorithm lends itself to recursion beautifully, so much so
that an implementation like Listing 10.3 comes almost without thought.
@ -417,7 +417,7 @@ unsigned int gcd(unsigned int int1, unsigned int int2) {
}
```
#### Patient Optimization {#Heading7}
#### Patient Optimization
At long last, we're ready to optimize GCD determination in the classic
sense. Table 10.1 shows the performance of Listing 10.4 with and without

View file

@ -11,9 +11,9 @@ pages: 205-231
---
## Chapter 11\
Pushing the 286 and 386 {#Heading1}
Pushing the 286 and 386
### New Registers, New Instructions, New Timings, New Complications {#Heading2}
### New Registers, New Instructions, New Timings, New Complications
This chapter, adapted from my earlier book *Zen of Assembly Language*
(1989; now out of print), provides an overview of the 286 and 386, often
@ -40,7 +40,7 @@ mainstream of computing, this chapter is a useful mix of history lesson,
x86 overview, and details on two workhorse processors that are still in
wide use.
#### Family Matters {#Heading3}
#### Family Matters
While the x86 family is a large one, only a few members of the
family—which includes the 8088, 8086, 80188, 80186, 286, 386SX, 386DX,
@ -80,7 +80,7 @@ its lifespan, and it is in even wider use than the 286. The future
clearly belongs to the 486 and Pentium, but the 286 and 386 are still
very much a part of the present-day landscape.
#### Crossing the Gulf to the 286 and the 386 {#Heading4}
#### Crossing the Gulf to the 286 and the 386
Apart from vastly improved performance, the biggest difference between
the 8088 and the 286 and 386 (as well as the later Intel CPUs) is that
@ -135,7 +135,7 @@ optimization strategies discussed in this book still hold true in
protected mode; it's just issues specific to protected mode or a
particular operating system that we won't discuss.
#### In the Lair of the Cycle-Eaters, Part II {#Heading5}
#### In the Lair of the Cycle-Eaters, Part II
Under the programming interface, the 286 and 386 differ considerably
from the 8088. Nonetheless, with one exception and one addition, the
@ -447,7 +447,7 @@ can literally double the performance of certain code running on the 286.
Even if it doesn't double performance, word alignment usually helps and
never hurts.
#### Code Alignment {#Heading8}
#### Code Alignment
Lack of word alignment can also interfere with instruction fetching on
the 286, although not to the extent that it interferes with access to
@ -698,7 +698,7 @@ What can we do about this new, more virulent form of the display adapter
cycle-eater? The workaround is the same as it was on the PC: Access
display memory as little as you possibly can.
#### New Instructions and Features: The 286 {#Heading13}
#### New Instructions and Features: The 286
The 286 and 386 offer a number of new instructions. The 286 has a
relatively small number of instructions that the 8088 lacks, while the
@ -731,7 +731,7 @@ For another, the 286 allows all shifts and rotates to be performed for
not just 1 bit or the number of bits specified by CL, but for *any*
constant number of bits.
#### New Instructions and Features: The 386 {#Heading14}
#### New Instructions and Features: The 386
The 386 is somewhat more complex than the 286 regarding new features.
Once again, we won't discuss protected mode, which on the 386 comes with
@ -941,7 +941,7 @@ the like.
The more things change, the more they remain the same....
#### POPF and the 286 {#Heading17}
#### POPF and the 286
We've one final 286-related item to discuss: the hardware malfunction of
`POPF` under certain circumstances on the 286.

View file

@ -11,9 +11,9 @@ pages: 233-246
---
## Chapter 12\
Pushing the 486 {#Heading1}
Pushing the 486
### It's Not Just a Bigger 386 {#Heading2}
### It's Not Just a Bigger 386
So this traveling salesman is walking down a road, and he sees a group
of men digging a ditch with their bare hands. "Whoa, there!" he says.
@ -45,7 +45,7 @@ register-to-register `MOV`s, Dorothy was heard to exclaim (before she
sank out of sight in a swirl of hopelessly mixed metaphors), "I don't
think we're in Kansas anymore, Toto."
#### Enter the 486 {#Heading3}
#### Enter the 486
No chip that is a direct, fully compatible descendant of the 8088, 286,
and 386 could ever be called a RISC chip, but the 486 certainly contains
@ -72,7 +72,7 @@ Intel; "8086 Optimization: Aim Down the Middle and Pray," in the March,
1991 *Dr. Dobb's Journal*; and "Peak Performance: On to the 486," in the
November, 1990 *Programmer's Journal.*
### Rules to Optimize By {#Heading4}
### Rules to Optimize By
In Appendix G of the *i486 Microprocessor Programmer*'*s* *Reference
Manual*, Intel lists a number of optimization techniques for the 486.
@ -102,7 +102,7 @@ the rules, documented and undocumented, that go into calculating actual
execution times—and uncovering some of those rules is exactly what this
chapter is about.
#### The Hazards of Indexed Addressing {#Heading5}
#### The Hazards of Indexed Addressing
Rule \#1: Avoid indexed addressing (that is, try not to use either two
registers or scaled addressing to point to memory).
@ -176,7 +176,7 @@ makes the *whole loop* more than 14 percent faster.
In a key loop on the 486, 1 cycle can indeed matter.
#### Calculate Memory Pointers Ahead of Time {#Heading6}
#### Calculate Memory Pointers Ahead of Time
Rule \#2: Don't use a register as a memory pointer during the next two
cycles after loading it.
@ -295,7 +295,7 @@ rearrangement of 486 code.
![**Figure 12.2**  *Two-cycle-ahead address pipelining.*](images/12-02.jpg)
### Caveat Programmor {#Heading7}
### Caveat Programmor
A caution: I'm quite certain that the 2-cycle-ahead addressing pipeline
interruption penalty I've described exists in the two 486s I've tested.
@ -319,7 +319,7 @@ undocumented optimizations, please write and let me know. And, of
course, if anyone from Intel is reading this and wants to give us the
gospel truth, please do!
#### Stack Addressing and Address Pipelining {#Heading8}
#### Stack Addressing and Address Pipelining
Rule \#2A: Rule \#2 sometimes, but not always, applies to the stack
pointer when it is implicitly used to point to memory.
@ -396,7 +396,7 @@ from the stack pointer should ideally be done at least two cycles before
`PUSH`, `POP`, `RET`, or any other instruction that uses the stack
pointer to address memory.
#### Problems with Byte Registers {#Heading9}
#### Problems with Byte Registers
There are two ways to lose cycles by using byte registers, and neither
of them is documented by Intel, so far as I know. Let's start with the
@ -479,7 +479,7 @@ you're a diehard ASMhead who does this stuff for fun. Just learn enough
to be able to speed up the key portions of your programs, and spend the
rest of your time on a fast design and overall implementation.
#### More Fun with Byte Registers {#Heading10}
#### More Fun with Byte Registers
Rule \#4: Don't load *any* byte register exactly 2 cycles before using
*any* register to address memory.
@ -552,7 +552,7 @@ can affect.
> to address memory, and try not to load a register either one or two
> cycles before using it to address memory, and you'll be fine.
#### Timing Your Own 486 Code {#Heading11}
#### Timing Your Own 486 Code
In case you want to do some 486 performance analysis of your own, let me
show you how I arrived at one of the above conclusions; at the same
@ -624,7 +624,7 @@ bytes.
> Whenever you see non-integral timing results of this sort, it's a good
> bet that the test code or data isn't cached.
### The Story Continues {#Heading12}
### The Story Continues
There's certainly plenty more 486 lore to explore, including the 486's
unique prefetch queue, more optimization rules, branching optimizations,

View file

@ -11,9 +11,9 @@ pages: 248-258
---
## Chapter 13\
Aiming the 486 {#Heading1}
Aiming the 486
### Pipelines and Other Hazards of the High End {#Heading2}
### Pipelines and Other Hazards of the High End
It's a sad but true fact that 84 percent of American schoolchildren are
ignorant of 92 percent of American history. Not my daughter, though. We
@ -58,7 +58,7 @@ For example, consider how Terje Mathisen doubled the speed of his
word-counting program on a 486 simply by shuffling a couple of
instructions.
#### 486 Pipeline Optimization {#Heading3}
#### 486 Pipeline Optimization
I've mentioned Terje Mathisen in my writings before. Terje is an
assembly language programmer extraordinaire, and author of the
@ -167,7 +167,7 @@ engine can process more than 16 million characters *per second* on a
Clever 486 optimization can pay off big. QED.
### BSWAP: More Useful Than You Might Think {#Heading4}
### BSWAP: More Useful Than You Might Think
There are only 3 non-system instructions unique to the 486. None is
earthshaking, but they have their uses. Consider `BSWAP`. `BSWAP` does
@ -268,7 +268,7 @@ looptop:
jnz looptop
```
### Pushing and Popping Memory {#Heading5}
### Pushing and Popping Memory
Pushing or popping a memory location, as in `PUSH WORD PTR [BX]` or
`POP [MemVar]`, is a compact, easy way to get a value onto or off of
@ -315,7 +315,7 @@ well as `XLAT`, `LOOP`, and, of course, `PUSH *mem*` and `POP
> pipeline efficiency, as is the case with Terje's optimization described
> earlier in this chapter.
### Optimal 1-Bit Shifts and Rotates {#Heading6}
### Optimal 1-Bit Shifts and Rotates
On a 486, the n-bit forms of the shift and rotate instructions—as in
`ROR AX,2` and `SHL BX,9`—are 2-cycle instructions, but the 1-bit
@ -357,7 +357,7 @@ critical cycles—and Lord knows that if you're optimizing for the
unoptimized code on a 486—you almost certainly need all the speed you
can get.
### 32-Bit Addressing Modes {#Heading7}
### 32-Bit Addressing Modes
The 386 and 486 both support 32-bit addressing modes, in which any
register may serve as the base memory addressing register, and almost

View file

@ -11,9 +11,9 @@ pages: 260-277
---
## Chapter 14\
Boyer-Moore String Searching {#Heading1}
Boyer-Moore String Searching
### Optimizing a Pretty Optimum Search Algorithm {#Heading2}
### Optimizing a Pretty Optimum Search Algorithm
When you seem to be stumped, stop for a minute and *think.* All the
information you need may be right in front of your nose if you just look
@ -61,7 +61,7 @@ said, "Hey! Did you guys put in a new floor?"
As I said, sometimes everything you need to know is right in front of
your nose. Which brings us to Boyer-Moore string searching.
### String Searching Refresher {#Heading3}
### String Searching Refresher
I've discussed string searching earlier in this book, in Chapters 5 and
9. You may want to refer back to these chapters for some background on
@ -132,7 +132,7 @@ matches. Can we?
Actually, yes, we can.
### The Boyer-Moore Algorithm {#Heading4}
### The Boyer-Moore Algorithm
All our *a priori* knowledge of string searching is stated above, but
there's another sort of knowledge—knowledge that's generated
@ -228,7 +228,7 @@ is to it!
![**Figure 14.2**  *Mismatch on third character checked.*](images/14-02.jpg)
### Boyer-Moore: The Good and the Bad {#Heading5}
### Boyer-Moore: The Good and the Bad
The worst case for this version of Boyer-Moore is that the pattern
mismatches on the leftmost character—the last character compared—every
@ -627,7 +627,7 @@ thereby getting the best of both worlds.)
Know your data and use your smarts. Don't stop thinking just because
you're implementing a big-name algorithm; you know more than it does.
### Further Optimization of Boyer-Moore {#Heading6}
### Further Optimization of Boyer-Moore
We can do substantially better yet than Listing 14.3 if we're willing to
accept tighter limits on the data. Limiting the length of the
@ -797,7 +797,7 @@ all but the first search when repeatedly searching for a particular
pattern, by building the skip table externally and passing a pointer to
it as a parameter.
### Know What You Know {#Heading7}
### Know What You Know
Here we've turned up our nose at a repeated string instruction, we've
gone against the grain by comparing backward, and yet we've speeded up

View file

@ -11,9 +11,9 @@ pages: 279-293
---
## Chapter 15\
Linked Lists and plain Unintended Challenges {#Heading1}
Linked Lists and plain Unintended Challenges
### Unfamiliar Problems with Familiar Data Structures {#Heading2}
### Unfamiliar Problems with Familiar Data Structures
After 21 years, this story still makes me wince. Oh, the humiliations I
suffer for your enlightenment....
@ -76,7 +76,7 @@ lifetime at this stuff and happens to be a genius?
Maybe you can—but I sure can't. For example, consider the evolution of
my understanding of linked lists.
### Linked Lists {#Heading3}
### Linked Lists
Linked lists are data structures composed of discrete elements, or
nodes, joined together with links. In C, the links are typically
@ -230,7 +230,7 @@ nodes, and in fact in all link manipulation code. It's easy to end up
working with either pointers to pointers or lots of special-case code,
and while those approaches work, they're inelegant and inefficient.
### Dummies and Sentinels {#Heading4}
### Dummies and Sentinels
A far better approach is to use a *dummy node* for the head of the list,
as shown in Figure 15.2. I invented this one for myself the next time I
@ -335,7 +335,7 @@ struct LinkNode *FindNodeBeforeValueNotLess(
![**Figure 15.4**  *List terminated by a sentinel.*](images/15-04.jpg)
### Circular Lists {#Heading5}
### Circular Lists
One minor but elegant refinement yet remains: Use a single node as both
the head *and* the tail of the list. We can do this by connecting the
@ -597,7 +597,7 @@ void main()
}
```
### Hi/Lo in 24 Bytes {#Heading6}
### Hi/Lo in 24 Bytes
In one of my *PC TECHNIQUES* "Pushing the Envelope" columns, I passed
along one of David Stafford's fiendish programming puzzles: Write a

View file

@ -11,9 +11,9 @@ pages: 295-319
---
## Chapter 16\
There Ain't No Such Thing as the Fastest Code {#Heading1}
There Ain't No Such Thing as the Fastest Code
### Lessons Learned in the Pursuit of the Ultimate Word Counter {#Heading2}
### Lessons Learned in the Pursuit of the Ultimate Word Counter
I remember reading an overview of C++ development tools for Windows in a
past issue of *PC Week*. In the lower left corner was the familiar box
@ -54,7 +54,7 @@ particularly attractive keys. We are talking about people who are
focusing on means, and have forgotten about ends. We are talking about
people with no programming souls.
### Counting Words in a Hurry {#Heading3}
### Counting Words in a Hurry
What are we to make of this? At the very least, we can safely guess that
very few corporate buyers ever enter optimization contests. Most of my
@ -331,7 +331,7 @@ _ScanBuffer endp
end
```
#### Which Way to Go from Here? {#Heading4}
#### Which Way to Go from Here?
We could rearrange the tests in light of the nature of the data being
scanned; for example, we could perform the tests more efficiently by
@ -487,7 +487,7 @@ difficult.
> ![](images/i.jpg)
> Exhaust all other optimizations before unrolling loops.
### Challenges and Hazards {#Heading5}
### Challenges and Hazards
The challenge I put to the readers of *PC TECHNIQUES* was to write a
faster module to replace Listing 16.4. The author of the code that
@ -520,7 +520,7 @@ code is the fastest possible is rollescating on a tightrope in a
hurricane; you're due for a fall, if you catch my drift. Case in point:
Terje Mathisen's word-counting program.
#### Blinding Yourself to a Better Approach {#Heading6}
#### Blinding Yourself to a Better Approach
Not so long ago, Terje Mathisen, who I introduced earlier in this book,
wrote a very fast word-counting program, and posted it on Bix. When I
@ -561,7 +561,7 @@ enough, by good fortune, to speed up the whole program by 5 percent.
this case, though, the code was specific to the 386. In case you're
curious, both forms take 2 cycles on the 486; quite a lot faster, eh?)
#### Watch Out for Luggable Assumptions! {#Heading7}
#### Watch Out for Luggable Assumptions!
The first lesson to be learned here is not to lug assumptions that may
no longer be valid from the 8088/286 world into the wonderful new world
@ -613,7 +613,7 @@ if you're interested in really fast assembly code. I wouldn't call it
the *fastest* word-counting code, though, because I would of course
never be so foolish as to call *anything* the fastest.
### The Astonishment of Right-Brain Optimization {#Heading8}
### The Astonishment of Right-Brain Optimization
As it happened, the challenge I issued to my *PC TECHNIQUES* readers was
a smashing success, with dozens of good entries. I certainly enjoyed it,
@ -847,7 +847,7 @@ jumping.
end
```
### Levels of Optimization {#Heading9}
### Levels of Optimization
Three levels of optimization were evident in the word-counting entries I
received in response to my challenge. I'd briefly describe them as
@ -865,7 +865,7 @@ the code, the greater the chance for obscure bugs.)
> like buying Telly Savalas a comb; it's not going to do any harm, but
> it's nonetheless a waste of time.
#### Optimization Level 1: Good Code {#Heading10}
#### Optimization Level 1: Good Code
The first level of optimization involves fine-tuning and clever use of
the instruction set. The basic framework is still the same as my code
@ -1038,7 +1038,7 @@ _ScanBuffer endp
end
```
### Level 2: A New Perspective {#Heading11}
### Level 2: A New Perspective
The second level of optimization is one of breaking out of the mode of
thinking established by my original code. Some entrants clearly did
@ -1117,7 +1117,7 @@ John's approach makes it clear that word-counting is nothing more than a
fairly simple state machine. The interesting part, of course, is
building the fastest state machine.
#### Level 3: Breakthrough {#Heading12}
#### Level 3: Breakthrough
The boundaries between the levels of optimization are not sharply
defined. In a sense, level 3 optimization is just like levels 1 and 2,
@ -1233,7 +1233,7 @@ cycles/byte.
Enough said, I trust.
#### Enough Word Counting Already! {#Heading13}
#### Enough Word Counting Already!
Before I finish up this chapter, I'd like to mention that Terje
Mathisen's WC word-counting program, which I've mentioned previously and

View file

@ -11,9 +11,9 @@ pages: 322-346
---
## Chapter 17\
The Game of Life {#Heading1}
The Game of Life
### The Triumph of Algorithmic Optimization in a Cellular Automata Game {#Heading2}
### The Triumph of Algorithmic Optimization in a Cellular Automata Game
I've spent a lot of my life discussing assembly language optimization,
which I consider to be an important and underappreciated topic. However,
@ -40,7 +40,7 @@ we will find is that it's possible to get a 50-times speed-up without
using *one byte of assembly!* It's all a matter of perspective—how you
look at your code and data.
### Conway's Game {#Heading3}
### Conway's Game
The program that we're going to optimize is Conway's famous Game of
Life, long-ago favorite of the hackers at MIT's AI Lab. If you've never
@ -64,7 +64,7 @@ speed-up range. Then in the next chapter, I'll show you how several
programmers *really* floored it in taking me up on my second
Optimization Challenge, which involved the Game of Life.
#### The Rules of the Game {#Heading4}
#### The Rules of the Game
The Game of Life is ridiculously simple. There is a cellmap, consisting
of a rectangular matrix of cells, each of which may initially be either
@ -359,7 +359,7 @@ void show_text(int x, int y, char *text)
}
```
### Where Does the Time Go? {#Heading5}
### Where Does the Time Go?
How slow is Listing 17.1? Table 17.1 shows that even on a 486, Listing
17.1 does fewer than three 96x96 generations per second. (The times in
@ -415,7 +415,7 @@ at for possible optimizations are `cell_state()` and
> knowing the nature of your data, and is a potent optimization technique
> that will be extremely useful a little later in this chapter.
### The Hazards and Advantages of Abstraction {#Heading6}
### The Hazards and Advantages of Abstraction
How can we speed up `cell_state()` and `next_generation()`? I'll
tell you how *not* to do it: By writing those member functions in
@ -685,7 +685,7 @@ assembly?
Not hardly.
### Heavy-Duty C++ Optimization {#Heading7}
### Heavy-Duty C++ Optimization
Before we get to assembly, we still have to perform C++ optimization,
then see if we can find an alternative approach that better fits the
@ -826,7 +826,7 @@ How is this possible? Here are some hints:
bit-per-pixel.
* Cells change state relatively infrequently.
### Bringing In the Right Brain {#Heading8}
### Bringing In the Right Brain
In the previous section, we saw how a C++ program could be sped up about
eight times simply by rearranging the data and code in straightforward
@ -843,7 +843,7 @@ encourage you to saturate your brain with everything you know about any
particular optimization problem, then make space for your right brain to
solve the problem.
#### Re-Examining the Task {#Heading9}
#### Re-Examining the Task
Earlier in this chapter, we looked at a straightforward Game of Life
implementation, then increased performance considerably by making the
@ -907,7 +907,7 @@ only one-tenth that of the original approach!
![**Figure 17.3**  *New cell format.*](images/17-03.jpg)
#### Acting on What We Know {#Heading10}
#### Acting on What We Know
Once we've changed the cellmap format to store neighbor counts as well
as states, with a byte for each cell, we can get another performance
@ -1254,7 +1254,7 @@ No doubt we could get another two to five times improvement with good
assembly code—but that's dwarfed by a 30-times improvement, so
optimization at a conceptual level *must* come first.
#### The Challenge That Ate My Life {#Heading11}
#### The Challenge That Ate My Life
The most recent optimization challenge I laid my community of readers
was to write the fastest possible Game of Life generation engine. By

View file

@ -11,9 +11,9 @@ pages: 347-367
---
## Chapter 18\
It's a plain Wonderful Life {#Heading1}
It's a plain Wonderful Life
### Optimization beyond the Pale {#Heading2}
### Optimization beyond the Pale
When I was in high school, my gym teacher had us run a race around the
soccer field, or rather, around a course marked with cones that roughly
@ -51,7 +51,7 @@ programming.
> will often be unable to change the specifications for the software you
> implement.
### Breaking the Rules {#Heading3}
### Breaking the Rules
The other reason for the anecdote has to do with the way my second
Optimization Challenge worked itself out. If you'll recall from the last
@ -119,7 +119,7 @@ specific "David Stafford" or "Peter Klerings.")
Onward to the code.
### Table-Driven Magic {#Heading4}
### Table-Driven Magic
David Stafford won my first Optimization Challenge by means of a huge
look-up table and an incredible state machine driven by that table. The
@ -859,7 +859,7 @@ extern unsigned short far ChangeList1[];
#define WRAPDOWN (UP * (HEIGHT - 1))
```
### Keeping Track of Change with a Change List {#Heading5}
### Keeping Track of Change with a Change List
In my earlier optimizations to the Game of Life, described in the last
chapter, I noted that most cells in a Life cellmap are dead, and in most
@ -966,7 +966,7 @@ Segment usage in David's assembly code is summarized in Listing 18.6.
FS : Video segment
GS : Unused
#### A Layperson's Overview of QLIFE {#Heading6}
#### A Layperson's Overview of QLIFE
Most likely, you're scratching your head right now in bemusement. I
don't blame you; I felt the same way myself at first. It's actually

View file

@ -11,9 +11,9 @@ pages: 369-379
---
## Chapter 19\
Pentium: Not the Same Old Song {#Heading1}
Pentium: Not the Same Old Song
### Learning a Whole Different Set of Optimization Rules {#Heading2}
### Learning a Whole Different Set of Optimization Rules
I can still remember the day I did my first 8088 programming. I had just
moved over from the distantly related Z80, so the 8088 wasn't totally
@ -45,7 +45,7 @@ that made cycle counting more meaningful than ever before, and careful
code massaging sometimes yielded startling results. Nonetheless, the 486
was still too simple to mark a return to the golden age of optimization.
### The Return of Optimization as Art {#Heading3}
### The Return of Optimization as Art
Then the Pentium came around, and filled our code with optimization
hazards, and life was good again. The Pentium has two execution
@ -90,7 +90,7 @@ pitch Preparation H. I can hardly wait.
Gimme a "P"....
### The Pentium: An Overview {#Heading4}
### The Pentium: An Overview
Architecturally, the Pentium is vastly different in many ways from the
486, but most of those differences are transparent to programmers. After
@ -139,7 +139,7 @@ to 128 bytes. In conjunction with the branch prediction feature
branches, this larger prefetch queue means that the Pentium's two pipes
should be better fed than those of any previous x86 processor.
#### Crossing Cache Lines {#Heading5}
#### Crossing Cache Lines
There are three other characteristics of the Pentium that make for a
healthy supply of instruction bytes. One is that the Pentium can
@ -189,7 +189,7 @@ Architecture and Programming Manual* (ISBN 1-55512-195-0; Intel order
number 241430-001), and the article "Optimizing Pentium Code" by Mike
Schmidt, in *Dr. Dobb's Journal* for January 1994.
#### Cache Organization {#Heading6}
#### Cache Organization
There are two other interesting changes in the Pentium's cache
organization. First, the cache is two-way set-associative, whereas the
@ -243,7 +243,7 @@ improvement. Clearly, avoiding AGIs becomes a much more challenging and
rewarding game in a superscalar world, one to which I'll return in the
next chapter.
### Faster Addressing and More {#Heading7}
### Faster Addressing and More
I'll spend the rest of this chapter covering a variety of Pentium
optimization tips. For starters, effective address calculations (that
@ -346,7 +346,7 @@ Pentium may have to shut down the V-pipe for a cycle to avoid potential
dependencies on the result of the `AND` or `OR`. `TEST` suffers
from no such potential dependencies.
### Branch Prediction {#Heading8}
### Branch Prediction
One brand-spanking-new feature of the Pentium is *branch prediction*,
whereby the Pentium tries to guess, based on past history, which way
@ -406,7 +406,7 @@ on any given iteration.
> to fall through branches if possible, and try to be consistent in your
> branching if not.
### Miscellaneous Pentium Topics {#Heading9}
### Miscellaneous Pentium Topics
The Pentium has all the instructions of the 486, plus a few new ones.
One much-needed instruction that has finally made it into the
@ -418,7 +418,7 @@ to me to be a particularly useful instruction, but I'm sure Intel
wouldn't have added it without a reason; if you know of a use for it,
please pass it along to me.
#### 486 versus Pentium Optimization {#Heading10}
#### 486 versus Pentium Optimization
Many Pentium optimizations help, or at least don't hurt, on the 486.
Many, but not all—and many *do* hurt on the 386. As I discuss various
@ -438,7 +438,7 @@ absolutely the best possible performance for your DOS and Windows apps
on the fastest hardware, Pentium optimization can make your code
*scream*.
#### Going Superscalar {#Heading11}
#### Going Superscalar
In the next chapter, we'll look into the single biggest element of
Pentium performance, cranking up the Pentium's second execution pipe.

View file

@ -11,9 +11,9 @@ pages: 381-396
---
## Chapter 20\
Pentium Rules {#Heading1}
Pentium Rules
### How Your Carbon-Based Optimizer Can Put the "Super" in Superscalar {#Heading2}
### How Your Carbon-Based Optimizer Can Put the "Super" in Superscalar
At the 1983 West Coast Computer Faire, my friend Dan Illowsky, Andy
Greenberg (co-author of Wizardry, at that time the best-selling computer
@ -71,7 +71,7 @@ that the `FXCH` instruction, which is largely free on the Pentium, is
expensive on the 486.) So discard your x86 preconceptions as we delve
into superscalar optimization for this one-of-a-kind processor.
### An Instruction in Every Pipe {#Heading3}
### An Instruction in Every Pipe
In the last chapter, we took a quick tour of the Pentium's architecture,
and started to look into the Pentium's optimization rules. Now we're
@ -139,7 +139,7 @@ practice, this is not too difficult. The only hard part is keeping in
mind the long list of rules governing instruction pairing. The place to
begin is with the set of instructions that can go through the V-pipe.
### V-Pipe-Capable Instructions {#Heading4}
### V-Pipe-Capable Instructions
Any instruction can go through the U-pipe, and, for practical purposes,
the U-pipe is always executing instructions. (The exceptions are when
@ -327,7 +327,7 @@ sequence can be reduced to 1.5 cycles, but it is *14* bytes long.
> performance and ignore the size, but on a program-wide basis, the size
> bears watching.
### Lockstep Execution {#Heading5}
### Lockstep Execution
You may wonder why anyone would bother breaking `ADD [MemVar],EAX`
into three instructions, given that this instruction can go through
@ -470,7 +470,7 @@ one-cycle instructions, mixed together so that at least two operations
are in progress at once. It's not the easiest code to read or write, but
it's the only way to get both pipes running at capacity.
### Superscalar Notes {#Heading6}
### Superscalar Notes
You may well ask why it's necessary to interleave operations, as is done
in Figure 20.7. It seems simpler just to turn
@ -505,7 +505,7 @@ hazard known as *register contention*. I'll return to the subject of
register contention in the next chapter; in the remainder of this
chapter I'd like to cover a few short items about superscalar execution.
#### Register Starvation {#Heading7}
#### Register Starvation
The above examples should make it pretty clear that effective
superscalar programming puts a lot of strain on the Pentium's relatively

View file

@ -11,9 +11,9 @@ pages: 397-411
---
## Chapter 21\
Unleashing the Pentium's V-Pipe {#Heading1}
Unleashing the Pentium's V-Pipe
### Focusing on Keeping Both Pentium Pipes Full {#Heading2}
### Focusing on Keeping Both Pentium Pipes Full
The other day, my daughter suggested that we each draw the prettiest
picture we could, then see whose was prettier. I won't comment on who
@ -52,7 +52,7 @@ written code from taking full advantage of the Pentium's two pipes, and
can thereby keep your code from pushing the Pentium to maximum
performance.
### Address Generation Interlocks {#Heading3}
### Address Generation Interlocks
The Pentium is advertised as having a five-stage pipeline for each of
its execution units. All this means is that at any given time, up to
@ -186,7 +186,7 @@ want to insert an instruction between the two `MOV`s—and, of course,
this is yet another reason why you should always measure your code's
actual performance.
### Register Contention {#Heading4}
### Register Contention
Finally, we come to the last major component of superscalar
optimization: register contention. The basic premise here is simple: You
@ -228,7 +228,7 @@ instructions comprising the above substitute for `MOVZX` should have
at least one unrelated instruction between them when `SUB EAX,EAX`
executes in the V-pipe.
#### Exceptions to Register Contention {#Heading5}
#### Exceptions to Register Contention
Intel has special-cased some very useful exceptions to register
contention. Happily, write-after-read operations do *not* cause
@ -285,7 +285,7 @@ U-pipe and 5 cycles in the V-pipe, and mispredicted calls and
unconditional jumps take 3 cycles in either pipe. Note that `RET`
can't pair.
### Who's in First? {#Heading6}
### Who's in First?
One of the trickiest things about superscalar optimization is that a
given instruction stream can execute at a different speed depending on
@ -321,7 +321,7 @@ usage, as discussed below. Shifts, rotates, `ADC, SBB`, and all other
instructions not listed in Table 20.1 in the last chapter are likewise
U-pipe markers.
### Pentium Optimization in Action {#Heading7}
### Pentium Optimization in Action
Now, let's take a look at one of the simplest, tightest pieces of code
imaginable, and see what our new Pentium perspective reveals. Listing
@ -646,7 +646,7 @@ measurement to check the efficacy of your optimizations, so reserve it
for when you really, really need it—but when you need it, you need it
*bad*.
#### A Quick Note on the 386 and 486 {#Heading8}
#### A Quick Note on the 386 and 486
I've mentioned that Pentium-optimized code does fine on the 486, but not
always so well on the 386. On a 486, Listing 21.1 runs at 9 cycles per

View file

@ -11,9 +11,9 @@ pages: 413-420
---
## Chapter 22\
Zenning and the Flexible Mind {#Heading1}
Zenning and the Flexible Mind
### Taking a Spin through What You've Learned {#Heading2}
### Taking a Spin through What You've Learned
And so we come to the end of our journey; for now, at least. What
follows is a modest bit of optimization, one which originally served to
@ -36,7 +36,7 @@ plain fun.
Enjoy!
### Zenning {#Heading3}
### Zenning
In Jeff Duntemann's excellent book *Borland Pascal From Square One*
(Random House, 1993), there's a small assembly subroutine that's

View file

@ -13,9 +13,9 @@ pages: 423-448
# Part II
## Chapter 23\
Bones and Sinew {#Heading1}
Bones and Sinew
### At the Very Heart of Standard PC Graphics {#Heading2}
### At the Very Heart of Standard PC Graphics
The VGA is unparalleled in the history of computer graphics, for it is
by far the most widely-used graphics standard ever, the closest we may
@ -50,7 +50,7 @@ well underway.
We'll start our exploration with a quick overview of the VGA, and then
we'll dive right in and get a taste of what the VGA can do.
### The VGA {#Heading3}
### The VGA
The VGA is the baseline adapter for modern IBM PC compatibles, present
in virtually every PC sold today or in the last several years. (Note
@ -103,7 +103,7 @@ rather to start you down the road to understanding the VGA.
Let's begin.
### An Introduction to VGA Programming {#Heading4}
### An Introduction to VGA Programming
Most discussions of the VGA start out with a traditional "Here's a block
diagram of the VGA" approach, with lists of registers and statistics.
@ -128,7 +128,7 @@ conceptual level, letting the code itself demonstrate the implementation
details. We'll return to many of these concepts in more depth later in
this book.
### At the Core {#Heading5}
### At the Core
A little background is necessary before we're ready to examine Listing
23.1. The VGA is built around four functional blocks, named the CRT
@ -247,7 +247,7 @@ fixed. Moreover, a great deal of graphics software now uses word
> course, this method only works if the GC Index register remains
> unchanged throughout the loop.
#### Linear Planes and True VGA Modes {#Heading6}
#### Linear Planes and True VGA Modes
The VGA's memory is organized as four 64K planes. Each of these planes
is a linear bitmap; that is, each byte from a given plane controls eight
@ -867,7 +867,7 @@ cseg ends
end start
```
#### Smooth Panning {#Heading7}
#### Smooth Panning
The first thing you'll notice upon running the sample program is the
remarkable smoothness with which the display pans from side-to-side and
@ -972,7 +972,7 @@ should be set to 1.
> reinventing the wheel and because the BIOS may well mask
> incompatibilities between the IBM VGA and VGA clones.
#### Color Plane Manipulation {#Heading8}
#### Color Plane Manipulation
The VGA provides a considerable amount of hardware assistance for
manipulating the four display memory planes. Two features illustrated by
@ -1050,7 +1050,7 @@ first pass; the VGA is a complicated beast, and learning about it is an
iterative process. We'll be going over these features again, in
different contexts, over the course of the rest of this book.
#### Page Flipping {#Heading9}
#### Page Flipping
When animated graphics are drawn directly on the screen, with no
intermediate frame-composition stage, the image typically flickers
@ -1156,7 +1156,7 @@ designing programs for the VGA.
To see the program run in 640x200 16-color mode, comment out the `EQU`
line for `MEDRES_VIDEO_MODE`.
### The Hazards of VGA Clones {#Heading10}
### The Hazards of VGA Clones
Earlier, I said that any VGA that doesn't support the features and
functionality covered in this book can't properly be called VGA
@ -1186,7 +1186,7 @@ is that if you're going to use oversized virtual bitmaps and pan around
them, you should take great care to test your software on a wide variety
of VRAM- and DRAM-based VGAs.
### Just the Beginning {#Heading11}
### Just the Beginning
That pretty well covers the important points of the sample VGA program
in Listing 23.1. There are many VGA features we didn't even touch on,
@ -1196,7 +1196,7 @@ VGA's resources, and in general to give you an initial sense of what VGA
programming is like. Starting with the next chapter, we'll begin to
explore the VGA systematically, on a more detailed basis.
### The Macro Assembler {#Heading12}
### The Macro Assembler
The code in this book is written in both C and assembly. I think C is a
good development environment, but I believe that often the best code

View file

@ -11,9 +11,9 @@ pages: 449-460
---
## Chapter 24\
Parallel Processing with the VGA {#Heading1}
Parallel Processing with the VGA
### Taking on Graphics Memory Four Bytes at a Time {#Heading2}
### Taking on Graphics Memory Four Bytes at a Time
This heading refers to the ability of the VGA chip to manipulate up to
four bytes of display memory at once. In particular, the VGA provides
@ -24,7 +24,7 @@ one part of the surprisingly complex data flow architecture of the VGA,
but since they're involved in almost all memory access operations,
they're a good place to begin.
### VGA Programming: ALUs and Latches {#Heading3}
### VGA Programming: ALUs and Latches
I'm going to begin our detailed tour of the VGA at the heart of the flow
of data through the VGA: the four ALUs built into the VGA's Graphics
@ -395,7 +395,7 @@ encountered any particularly valuable applications for AND and OR, but
they're the sort of building-block features that could come in handy in
just the right context, so keep them in mind.
### Notes on the ALU/Latch Demo Program {#Heading4}
### Notes on the ALU/Latch Demo Program
VGA settings such as the logical function select should be restored to
their default condition before the BIOS is called to output text or draw

View file

@ -11,9 +11,9 @@ pages: 461-479
---
## Chapter 25\
VGA Data Machinery {#Heading1}
VGA Data Machinery
### The Barrel Shifter, Bit Mask, and Set/Reset Mechanisms {#Heading2}
### The Barrel Shifter, Bit Mask, and Set/Reset Mechanisms
In the last chapter, we examined a simplified model of data flow within
the GC portion of the VGA, featuring the latches and ALUs. Now we're
@ -21,7 +21,7 @@ ready to expand that model to include the barrel shifter, bit mask, and
the set/reset capabilities, leaving only the write modes to be explored
over the next few chapters.
### VGA Data Rotation {#Heading3}
### VGA Data Rotation
Figure 25.1 shows an expanded model of GC data flow, featuring the
barrel shifter and bit mask circuitry. Let's look at the barrel shifter
@ -60,7 +60,7 @@ I'll demonstrate that application below. In general, though, don't knock
yourself out trying to figure out how to work data rotation into your
programs—it just isn't all that useful in most cases.
### The Bit Mask {#Heading4}
### The Bit Mask
The VGA has bit mask circuitry for each of the four memory planes. The
four bit masks operate in parallel and are all driven by the same mask
@ -403,7 +403,7 @@ complex."
He's got a point there.
### The VGA's Set/Reset Circuitry {#Heading5}
### The VGA's Set/Reset Circuitry
At last we come to the final aspect of data flow through the GC on write
mode 0 writes: the set/reset circuitry. Figure 25.3 shows data flow on a
@ -530,7 +530,7 @@ cseg ends
end start
```
#### Setting All Planes to a Single Color {#Heading6}
#### Setting All Planes to a Single Color
The set/reset circuitry can be used to force some planes to 0-bits and
others to 1-bits during a single write, while letting CPU data go to
@ -680,7 +680,7 @@ cseg ends
end start
```
#### Manipulating Planes Individually {#Heading7}
#### Manipulating Planes Individually
Listing 25.4 illustrates the use of set/reset to control only some,
rather than all, planes. Here, the set/reset circuitry forces plane 2 to
@ -826,7 +826,7 @@ you force all bits in each plane to either zero or one, or pass CPU data
through unchanged, on each write to display memory. As tools go,
set/reset is a handy one, and it'll pop up often in this book.
### Notes on Set/Reset {#Heading8}
### Notes on Set/Reset
The set/reset circuitry is not active in write modes 1 or 2. The Enable
Set/Reset register is inactive in write mode 3, but the Set/Reset
@ -845,7 +845,7 @@ discussed in the next chapter.
> selected planes; the set/reset value is then processed in exactly the
> same way that CPU data normally is.
### A Brief Note on Word OUTs {#Heading9}
### A Brief Note on Word OUTs
In the early days of the EGA and VGA, there was considerable debate
about whether it was safe to do word `OUT`s (`OUT DX,AX`) to set

View file

@ -11,9 +11,9 @@ pages: 481-497
---
## Chapter 26\
VGA Write Mode 3 {#Heading1}
VGA Write Mode 3
### The Write Mode That Grows on You {#Heading2}
### The Write Mode That Grows on You
Over the last three chapters, we've covered the VGA's write path from
stem to stern—with one exception. Thus far, we've only looked at how
@ -31,7 +31,7 @@ in the next chapter, but right now I want to focus on write mode 3,
which can be confusing at first, but turns out to be quite a bit more
powerful than one might initially think.
### A Mode Born in Strangeness {#Heading3}
### A Mode Born in Strangeness
Write mode 3 is strange indeed, and its use is not immediately obvious.
The first time I encountered write mode 3, I understood immediately how
@ -806,7 +806,7 @@ of the X-Sharp library. Nonetheless, the performance benefit of this
approach can be a speedup of as much as four times—all thanks to the
decidedly quirky but surprisingly powerful and flexible write mode 3.
### A Note on Preserving Register Bits {#Heading4}
### A Note on Preserving Register Bits
If you take a quick look, you'll see that the code in Listing 26.1 uses
the readable register feature of the VGA to preserve reserved bits and

View file

@ -11,9 +11,9 @@ pages: 499-521
---
## Chapter 27\
Yet Another VGA Write Mode {#Heading1}
Yet Another VGA Write Mode
### Write Mode 2, Chunky Bitmaps,and Text-Graphics Coexistence {#Heading2}
### Write Mode 2, Chunky Bitmaps,and Text-Graphics Coexistence
In the last chapter, we learned about the markedly peculiar write mode 3
of the VGA, after having spent three chapters learning the ins and outs
@ -31,7 +31,7 @@ ever imagine.
Let's start with the easy stuff, write mode 2, and save the read modes
for the next chapter.
### Write Mode 2 and Set/Reset {#Heading3}
### Write Mode 2 and Set/Reset
Remember how set/reset works? Good, because that's pretty much how write
mode 2 works. (You *don't* remember? Well, I'll provide a brief
@ -68,7 +68,7 @@ nonetheless, I suspect that some additional explanation of an admittedly
non-obvious mode wouldn't hurt. Let's follow the CPU byte through the
VGA in write mode 2, step by step.
#### A Byte's Progress in Write Mode 2 {#Heading4}
#### A Byte's Progress in Write Mode 2
Figure 27.1 shows the write mode 2 data path. The CPU byte comes into
the VGA and is split into four separate bits, one for each plane. Bits
@ -130,7 +130,7 @@ on the VGA is to read the Graphics Mode register, mask off bits 1 and 0,
OR in 00000010b (02H), and write the result back to the Graphics Mode
register, thereby leaving the other bits in the register undisturbed.
#### Copying Chunky Bitmaps to VGA Memory Using Write Mode 2 {#Heading5}
#### Copying Chunky Bitmaps to VGA Memory Using Write Mode 2
Let's take a look at two examples of write mode 2 in action. Listing
27.1 presents a program that uses write mode 2 to copy a graphics image
@ -406,7 +406,7 @@ to illustrate the mechanics of write mode 2.
> time, nasty transient color effects can occur as one plane becomes
> visibly changed before other planes have been modified.
#### Drawing Color-Patterned Lines Using Write Mode 2 {#Heading6}
#### Drawing Color-Patterned Lines Using Write Mode 2
A more serviceable use of write mode 2 is shown in the program presented
in Listing 27.2. The program draws multicolored horizontal, vertical,
@ -764,7 +764,7 @@ Code ends
end Start
```
### When to Use Write Mode 2 and When to Use Set/Reset {#Heading7}
### When to Use Write Mode 2 and When to Use Set/Reset
As indicated earlier, write mode 2 and set/reset are functionally
interchangeable. Write mode 2 lends itself to more efficient
@ -785,7 +785,7 @@ the value written to some planes to a fixed value while allowing the CPU
byte to modify other planes. This is the mode of operation when
set/reset is enabled for some but not all planes.
### Mode 13H—320x200 with 256 Colors {#Heading8}
### Mode 13H—320x200 with 256 Colors
I'm going to take a minute—and I do mean a minute—to discuss the
programming model for mode 13H, the VGA's 320x200 256-color mode.
@ -803,7 +803,7 @@ program, especially given that some of the listings later in this book,
such as the antialiasing code in Chapter F on the companion CD-ROM, use
mode 13H.
### Flipping Pages from Text to Graphics and Back {#Heading9}
### Flipping Pages from Text to Graphics and Back
A while back, I got an interesting letter from Phil Coleman, of La
Jolla, who wrote:

View file

@ -11,9 +11,9 @@ pages: 523-537
---
## Chapter 28\
Reading VGA Memory {#Heading1}
Reading VGA Memory
### Read Modes 0 and 1, and the Color Don't Care Register {#Heading2}
### Read Modes 0 and 1, and the Color Don't Care Register
Well, it's taken five chapters, but we've finally covered the data write
path and all four write modes of the VGA. Now it's time to tackle the
@ -27,7 +27,7 @@ straightforward? Well...no. But then, clearing up the mysteries of VGA
programming is what this part of the book is all about, so let's get
started.
### Read Mode 0 {#Heading3}
### Read Mode 0
Read mode 0 is actually relatively uncomplicated, given that you
understand the four-plane nature of the VGA. (If you don't understand
@ -335,7 +335,7 @@ register affects CPU *writes* to VGA memory in any way.
> short, whenever the CPU reads VGA memory in any read mode, all four
> planes are read and all four latches are always loaded.
### Read Mode 1 {#Heading4}
### Read Mode 1
Read mode 0 is the workhorse read mode, but it's got an annoying
limitation: Whenever you want to determine the color of a given pixel in
@ -537,7 +537,7 @@ code ends
end Start
```
### When all Planes "Don't Care" {#Heading5}
### When all Planes "Don't Care"
Still and all, there aren't all that many uses for basic color compare
operations. There is, however, a genuinely odd application of read mode

View file

@ -11,9 +11,9 @@ pages: 539-559
---
## Chapter 29\
Saving Screens and Other VGA Mysteries {#Heading1}
Saving Screens and Other VGA Mysteries
### Useful Nuggets from the VGA Zen File {#Heading2}
### Useful Nuggets from the VGA Zen File
There are a number of VGA graphics topics that aren't quite involved
enough to warrant their own chapters, yet still cause a fair amount of
@ -25,7 +25,7 @@ writing VGA control registers.
That's a lot of ground to cover, so let's get started!
### Saving and Restoring EGA and VGA Screens {#Heading3}
### Saving and Restoring EGA and VGA Screens
The memory architectures of EGAs and VGAs are similar enough to treat
both together in this regard. The basic principle for saving EGA and VGA
@ -400,7 +400,7 @@ directly.
> VGA, of course, you can just read the registers out before you change
> them, then put them back the way you found them when you're done.
### 16 Colors out of 64 {#Heading4}
### 16 Colors out of 64
How does one produce the 64 colors from which the 16 colors displayed by
the EGA can be chosen? The answer is simple enough: There's a BIOS
@ -770,7 +770,7 @@ Code ends
end Start
```
### Overscan {#Heading5}
### Overscan
While we're at it, I'm going to touch on overscan. Overscan is the color
of the border of the display, the rectangular area around the edge of
@ -789,7 +789,7 @@ subfunction 1.
> border in all modes; all you need do is set the overscan color on any
> VGA to see the border.
### A Bonus Blanker {#Heading6}
### A Bonus Blanker
An interesting bonus: The Attribute Controller provides a very
convenient way to blank the screen, in the form of the aforementioned
@ -898,7 +898,7 @@ capabilities, which are supported by another set of BIOS functions, can
be used to produce stunning color effects, as we'll see when we cover
them starting in Chapter 33.
### Modifying VGA Registers {#Heading7}
### Modifying VGA Registers
EGA registers are not readable. VGA registers are readable. This
revelation will not come as news to most of you, but many programmers

View file

@ -11,9 +11,9 @@ pages: 561-585
---
## Chapter 30\
Video Est Omnis Divisa {#Heading1}
Video Est Omnis Divisa
### The Joys and Galling Problems of Using Split Screens on the EGA and VGA {#Heading2}
### The Joys and Galling Problems of Using Split Screens on the EGA and VGA
The ability to split the screen into two largely independent portions
one—displayed above the other on the screen—is one of the more
@ -33,7 +33,7 @@ we do have some ground to cover.
Let's start with the basic operation of the split screen.
### How the Split Screen Works {#Heading3}
### How the Split Screen Works
The *operation* of the split screen is simplicity itself. A split screen
start scan line value is programmed into two EGA registers or three VGA
@ -97,7 +97,7 @@ line displayed; the safest such approach is to set all bits of the split
screen start scan line to 1. (That is, in fact, the split screen start
scan line value programmed by the BIOS during a mode set.)
#### The Split Screen in Action {#Heading4}
#### The Split Screen in Action
All of these points are illustrated by Listing 30.1. Listing 30.1 fills
display memory starting at offset zero (the split screen area of memory)
@ -509,7 +509,7 @@ Code ends
end Start
```
#### VGA and EGA Split-Screen Operation Don't Mix {#Heading5}
#### VGA and EGA Split-Screen Operation Don't Mix
You must set the `IS_VGA` equate at the start of Listing 30.1
correctly for the adapter the code will run on in order for the program
@ -537,7 +537,7 @@ highest-resolution mode the VGA and EGA share. That's not the only mode
the split screen works in, however. In fact, it works in *all* modes, as
we'll see later.
### Setting the Split-Screen-Related Registers {#Heading6}
### Setting the Split-Screen-Related Registers
Setting the split-screen-related registers is not as simple a matter as
merely outputting the right values to the right registers; timing is
@ -585,7 +585,7 @@ aware that the VGA supports 70 Hz frame rates in all non-480-scan-line
modes, while the VGA in 480-scan-line-modes and the EGA in all color
modes support 60 Hz frame rates.
### The Problem with the EGA Split Screen {#Heading7}
### The Problem with the EGA Split Screen
I mentioned earlier that the EGA's split screen is a little buggy. How?
you may well ask, particularly given that Listing 30.1 illustrates that
@ -618,7 +618,7 @@ split screen is on. This isn't a bug—it's just one of the many areas in
which the VGA's designers learned from the shortcomings of the EGA and
went the EGA one better.
### Split Screen and Panning {#Heading8}
### Split Screen and Panning
Back in Chapter 23, I presented a program that performed smooth
horizontal panning. Smooth horizontal panning consists of two parts:
@ -661,7 +661,7 @@ can be used to produce an attractive "streaming tape" effect in the
normal screen while the split screen is used to display non-moving
information.
#### The Split Screen and Horizontal Panning: An Example {#Heading9}
#### The Split Screen and Horizontal Panning: An Example
Listing 30.2 illustrates the interaction of horizontal smooth panning
with the split screen, as well as the suppression of pel panning in the
@ -1107,7 +1107,7 @@ Codeends
endStart
```
### Notes on Setting and Reading Registers {#Heading10}
### Notes on Setting and Reading Registers
There are a few interesting points regarding setting and reading
registers to be made about Listing 30.2. First, bit 5 of the AC Index
@ -1190,7 +1190,7 @@ What if you wanted to pan faster? Well, you could of course just move
two pixels at a time rather than one; I assure you no one will ever
notice when you're panning at a rate of 10 or more times per second.
### Split Screens in Other Modes {#Heading11}
### Split Screens in Other Modes
So far we've only discussed the split screen in mode 10H. What about
other modes? Generally, the split screen works in any mode; the basic
@ -1226,7 +1226,7 @@ noticeable on-screen effects depends on the text displayed by a
particular application; for example, there should be no problem if the
split screen has a border of blanks on the left side.
### How Safe? {#Heading12}
### How Safe?
So, how safe *is* it to use the split screen? My opinion is that it's
perfectly safe, although I'd welcome input from people with extensive

View file

@ -11,9 +11,9 @@ pages: 587-605
---
## Chapter 31\
Higher 256-Color Resolution on the VGA {#Heading1}
Higher 256-Color Resolution on the VGA
### When Is 320x200 Really 320x400? {#Heading2}
### When Is 320x200 Really 320x400?
One of the more appealing features of the VGA is its ability to display
256 simultaneous colors. Unfortunately, one of the *less* appealing
@ -43,7 +43,7 @@ games use.
So. Let's get started.
### Why 320x200? Only IBM Knows for Sure {#Heading3}
### Why 320x200? Only IBM Knows for Sure
The first question, of course, is, "How can it be possible to get higher
256-color resolutions out of the VGA?" After all, there were no unused
@ -86,7 +86,7 @@ designing the chip. Whatever the reason, mode 13H is really a
400-scan-line mode masquerading as a 200-scan-line mode, and we can
readily end that masquerade.
### 320x400 256-Color Mode {#Heading4}
### 320x400 256-Color Mode
Okay, what's so great about 320x400 256-color mode? Two things: easy,
safe mode sets and page flipping.
@ -122,7 +122,7 @@ That's why I like 320x400 256-color mode. The next step is to understand
how display memory is organized in 320x400 mode, and that's not so
simple.
#### Display Memory Organization in 320x400 Mode {#Heading5}
#### Display Memory Organization in 320x400 Mode
First, let's look at why display memory must be organized differently in
320x400 256-color mode than in mode 13H. The designers of the VGA
@ -187,7 +187,7 @@ turned off, and selecting byte mode for video data display. All that's
done in the `Set320x400Mode` subroutine in Listing 31.1, which we'll
discuss next.
#### Reading and Writing Pixels {#Heading6}
#### Reading and Writing Pixels
The basic graphics functions in any mode are functions to read and write
single pixels. Any more complex function can be built on these
@ -624,7 +624,7 @@ an adequately fast—and often *very* fast—version for 320x400 mode of
whatever graphics function you need. If you're not all that concerned
with speed, `WritePixel` and `ReadPixel` should meet your needs.
### Two 256-Color Pages {#Heading7}
### Two 256-Color Pages
Listing 31.2 demonstrates the two pages of 320x400 256-color mode by
drawing slanting color bars in page 0, then drawing color bars slanting
@ -911,7 +911,7 @@ The displays produced by Listing 31.2 make it clear that 320x400
256-color mode can produce effects that are simply not possible in any
16-color mode.
### Something to Think About {#Heading8}
### Something to Think About
You can, if you wish, use the display memory organization of 320x400
mode in 320x200 mode by modifying `Set320x400Mode` to leave the

View file

@ -11,9 +11,9 @@ pages: 607-622
---
## Chapter 32\
Be It Resolved: 360x480 {#Heading1}
Be It Resolved: 360x480
### Taking 256-Color Modes About as Far as the Standard VGA Can Take Them {#Heading2}
### Taking 256-Color Modes About as Far as the Standard VGA Can Take Them
In the last chapter, we learned how to coax 320x400 256-color resolution
out of a standard VGA. At the time, I noted that the VGA was actually
@ -36,7 +36,7 @@ the line-drawing code that we'll develop in Chapter 35. Together, those
routines will make a pretty nifty demo of the capabilities of 360x480
256-color mode.
### Extended 256-Color Modes: What's Not to Like? {#Heading3}
### Extended 256-Color Modes: What's Not to Like?
When last we left 256-color programming, we had found that the standard
256-color mode, mode 13H, which officially offers 320x200 resolution,
@ -101,7 +101,7 @@ undocumented, offers a better combination of resolution and color; even
In other words, 360x480 256-color mode is worth considering—so let's
have a look.
### 360x480 256-Color Mode {#Heading4}
### 360x480 256-Color Mode
I'm going to start by showing you 360x480 256-color mode in action,
after which we'll look at how it works. I suspect that once you see what
@ -585,7 +585,7 @@ significant chunk of the market for your code.)
Now that we've seen the wonders of which our new mode is capable, let's
take the time to understand how it works.
### How 360x480 256-Color Mode Works {#Heading5}
### How 360x480 256-Color Mode Works
In describing 360x480 256-color mode, I'm going to assume that you're
familiar with the discussion of 320x400 256-color mode in the last
@ -597,7 +597,7 @@ myself when the goods are just a few page flips (the paper kind) away.
stretched in both dimensions. Let's look at the vertical stretching
first, since that's the simpler of the two.
#### 480 Scan Lines per Screen: A Little Slower, But No Big Deal {#Heading6}
#### 480 Scan Lines per Screen: A Little Slower, But No Big Deal
There's nothing unusual about 480 scan lines; standard modes 11H and 12H
support that vertical resolution. The number of scan lines has nothing
@ -620,7 +620,7 @@ isn't *bad*—that's the only refresh rate the EGA ever supported, and the
EGA was the industry standard in its time—but it does tend to flicker a
little more and so is a little harder on the eyes than 70 Hz.
#### 360 Pixels per Scan Line: No Mean Feat {#Heading7}
#### 360 Pixels per Scan Line: No Mean Feat
Converting from 320 to 360 pixels per scan line is more difficult than
converting from 400 to 480 scan lines per screen. None of the VGA's
@ -682,7 +682,7 @@ resolution, as well.
Once all that's done, the VGA is in 360x480 mode, awaiting our every
high-resolution 256-color graphics whim.
#### Accessing Display Memory in 360x480 256-Color Mode {#Heading8}
#### Accessing Display Memory in 360x480 256-Color Mode
Setting up for 360x480 256-color mode proved to be quite a task. Is
drawing in this mode going to be as difficult?

View file

@ -11,9 +11,9 @@ pages: 623-636
---
## Chapter 33\
Yogi Bear and Eurythmics Confront VGA Colors {#Heading1}
Yogi Bear and Eurythmics Confront VGA Colors
### The Basics of VGA Color Generation {#Heading2}
### The Basics of VGA Color Generation
Kevin Mangis wants to know about the VGA's 4-bit to 8-bit to 18-bit
color translation. Mansur Loloyan would like to find out how to generate
@ -60,7 +60,7 @@ and the Digital Differential Analyzer," by Tim Paterson, is a good
article about fast circle drawing, a topic we'll tackle soon. All in
all, the dog days of 1990 were good times for graphics.
### VGA Color Basics {#Heading3}
### VGA Color Basics
Briefly put, the VGA color translation circuitry takes in one 4- or
8-bit pixel value at a time and translates it into three 6-bit values,
@ -69,7 +69,7 @@ analog levels and sent to the monitor. Seems simple enough, doesn't it?
Unfortunately, nothing is ever that simple on the VGA, and color
translation is no exception.
#### The Palette RAM {#Heading4}
#### The Palette RAM
The color path in the VGA involves two stages, as shown in Figure 33.1.
The first stage fetches a 4-bit pixel from display memory and feeds it
@ -91,7 +91,7 @@ attribute. In 256-color mode, which we'll get to eventually, the palette
RAM is not a factor from the programmer's perspective and should be left
alone.
#### The DAC {#Heading5}
#### The DAC
Once the EGA-compatible palette RAM has fulfilled its karma and
performed 4-bit to 6-bit translation on a pixel, the resulting value is
@ -125,7 +125,7 @@ higher the number, the brighter the color, with 0 turning that color off
in the pixel and 63 (3FH) making that color maximum brightness. Got all
that?
#### Color Paging with the Color Select Register {#Heading6}
#### Color Paging with the Color Select Register
"Wait a minute," you say bemusedly. "Aren't you missing some bits
between the palette RAM and the DAC?" Indeed I am. The palette RAM puts
@ -173,7 +173,7 @@ out of the circuit and simplifies life something wonderful. The palette
RAM exists solely for EGA compatibility, and serves no useful purpose
that I know of for VGA-only color programming.
#### 256-Color Mode {#Heading7}
#### 256-Color Mode
So far I've spoken only of 16-color modes; what of 256-color modes?
@ -193,7 +193,7 @@ VGA chip to the DAC come from display memory. Therefore, there is no
color paging in 256-color mode. Of course, that makes sense given that
all 256 DAC registers are simultaneously in use in 256-color mode.
#### Setting the Palette RAM {#Heading8}
#### Setting the Palette RAM
The palette RAM can be programmed either directly or through BIOS
interrupt 10H, function 10H. I strongly recommend using the BIOS
@ -227,7 +227,7 @@ Having said that, let's leave the palette RAM behind (presumably in a
pass-through state) and move on to the DAC, which is the right place to
do color translation on the VGA.
#### Setting the DAC {#Heading9}
#### Setting the DAC
Like the palette RAM, the DAC registers can be set either directly or
through the BIOS. Again, the BIOS should be used whenever possible, but
@ -264,7 +264,7 @@ consists of three bytes; the first byte is a 6-bit red component, the
second byte is a 6-bit green component, and the third byte is a 6-bit
blue component, as illustrated by Listing 33.1.
### If You Can't Call the BIOS, Who Ya Gonna Call? {#Heading10}
### If You Can't Call the BIOS, Who Ya Gonna Call?
Although the palette RAM and DAC registers should be set through the
BIOS whenever possible, there are times when the BIOS is not the best
@ -340,7 +340,7 @@ In the meantime, if you can use the BIOS to set the DAC, do so; then you
won't have to worry about the real and potential complications of
setting the DAC directly.
### An Example of Setting the DAC {#Heading11}
### An Example of Setting the DAC
This chapter has gotten about as big as a chapter really ought to be;
the VGA color saga will continue in the next few. Quickly, then, Listing

View file

@ -11,9 +11,9 @@ pages: 637-652
---
## Chapter 34\
Changing Colors without Writing Pixels {#Heading1}
Changing Colors without Writing Pixels
### Special Effects through Realtime Manipulation of DAC Colors {#Heading2}
### Special Effects through Realtime Manipulation of DAC Colors
Sometimes, strange as it may seem, the harder you try, the less you
accomplish. Brute force is fine when it suffices, but it does not always
@ -31,7 +31,7 @@ by cleaning up some odds and ends about VGA color.
There's a lot to be said about loading the DAC, so let's dive right in
and see where the complications lie.
### Color Cycling {#Heading3}
### Color Cycling
As we've learned in past chapters, the VGA's DAC contains 256 storage
locations, each holding one 18-bit value representing an RGB color
@ -78,7 +78,7 @@ In short, color cycling is really the method of choice for dynamic color
effects only in 256-color mode—but, regrettably, color cycling is at its
least reliable and capable in that mode, as we'll see next.
### The Heart of the Problem {#Heading4}
### The Heart of the Problem
Here's the problem with loading the entire DAC repeatedly: The DAC
contains 256 color storage locations, each loaded via either 3 or 4
@ -122,7 +122,7 @@ let you explore for yourself the extent of the problem on computers in
which you're interested. First, though, we must address *another* DAC
loading problem: the BIOS.
#### Loading the DAC via the BIOS {#Heading5}
#### Loading the DAC via the BIOS
The DAC can be loaded either directly or through subfunctions 10H (for a
single DAC register) or 12H (for a block of DAC registers) of the BIOS
@ -194,7 +194,7 @@ cycle by calling the BIOS.
Which is not to say that loading the DAC directly is a picnic either, as
we'll see next.
#### Loading the DAC Directly {#Heading6}
#### Loading the DAC Directly
So we must load the DAC directly in order to perform color cycling. The
DAC is loaded directly by sending (with an `OUT` instruction) the
@ -233,7 +233,7 @@ blame me if you get a call from someone who's claims that your program
sometimes turns their screen into something resembling month-old yogurt.
It's not really your fault, of course—but try explaining that to *them!*
### A Test Program for Color Cycling {#Heading7}
### A Test Program for Color Cycling
Anyway, the choice of how to load the DAC is yours. Given that I'm not
providing you with any hard-and-fast rules (mainly because there don't
@ -584,7 +584,7 @@ force isn't appropriate to the task of color cycling. That doesn't mean
that color cycling can't be used, just that subtler approaches must be
employed. Let's look at some of those alternatives.
### Color Cycling Approaches that Work {#Heading8}
### Color Cycling Approaches that Work
First of all, I'd like to point out that when color cycling does work,
it's a thing of beauty. Assemble Listing 34.1 so that it doesn't use the
@ -680,7 +680,7 @@ That's what *I'd* do. Don't let yourself be held back by my limited
imagination, though! Color cycling may be the most complicated of all
the color control techniques, but it's also the most powerful.
### Odds and Ends {#Heading9}
### Odds and Ends
In my experience, when relying on the autoincrementing feature while
loading the DAC, the Write Index register wraps back from 255 to 0, and
@ -694,7 +694,7 @@ understand exactly how your resources behave, and I never know when one
of you might come up with a serviceable application for any particular
quirk.
#### The DAC Mask {#Heading10}
#### The DAC Mask
There's one register in the DAC that I haven't mentioned yet, the DAC
Mask register at 03C6H. The operation of this register is simple but
@ -710,7 +710,7 @@ DAC location 0 is looked up for every pixel, and the entire screen
displays the color stored in DAC location 0. This makes setting the DAC
Mask register to 0 a quick and easy way to blank the screen.
#### Reading the DAC {#Heading11}
#### Reading the DAC
The DAC can be read directly, via the DAC Read Index register at 3C7H
and the DAC Data register at 3C9H, in much the same way as it can be
@ -742,7 +742,7 @@ conditionally assembling to either guard against interrupts or not and
to use `REP INSB` or not. As you can see, reading the DAC settings is
very much symmetric with setting the DAC.
#### Cycling Down {#Heading12}
#### Cycling Down
And so, at long last, we come to the end of our discussion of color
control on the VGA. If it has been more complex than anyone might have

View file

@ -11,9 +11,9 @@ pages: 653-678
---
## Chapter 35\
Bresenham Is Fast, and Fast Is Good {#Heading1}
Bresenham Is Fast, and Fast Is Good
### Implementing and Optimizing Bresenham's Line-Drawing Algorithm {#Heading2}
### Implementing and Optimizing Bresenham's Line-Drawing Algorithm
For all the complexity of graphics design and programming, surprisingly
few primitive functions lie at the heart of most graphics software.
@ -73,7 +73,7 @@ Notwithstanding, the line-drawing implementation in Listing 35.3 is
plenty fast enough for most purposes, so let's get the discussion
underway.
### The Task at Hand {#Heading3}
### The Task at Hand
There are two important characteristics of any line-drawing function.
First, it must draw a reasonable approximation of a line. A computer
@ -124,7 +124,7 @@ floating-point operations, no divides, and no multiplies inside the
line-drawing loop. Moreover, it can be implemented with surprisingly
little code.
### Bresenham's Line-Drawing Algorithm {#Heading4}
### Bresenham's Line-Drawing Algorithm
The key to grasping Bresenham's algorithm is to understand that when
drawing an approximation of a line on a finite-resolution display, each
@ -243,7 +243,7 @@ under the name *Computer Graphics: Principles and Practice*
integer-only, divide-free version of the algorithm, as well as Pascal
code for drawing lines in one of the eight possible octants.
#### Strengths and Weaknesses {#Heading5}
#### Strengths and Weaknesses
The overwhelming strength of Bresenham's line-drawing algorithm is
speed. With no divides, no floating-point operations, and no need for
@ -266,7 +266,7 @@ acceptance the algorithm is certainly good enough.
Then, too, users hate waiting for their computer to finish drawing. By
any standard of drawing performance, Bresenham's algorithm excels.
### An Implementation in C {#Heading6}
### An Implementation in C
It's time to get down and look at some actual working code. Listing 35.1
is a C implementation of Bresenham's line-drawing algorithm for modes
@ -556,7 +556,7 @@ void main()
}
```
#### Looking at EVGALine {#Heading7}
#### Looking at EVGALine
The `EVGALine` function itself performs four operations. `EVGALine`
first sets up the VGA's hardware so that all pixels drawn will be in the
@ -654,7 +654,7 @@ modularity would improve, speed would suffer markedly.
![**Figure 35.5**  *EVGALine's decision logic.*](images/35-05.jpg)
#### Drawing Each Line {#Heading8}
#### Drawing Each Line
The `Octant0` and `Octant1` functions draw lines for which
|`DeltaX`| is greater than `DeltaY` and lines for which |`DeltaX`|
@ -685,7 +685,7 @@ coordinate is advanced by either 1 or -1, depending on the value of
`XDirection`. (This makes it possible for `Octant1` to draw lines in
both octant 1 and octant 2.)
#### Drawing Each Pixel {#Heading9}
#### Drawing Each Pixel
At the core of `Octant0` and `Octant1` is a pixel-drawing function,
`EVGADot`. `EVGADot` draws a pixel at the specified coordinates in
@ -765,7 +765,7 @@ pixel-drawing function for a different adapter, or a fundamentally
different mode such as a 256-color SuperVGA mode, remember to remove the
hardware-dependent `outportb` lines in `EVGALine` itself.
### Comments on the C Implementation {#Heading10}
### Comments on the C Implementation
`EVGALine` does no error checking whatsoever. My assumption in writing
`EVGALine` was that it would be ultimately used as the lowest-level
@ -806,7 +806,7 @@ times the speed?
Given which, a high-speed assembly language version of `EVGALine`
would seem to be a logical next step.
### Bresenham's Algorithm in Assembly {#Heading11}
### Bresenham's Algorithm in Assembly
Listing 35.3 is a high-performance implementation of Bresenham's
algorithm, written entirely in assembly language. The code is callable

View file

@ -11,9 +11,9 @@ pages: 679-693
---
## Chapter 36\
The Good, the Bad, and the Run-Sliced {#Heading1}
The Good, the Bad, and the Run-Sliced
### Faster Bresenham Lines with Run-Length Slice Line Drawing {#Heading2}
### Faster Bresenham Lines with Run-Length Slice Line Drawing
Years ago, I worked at a company that asked me to write blazingly fast
line-drawing code for an AutoCAD driver. I implemented the basic
@ -107,7 +107,7 @@ algorithm, which just happens to be an excellent example of a minimized
state machine. In case you're fuzzy on the good/bad performance thing,
that's "good"—as in *fast*.
### Run-Length Slice Fundamentals {#Heading3}
### Run-Length Slice Fundamentals
First off, I have a confession to make: I'm not sure that the algorithm
I'll discuss is actually, precisely Bresenham's run-length slice
@ -171,7 +171,7 @@ redundant work is preferable.
![**Figure 36.3**  *Runs in a slope 1/3.5 line.*](images/36-03.jpg)
### Run-Length Slice Implementation {#Heading4}
### Run-Length Slice Implementation
We know that for any line, a given run will always be one of two
possible lengths. How, though, do we know which length to select?
@ -242,7 +242,7 @@ actually write the pixel to display memory.
That's good.
### Run-Length Slice Details {#Heading5}
### Run-Length Slice Details
A couple of run-length slice implementation details yet remain. First is
the matter of how error-term turnover is detected. This is done in much

View file

@ -11,9 +11,9 @@ pages: 695-706
---
## Chapter 37\
Dead Cats and Lightning Lines {#Heading1}
Dead Cats and Lightning Lines
### Optimizing Run-Length Slice Line Drawing in a Major Way {#Heading2}
### Optimizing Run-Length Slice Line Drawing in a Major Way
As I write this, the wife, the kid, and I are in the throes of yet
another lightning-quick transcontinental move, this time to Redmond,
@ -56,7 +56,7 @@ Okay, but what's the point? The point is, if it isn't broken, don't fix
it. And if it is broken, maybe that's all right, too. Which brings us,
neat as a pin, to the topic of drawing lines in a serious hurry.
### Fast Run-Length Slice Line Drawing {#Heading3}
### Fast Run-Length Slice Line Drawing
In the last chapter, we examined the principles of run-length slice line
drawing, which draws lines a run at a time rather than a pixel at a
@ -418,7 +418,7 @@ _LineDraw endp
end
```
#### How Fast Is Fast? {#Heading4}
#### How Fast Is Fast?
Your first question is likely to be the following: Just how fast is
Listing 37.1? Is it optimized to the hilt or just pretty fast? The quick
@ -483,7 +483,7 @@ basically a waste of time.
Profile before you optimize.
#### Further Optimizations {#Heading5}
#### Further Optimizations
Following is a quick tour of some of the many possible further
optimizations to Listing 37.1.

View file

@ -11,9 +11,9 @@ pages: 707-721
---
## Chapter 38\
The Polygon Primeval {#Heading1}
The Polygon Primeval
### Drawing Polygons Efficiently and Quickly {#Heading2}
### Drawing Polygons Efficiently and Quickly
*"Give me but one firm spot on which to stand, and I will move the
Earth."*
@ -44,7 +44,7 @@ boost performance into the realm of the sublime.
And slow computer graphics is scarcely worth the bother.
### Filled Polygons {#Heading3}
### Filled Polygons
A polygon is simply a shape formed by lines laid end to end to form a
continuous, closed path. A polygon is filled by setting all pixels
@ -79,7 +79,7 @@ widely useful and will serve well to introduce some of the subtler
complexities of polygon drawing, not the least of which is the slippery
concept of "inside."
#### Which Side Is Inside? {#Heading4}
#### Which Side Is Inside?
The basic principle of polygon filling is decomposing each polygon into
a series of horizontal lines, one for each horizontal row of pixels, or
@ -139,7 +139,7 @@ to the boundary lines just won't do for drawing images composed of
fitted-together polygons. And because fitting polygons together is
exactly what I have in mind, we need a different approach.
#### How Do You Fit Polygons Together? {#Heading5}
#### How Do You Fit Polygons Together?
How, then, do you fit polygons together? *Very* carefully. First, the
line-tracing algorithm must be adjusted so that it selects only those
@ -185,7 +185,7 @@ together seamlessly.
For our purposes, nonoverlapping polygons are the way to go, so let's
have at them.
### Filling Non-Overlapping Convex Polygons {#Heading6}
### Filling Non-Overlapping Convex Polygons
Without further ado, Listing 38.1 contains a function,
`FillConvexPolygon`, that accepts a list of points that describe a
@ -658,7 +658,7 @@ Once the two edges are scan-converted, the whole line list is passed to
Finis.
### Oddball Cases {#Heading7}
### Oddball Cases
Listing 38.1 handles zero-length segments (multiple vertices at the same
location) by ignoring them, which will be useful down the road because

View file

@ -11,9 +11,9 @@ pages: 723-738
---
## Chapter 39\
Fast Convex Polygons {#Heading1}
Fast Convex Polygons
### Filling Polygons in a Hurry {#Heading2}
### Filling Polygons in a Hurry
In the previous chapter, we explored the surprisingly intricate process
of filling convex polygons. Now we're going to fill them an order of
@ -92,7 +92,7 @@ to understand how things work, especially when they're very visible
parts of the software you develop. That said, let's learn more about
filling convex polygons.
### Fast Convex Polygon Filling {#Heading3}
### Fast Convex Polygon Filling
In addressing the topic of filling convex polygons in the previous
chapter, the implementation we came up with met all of our functional
@ -118,7 +118,7 @@ time was spent drawing and the other half was spent tracing the polygon
edges (the time spent in `FillConvexPolygon` was relatively
minuscule), so we have our choice of where to begin optimizing.
#### Fast Drawing {#Heading4}
#### Fast Drawing
Let's start with drawing, which is easily sped up. The previous
chapter's code used a double-nested loop that called a draw-pixel
@ -239,7 +239,7 @@ time. There are cycles yet to be had in the drawing code, but as tracing
polygon edges now takes 92 percent of the polygon filling time, it's
logical to optimize the tracing code next.
#### Fast Edge Tracing {#Heading5}
#### Fast Edge Tracing
There's no secret as to why last chapter's `ScanEdge` was so slow: It
used floating point calculations. One secret of fast graphics is using
@ -401,7 +401,7 @@ void ScanEdge(int X1, int Y1, int X2, int Y2, int SetXStart,
}
```
### The Finishing Touch: Assembly Language {#Heading6}
### The Finishing Touch: Assembly Language
The C implementation in Listing 39.2 is now nearly 20 times as fast as
the original, which is good enough for most purposes. Still, it requires
@ -532,7 +532,7 @@ _DrawHorizontalLineList endp
end
```
#### Maximizing REP STOS {#Heading7}
#### Maximizing REP STOS
Listing 39.3 doesn't take the easy way out and use `REP STOSB` to fill
each scan line; instead, it uses `REP STOSW` to fill as many pixel
@ -549,7 +549,7 @@ word-at-a-time filling, resulting in extra overhead. For very small or
narrow polygons, that overhead might overwhelm the advantage of drawing
a word at a time, making plain old `REP STOSB` faster.
### Faster Edge Tracing {#Heading8}
### Faster Edge Tracing
Finally, Listing 39.4 is an assembly language version of `ScanEdge`.
Listing 39.4 is a relatively straightforward translation from C to

View file

@ -11,9 +11,9 @@ pages: 739-756
---
## Chapter 40\
Of Songs, Taxes, and the Simplicity of Complex Polygons {#Heading1}
Of Songs, Taxes, and the Simplicity of Complex Polygons
### Dealing with Irregular Polygonal Areas {#Heading2}
### Dealing with Irregular Polygonal Areas
Every so often, my daughter asks me to sing her to sleep. (If you've
ever heard me sing, this may cause you concern about either her hearing
@ -43,7 +43,7 @@ where everything fits together as if preordained.
Filling arbitrary polygons is such a case.
### Filling Arbitrary Polygons {#Heading3}
### Filling Arbitrary Polygons
In Chapter 38, I described three types of polygons: convex, nonconvex,
and complex. *The RenderMan Companion*, a terrific book by Steve Upstill
@ -73,7 +73,7 @@ all polygons; in such a case, the polygon filler will use the slow
complex-fill code even if the polygon is, in fact, a convex polygon. In
Chapter 41, I'll discuss one way to improve this situation.
#### Active Edges {#Heading4}
#### Active Edges
The basic premise of filling a complex polygon is that for a given scan
line, we determine all intersections between the polygon's edges and
@ -459,7 +459,7 @@ static void ScanOutAET(int YToScan, int Color) {
}
```
### Complex Polygon Filling: An Implementation {#Heading5}
### Complex Polygon Filling: An Implementation
Listing 40.1 just shown presents a function, `FillPolygon()`, that
fills polygons of all shapes. If `CONVEX_FILL_LINKED` is defined,
@ -665,7 +665,7 @@ this way elsewhere. The boundary filling approach in Foley and van Dam
is similar, but seems to me to not draw all boundary and vertex pixels
once and only once.
#### More on Active Edges {#Heading6}
#### More on Active Edges
Edges of zero height—horizontal edges and edges defined by two vertices
at the same location—never even make it into the GET in Listing 40.1. A
@ -674,7 +674,7 @@ never intersect a scan line; it can only run along the scan line, and
the span it runs along is defined not by that edge but by the edges that
connect to its endpoints.
#### Performance Considerations {#Heading7}
#### Performance Considerations
How fast is Listing 40.1? When drawing triangles on a 20-MHz 386, it's
less than one-fifth the speed of the fast convex polygon fill code.
@ -777,7 +777,7 @@ spent sorting the AET.
> example of the need to keep an overall perspective when comparing the
> theoretical characteristics of various approaches.
### Nonconvex Polygons {#Heading8}
### Nonconvex Polygons
Nonconvex polygons can be filled somewhat faster than complex polygons.
Because edges never cross or switch positions with other edges once
@ -789,7 +789,7 @@ slopes must be compared to determine which edge is leftmost. This is
certainly doable, but because of space limitations and limited
performance returns, I haven't implemented this in Listing 40.1.
#### Details, Details {#Heading9}
#### Details, Details
Every so often, a programming demon that I'd thought I'd forever laid to
rest arises to haunt me once again. A minor example of this—an imp, if

View file

@ -11,9 +11,9 @@ pages: 757-771
---
## Chapter 41\
Those Way-Down Polygon Nomenclature Blues {#Heading1}
Those Way-Down Polygon Nomenclature Blues
### Names Do Matter when You Conceptualize a Data Structure {#Heading2}
### Names Do Matter when You Conceptualize a Data Structure
After I wrote the columns on polygons in *Dr. Dobb's Journal* that
became Chapters 38-40, long-time reader Bill Huber wrote to take me to
@ -63,7 +63,7 @@ who could be among your most astute readers—those who already have been
trained in the same or a related field." Ditto. Likewise. *D'accord*.
And *mea culpa* ; I shall endeavor to watch my language in the future.
### Nomenclature in Action {#Heading3}
### Nomenclature in Action
Just to show you how much difference proper description and interchange
of ideas can make, consider the case of identifying convex polygons.

View file

@ -11,9 +11,9 @@ pages: 773-792
---
## Chapter 42\
Wu'ed in Haste; Fried, Stewed at Leisure {#Heading1}
Wu'ed in Haste; Fried, Stewed at Leisure
### Fast Antialiased Lines Using Wu's Algorithm {#Heading2}
### Fast Antialiased Lines Using Wu's Algorithm
The thought first popped into my head as I unenthusiastically picked
through the salad bar at a local "family" restaurant, trying to decide
@ -74,7 +74,7 @@ be accomplished on inexpensive, mass-market hardware with the proper
programming perspective. In short, it's a splendid example of
appropriate technology for PCs.
### Wu Antialiasing {#Heading3}
### Wu Antialiasing
Antialiasing, as we've been discussing for the past few chapters, is the
process of smoothing lines and edges so that they appear less jagged.
@ -128,7 +128,7 @@ possible drawing speed—of an AT-bus VGA. In short, Wu antialiasing is
about as fast an antialiased line approach as you could ever hope to
find for the VGA.
### Tracing and Intensity in One {#Heading4}
### Tracing and Intensity in One
Horizontal, vertical, and diagonal lines do not require Wu antialiasing
because they pass through the center of every pixel they meet; such
@ -331,7 +331,7 @@ void DrawWuLine(int X0, int Y0, int X1, int Y1, int BaseColor, int NumLevels,
}
```
### Sample Wu Antialiasing {#Heading5}
### Sample Wu Antialiasing
The true test of any antialiasing technique is how good it looks, so
let's have a look at Wu antialiasing in action. Listing 42.1 is a C
@ -929,7 +929,7 @@ _DrawWuLine endp
end
```
#### Notes on Wu Antialiasing {#Heading6}
#### Notes on Wu Antialiasing
Wu antialiasing can be applied to any curve for which it's possible to
calculate at each step the positions and intensities of two bracketing

View file

@ -11,9 +11,9 @@ pages: 793-815
---
## Chapter 43\
Bit-Plane Animation {#Heading1}
Bit-Plane Animation
### A Simple and Extremely Fast Animation Method for Limited Color {#Heading2}
### A Simple and Extremely Fast Animation Method for Limited Color
When it comes to computers, my first love is animation. There's nothing
quite like the satisfaction of fooling the eye and creating a miniature
@ -87,7 +87,7 @@ resources, and that you can do remarkable things if you understand those
resources and come up with creative ways to put them to work at specific
tasks.
### Bit-Planes: The Basics {#Heading3}
### Bit-Planes: The Basics
The underlying principle of bit-plane animation is extremely simple. The
VGA has four separate bit planes in modes 0DH, 0EH, 10H, and 12H. Plane
@ -141,7 +141,7 @@ You bet.
![**Figure 43.3**  *The problem of overlapping colors.*](images/43-03.jpg)
#### Stacking the Palette Registers {#Heading4}
#### Stacking the Palette Registers
Suppose that instead of viewing the four bits per pixel coming out of
display memory as selecting one of sixteen colors,we view those bits as
@ -217,7 +217,7 @@ chosen to make plane 0 the highest precedence only because it seems
simplest to think of plane 0 as appearing in front of plane 1, which is
in front of plane 2, which is in front of plane 3.
### Bit-Plane Animation in Action {#Heading5}
### Bit-Plane Animation in Action
Without further ado, Listing 43.1 shows bit-plane animation in action.
Listing 43.1 animates 13 rather large images (each 32 pixels on a side)
@ -793,7 +793,7 @@ Bit-plane animation with bit-aligned images and internal animation can
look truly spectacular. It's a sight worth seeing, particularly for
those who doubt the PC's worth when it comes to animation.
### Limitations of Bit-Plane Animation {#Heading6}
### Limitations of Bit-Plane Animation
As I've said, bit-plane animation is not perfect. For starters,
bit-plane animation can only be used in the VGA's planar modes, modes
@ -877,7 +877,7 @@ the images in a given plane marching along in step in a continuous band.
The images could never overlap, so bit-plane animation would produce
very high image quality.
### Shearing and Page Flipping {#Heading7}
### Shearing and Page Flipping
As Listing 43.1 runs, you may occasionally see an image shear, with the
top and bottom parts of the image briefly offset. This is a consequence
@ -942,7 +942,7 @@ conjunction with page flipping, bit-plane animation looks a little
better but is slower, and the overall animation scheme is more difficult
to implement and perhaps a bit less reliable on some computers.
### Beating the Odds in the Jaw-Dropping Contest {#Heading8}
### Beating the Odds in the Jaw-Dropping Contest
Bit-plane animation is neat stuff. Heck, good animation of *any* sort is
fun, and the PC is as good a place as any (well, almost any) to make

View file

@ -11,9 +11,9 @@ pages: 817-837
---
## Chapter 44\
Split Screens Save the Page Flipped Day {#Heading1}
Split Screens Save the Page Flipped Day
### 640x480 Page Flipped Animation in 64K...Almost {#Heading2}
### 640x480 Page Flipped Animation in 64K...Almost
Almost doesn't count, they say—at least in horseshoes and maybe a few
other things. This is especially true in digital circles, where if you
@ -38,7 +38,7 @@ groundwork first. Or maybe a lot of groundwork.
No horseshoes here.
#### A Plethora of Challenges {#Heading3}
#### A Plethora of Challenges
In its simplest terms, computer animation consists of rapidly redrawing
similar images at slightly differing locations, so that the eye
@ -66,7 +66,7 @@ invisible to the user; only the end result should ever be seen. Both of
these requirements are met by the program presented in Listings 44.1 and
44.2.
#### A Page Flipping Animation Demonstration {#Heading4}
#### A Page Flipping Animation Demonstration
The listings taken together form a sample animation program, in which a
single object bounces endlessly off other objects, with instructions and
@ -977,7 +977,7 @@ screens drawn and cross-referencing that to the BIOS timer count
periodically, accelerating the overall pace of the animation (moving
farther each time and the like) if updates are happening too slowly.
#### Enter the Split Screen {#Heading9}
#### Enter the Split Screen
So far, I've discussed page flipping in 640x350 mode. There's a reason
for that: 640x350 is the highest-resolution standard mode in which

View file

@ -11,9 +11,9 @@ pages: 839-857
---
## Chapter 45\
Dog Hair and Dirty Rectangles {#Heading1}
Dog Hair and Dirty Rectangles
### Different Angles on Animation {#Heading2}
### Different Angles on Animation
We brought our pets with us when we moved to Seattle. At about the same
time, our Golden Retriever, Sam, observed his third birthday. Sam is
@ -55,7 +55,7 @@ joyously knocks down any stranger who makes the mistake of glancing in
his direction, and will, quite possibly, be booked any day now on
suspicion of homicide by licking.
### Plus ça Change {#Heading3}
### Plus ça Change
Okay, you give up. What exactly does this have to do with graphics? I'm
glad you asked. The lesson to be learned from Sam, The Dog With A Brain
@ -86,7 +86,7 @@ least one pair of underwear without a single hole in it. Which brings
us, deus ex machina and the creek don't rise, to yet another animation
method: dirty-rectangle animation.
### VGA Access Times {#Heading4}
### VGA Access Times
Actually, before we get to dirty rectangles, I'd like to take you
through a quick refresher on VGA memory and I/O access times. I want to
@ -162,7 +162,7 @@ memory if you don't have to. Write each pixel once and only once.
It is indeed a strange concept: The key to fast graphics is staying away
from the graphics adapter as much as possible.
### Dirty-Rectangle Animation {#Heading5}
### Dirty-Rectangle Animation
The relative slowness of VGA hardware is part of the appeal of the
technique that I call "dirty-rectangle" animation, in which a complete
@ -192,7 +192,7 @@ solves these problems.
![**Figure 45.2**  *Dirty rectangle animation.*](images/45-02.jpg)
#### So Why Not Use Page Flipping? {#Heading6}
#### So Why Not Use Page Flipping?
Well, then, if we want good visual quality, why not use page flipping?
For one thing, not all adapters and all modes support page flipping. The
@ -234,7 +234,7 @@ happen, it's still possible to have the images in the various dirty
rectangles show up non-simultaneously. In my experience, this latter
phenomenon is not a serious problem, but do be aware of it.
### Dirty Rectangles in Action {#Heading7}
### Dirty Rectangles in Action
Listing 45.1 demonstrates dirty-rectangle animation. This is a very
simple implementation, in several respects. For one thing, it's written
@ -540,7 +540,7 @@ graphics and by items such as scoreboards and status screens, but look
closely and see if the animation region in your favorite game isn't
smaller than you thought.
### Hi-Res VGA Page Flipping {#Heading8}
### Hi-Res VGA Page Flipping
On a standard VGA, hi-res mode is mode 12H, which offers 640x480
resolution with 16 colors. That's a nice mode, with plenty of pixels,
@ -762,7 +762,7 @@ The 640x400 mode I've described here isn't exactly earthshaking, but it
can come in handy for page flipping and CGA emulation, and I'm sure that
some of you will find it useful at one time or another.
### Another Interesting Twist on Page Flipping {#Heading9}
### Another Interesting Twist on Page Flipping
I've spent a fair amount of time exploring various ways to do animation.
I thought I had pegged all the possible ways to do animation:

View file

@ -11,9 +11,9 @@ pages: 859-874
---
## Chapter 46\
Who Was that Masked Image? {#Heading1}
Who Was that Masked Image?
### Optimizing Dirty-Rectangle Animation {#Heading2}
### Optimizing Dirty-Rectangle Animation
Programming is, by and large, a linear process. One statement or
instruction follows another, in predictable sequences, with tiny
@ -61,7 +61,7 @@ We're strange thinking machines, but we're the best ones yet invented,
and it's worth learning how to tap our full potential. And with that,
it's back to dirty-rectangle animation.
#### Dirty-Rectangle Animation, Continued {#Heading3}
#### Dirty-Rectangle Animation, Continued
In the last chapter, Introduced the idea of dirty-rectangle animation.
This technique is an alternative to page flipping that's capable of
@ -618,7 +618,7 @@ RowLoop3:
end
```
#### Masked Images {#Heading4}
#### Masked Images
Masked images are rendered by drawing an object's pixels through a mask;
pixels are actually drawn only where the mask specifies that drawing is
@ -654,7 +654,7 @@ one color undrawable. Also, with a transparent color, it's not possible
to keep the same base image but use different masks, because the mask
information is embedded in the image data.
#### Internal Animation {#Heading5}
#### Internal Animation
I've added another feature essential to producing convincing animation:
*internal animation*, which is the process of changing the appearance of
@ -720,7 +720,7 @@ minimal cost. You might then decide to ignore overlapped drawing between
different images, which tends to be both less common and more expensive
to identify and handle.
#### Drawing Order and Visual Quality {#Heading7}
#### Drawing Order and Visual Quality
A final note on dirty-rectangle animation concerns the quality of the
displayed screen image. In the last chapter, we simply stuffed dirty

View file

@ -11,9 +11,9 @@ pages: 875-893
---
## Chapter 47\
Mode X: 256-Color VGA Magic {#Heading1}
Mode X: 256-Color VGA Magic
### Introducing the VGA's Undocumented "Animation-Optimal" Mode {#Heading2}
### Introducing the VGA's Undocumented "Animation-Optimal" Mode
At a book signing for my book *Zen of Code Optimization*, an attractive
young woman came up to me, holding my book, and said, "You're Michael
@ -60,7 +60,7 @@ two chapters are based on the *DDJ* columns that started it all back in
spawned a ton of games, and about which I still regularly get letters
and e-mail. Ladies and gentlemen, I give you...Mode X.
### What Makes Mode X Special? {#Heading3}
### What Makes Mode X Special?
Consider the strange case of the VGA's 320x256-color mode—Mode X—which
is undeniably complex to program and isn't even documented by IBM—but
@ -143,7 +143,7 @@ animation program that shows many of the features of Mode X in action.
The mode set code is the logical place to begin.
### Selecting 320x240 256-Color Mode {#Heading4}
### Selecting 320x240 256-Color Mode
We could, if we wished, write our own mode set code for Mode X from
scratch—but why bother? Instead, we'll let the BIOS do most of the work
@ -440,7 +440,7 @@ _ReadPixelX endp
end
```
### Designing from a Mode X Perspective {#Heading5}
### Designing from a Mode X Perspective
Listing 47.4 shows Mode X rectangle fill code. The plane is selected for
each pixel in turn, with drawing cycling from plane 0 to plane 3, then
@ -711,7 +711,7 @@ _FillRectangleX endp
end
```
### Hardware Assist from an Unexpected Quarter {#Heading6}
### Hardware Assist from an Unexpected Quarter
Listing 47.5 illustrates the benefits of designing code from a Mode X
perspective; this is the software aspect of Mode X optimization, which

View file

@ -11,9 +11,9 @@ pages: 895-911
---
## Chapter 48\
Mode X Marks the Latch {#Heading1}
Mode X Marks the Latch
### The Internals of Animation's Best Video Display Mode {#Heading2}
### The Internals of Animation's Best Video Display Mode
In the previous chapter, I introduced you to what I call Mode X, an
undocumented 320x240 256-color mode of the VGA. Mode X is distinguished
@ -320,7 +320,7 @@ handle, because the latches are four pixels wide; one possible solution
is expanding such patterns via repetition until they are
multiple-of-four widths.)
### Allocating Memory in Mode X {#Heading3}
### Allocating Memory in Mode X
Listing 48.2 raises some interesting questions about the allocation of
display memory in Mode X. In Listing 48.2, whenever a pattern is to be
@ -365,7 +365,7 @@ the screen, with the screen becoming a scrolling window onto that larger
bitmap. This technique has been used to good effect in a number of
animated games, with and without the use of Mode X.
### Copying Pixel Blocks within Display Memory {#Heading4}
### Copying Pixel Blocks within Display Memory
Another fine use for the latches is copying pixels from one place in
display memory to another. Whenever both the source and the destination
@ -588,7 +588,7 @@ memory-to-display memory copy routine can do us any good, we must have a
way to get pixel patterns from system memory into display memory, so
that they can then be copied with the fast copy routine.
#### Copying to Display Memory {#Heading5}
#### Copying to Display Memory
The final piece of the puzzle is the system memory to
display-memory-copy-routine shown in Listing 48.4. This routine assumes
@ -732,7 +732,7 @@ _CopySystemToScreenX endp
end
```
### Who Was that Masked Image Copier? {#Heading6}
### Who Was that Masked Image Copier?
At this point, it's getting to be time for us to take all the Mode X
tools we've developed, together with one more tool—masked image

View file

@ -11,9 +11,9 @@ pages: 913-930
---
## Chapter 49\
Mode X 256-Color Animation {#Heading1}
Mode X 256-Color Animation
### How to Make the VGA Really Get up and Dance {#Heading2}
### How to Make the VGA Really Get up and Dance
Okay—no amusing stories or informative anecdotes to kick off this
chapter; lotta ground to cover, gotta hurry—you're impatient, I can
@ -33,7 +33,7 @@ computing, as Jeff Duntemann's writings make manifest. No lighthearted
fluff for us; we have real work to do, for today we animate with 256
colors in Mode X.
### Masked Copying {#Heading3}
### Masked Copying
Over the past two chapters, we've put together most of the tools needed
to implement animation in the VGA's undocumented 320x240 256-color Mode
@ -212,7 +212,7 @@ _CopySystemToScreenMaskedX endp
end
```
#### Faster Masked Copying {#Heading4}
#### Faster Masked Copying
In the previous chapter we saw how the VGA's latches can be used to copy
four pixels at a time from one area of display memory to another in Mode
@ -511,7 +511,7 @@ typedef struct {
} MaskedImage;
```
#### Notes on Masked Copying {#Heading5}
#### Notes on Masked Copying
Listings 49.1 and 49.2, like all Mode X code I've presented, perform no
clipping, because clipping code would complicate the listings too much.
@ -541,7 +541,7 @@ used separate parameters for simplicity and flexibility.
> instruction, and most VGAs respond to `OUT`s much more slowly than to
> display memory writes.)
### Animation {#Heading6}
### Animation
Gosh. There's just no way I can discuss high-level animation
fundamentals in any detail here; I could spend an entire (and entirely
@ -564,7 +564,7 @@ Some of the code in this chapter was adapted for Mode X from the code in
Chapter 44—yet another reason to read that chapter before finishing this
one.
### Mode X Animation in Action {#Heading7}
### Mode X Animation in Action
Listing 49.5 ties together everything I've discussed about Mode X so far
in a compact but surprisingly powerful animation package. Listing 49.5
@ -893,7 +893,7 @@ _ShowPage endp
end
```
### Works Fast, Looks Great {#Heading8}
### Works Fast, Looks Great
We now end our exploration of Mode X, although we'll use it again
shortly for 3-D animation. Mode X admittedly has its complexities;

View file

@ -11,9 +11,9 @@ pages: 931-949
---
## Chapter 50\
Adding a Dimension {#Heading1}
Adding a Dimension
### 3-D Animation Using Mode X {#Heading2}
### 3-D Animation Using Mode X
When I first started programming micros, more than 11 years ago now,
there wasn't much money in it, or visibility, or anything you could call
@ -84,7 +84,7 @@ In a sense, I've saved the best for last, because, to my mind, real-time
be done with a computer—and because, with today's hardware, it can in
fact be done. Nay, it can be done amazingly well.
### References on 3-D Drawing {#Heading3}
### References on 3-D Drawing
There are several good sources for information about 3-D graphics. Foley
and van Dam's *Computer Graphics: Principles and Practice* (Second
@ -113,7 +113,7 @@ you're just starting out, you might want to look at one and see if it
helps you bridge the gap between the theory and implementation of 3-D
graphics.
### The 3-D Drawing Pipeline {#Heading4}
### The 3-D Drawing Pipeline
Each 3-D object that we'll handle will be built out of polygons that
represent the surface of the object. Figure 50.1 shows the stages a
@ -160,7 +160,7 @@ twice as far away as a coordinate of (0,0,-500).
![**Figure 50.2**  *A right-handed coordinate system.*](images/50-02.jpg)
#### Projection {#Heading5}
#### Projection
Working backward from the final image, we want to take the vertices of a
polygon, as transformed into view space, and project them to 2-D
@ -182,7 +182,7 @@ projected X and Y coordinates to integers, appropriately clipped and
adjusted as necessary to center the origin on the screen or otherwise
map the image into a window, if desired.
#### Translation {#Heading6}
#### Translation
*Translation* means adding X, Y, and Z offsets to a coordinate to move
it linearly through space. Translation is as simple as it seems; it
@ -193,7 +193,7 @@ the object may be located anywhere.
![**Figure 50.3**  *Perspective projection.*](images/50-03.jpg)
#### Rotation {#Heading7}
#### Rotation
*Rotation* is the process of circularly moving coordinates around the
origin. For our present purposes, it's necessary only to rotate objects
@ -225,7 +225,7 @@ There's much more to be said about transformations and the supporting
matrix math, but, in the interests of getting to working code in this
chapter, I'll leave that to be discussed as the need arises.
### A Simple 3-D Example {#Heading8}
### A Simple 3-D Example
At this point, we know enough to be able to put together a simple
working 3-D animation example. The example will do nothing more
@ -755,7 +755,7 @@ void main() {
}
```
#### Notes on the 3-D Animation Example {#Heading9}
#### Notes on the 3-D Animation Example
The sample program transforms the polygon's vertices from object space
to world space to view space to the screen, as described earlier. In
@ -812,7 +812,7 @@ it rotates. This is temporal aliasing at its finest! We won't address
antialiasing further, realtime antialiasing being decidedly nontrivial,
but this should give you an idea of why antialiasing is so desirable.
### An Ongoing Journey {#Heading10}
### An Ongoing Journey
In the next chapter, we'll assign fronts and backs to polygons, and
start drawing only those that are facing the viewer. That will enable us

View file

@ -11,9 +11,9 @@ pages: 951-967
---
## Chapter 51\
Sneakers in Space {#Heading1}
Sneakers in Space
### Using Backface Removal to Eliminate Hidden Surfaces {#Heading2}
### Using Backface Removal to Eliminate Hidden Surfaces
As I'm fond of pointing out, computer animation isn't a matter of
mathematically exact modeling or raw technical prowess, but rather of
@ -68,7 +68,7 @@ being tipped off—which is, of course, the whole point.)
If it's good enough for George Lucas, it's good enough for us. And with
that, let's resume our quest for realtime 3-D animation on the PC.
### One-sided Polygons: Backface Removal {#Heading3}
### One-sided Polygons: Backface Removal
In the previous chapter, we implemented the basic polygon drawing
pipeline, transforming a polygon all the way from its basic definition
@ -181,7 +181,7 @@ the reason it's preferable to work in screen space rather than screen
coordinates (which suffer from rounding problems), speed considerations
aside.
#### Backface Removal in Action {#Heading4}
#### Backface Removal in Action
Listings 51.1 through 51.5 together form a program that rotates a solid
cube in real-time under user control. Listing 51.1 is the main program;
@ -514,7 +514,7 @@ approach; over two-thirds of the overall time is spent in floating-point
calculations, and it's there that we'll begin to attack the performance
bottleneck we find ourselves up against.
### Incremental Transformation {#Heading5}
### Incremental Transformation
Listing 51.4 contains three functions; each concatenates an additional
rotation around one of the three axes to an existing rotation. To
@ -690,7 +690,7 @@ extern int DisplayedPage, NonDisplayedPage;
extern struct Rect EraseRect[];
```
### A Note on Rounding Negative Numbers {#Heading6}
### A Note on Rounding Negative Numbers
In the previous chapter, I added 0.5 and truncated in order to round
values from floating-point to integer format. Here, in Listing 51.2,
@ -698,7 +698,7 @@ I've switched to adding 0.5 and using the `floor()` function. For
positive values, the two approaches are equivalent; for negative values,
only the `floor()` approach works properly.
### Object Representation {#Heading7}
### Object Representation
Each object consists of a list of vertices and a list of faces, with the
vertices of each face defined by pointers into the vertex list; this

View file

@ -11,9 +11,9 @@ pages: 969-987
---
## Chapter 52\
Fast 3-D Animation: Meet X-Sharp {#Heading1}
Fast 3-D Animation: Meet X-Sharp
### The First Iteration of a Generalized 3-D Animation Package {#Heading2}
### The First Iteration of a Generalized 3-D Animation Package
Across the lake from Vermont, a few miles into upstate New York, the
Ausable River has carved out a fairly impressive gorge known as "Ausable
@ -68,7 +68,7 @@ easy to add new and different sorts of objects. Taken together, these
alterations will let us start to do some really interesting real-time
animation.
### This Chapter's Demo Program {#Heading3}
### This Chapter's Demo Program
Three-dimensional animation is a complicated business, and it takes an
astonishing amount of functionality just to get off the launching pad:
@ -795,7 +795,7 @@ extern Object *ObjectList[];
extern Point3 CubeVerts[];
```
### A New Animation Framework: X-Sharp {#Heading4}
### A New Animation Framework: X-Sharp
Listings 52.1 through 52.10 shown earlier represent not merely faster
animation in library form, but also a nearly complete, extensible,
@ -849,7 +849,7 @@ If you're intending to use X-Sharp in a real project, use the most
recent version to be sure that you avail yourself of all new features
and bug fixes.
### Three Keys to Realtime Animation Performance {#Heading5}
### Three Keys to Realtime Animation Performance
As of the previous chapter, we were at the point where we could rotate,
move, and draw a solid cube in real time. Not too shabby...but the code
@ -912,7 +912,7 @@ Borland C++, and we're *still* doing sine and cosine via the
floating-point emulator. Happily, we're still nowhere near the upper
limit on the animation potential of the PC.
#### Drawbacks {#Heading6}
#### Drawbacks
The techniques we've used to turbocharge 3-D animation are very
powerful, but there's a dark side to them as well. Obviously, native 386
@ -939,7 +939,7 @@ the viewer moves, so there's no chance for cumulative error. 3-D
clipping with a front clip plane of -1 or less can prevent divide
overflow.
#### Where the Time Goes {#Heading7}
#### Where the Time Goes
The distribution of execution time in the animation code is no longer
wildly biased toward transformation, but sine and cosine are certainly

View file

@ -11,9 +11,9 @@ pages: 989-1003
---
## Chapter 53\
Raw Speed and More {#Heading1}
Raw Speed and More
### The Naked Truth About Speed in 3-D Animation {#Heading2}
### The Naked Truth About Speed in 3-D Animation
Years ago, this friend of mine—let's call him Bert—went to Hawaii with
three other fellows to celebrate their graduation from high school. This
@ -52,7 +52,7 @@ elevator doors opened again. On the lobby.
And with that, we come to this chapter's topics: raw speed and hidden
surfaces.
### Raw Speed, Part 1: Assembly Language {#Heading3}
### Raw Speed, Part 1: Assembly Language
I would like to state, here and for the record, that I am not an
assembly language fanatic. Frankly, I prefer programming in C; assembly
@ -478,7 +478,7 @@ ret
end
```
### Raw Speed, Part II: Look it Up {#Heading4}
### Raw Speed, Part II: Look it Up
It's a funny thing about Turbo Profiler: Time spent in the Borland C++
80x87 emulator doesn't show up directly anywhere that I can see in the
@ -523,7 +523,7 @@ polygon filling soon, but for the moment, we have more than enough
horsepower to have some fun with. First, though, we need one more
feature: hidden surfaces.
#### Hidden Surfaces {#Heading5}
#### Hidden Surfaces
So far, we've made a number of simplifying assumptions in order to get
the animation to look good; for example, all objects must currently be
@ -662,7 +662,7 @@ void SortObjects()
}
```
#### Rounding {#Heading6}
#### Rounding
FIXED.ASM contains the equate **ROUNDING-ON**. When this equate is 1,
the results of multiplications and divisions are rounded to the nearest
@ -689,7 +689,7 @@ division is performed only in the course of projection, and the results
do not accumulate over time, so it would be reasonable to disable
rounding for division.
#### Having a Ball {#Heading7}
#### Having a Ball
So far in our exploration of 3-D animation, we've had nothing to look at
but triangles and cubes. It's time for something a little more visually

View file

@ -11,9 +11,9 @@ pages: 1005-1029
---
## Chapter 54\
3-D Shading {#Heading1}
3-D Shading
### Putting Realistic Surfaces on Animated 3-D Objects {#Heading2}
### Putting Realistic Surfaces on Animated 3-D Objects
At the end of the previous chapter, X-Sharp had just acquired basic
hidden-surface capability, and performance had been vastly improved
@ -22,7 +22,7 @@ to add quite a bit more: support for 8088 and 80286 PCs, a general color
model, and shading. That's an awful lot to cover in one chapter
(actually, it'll spill over into the next chapter), so let's get to it!
### Support for Older Processors {#Heading3}
### Support for Older Processors
To date, X-Sharp has run on only the 386 and 486, because it uses 32-bit
multiply and divide instructions that sub-386 processors don't support.
@ -940,7 +940,7 @@ _ConcatXforms endp
end
```
#### Shading {#Heading4}
#### Shading
So far, the polygons out of which our animated objects have been built
have had colors of fixed intensities. For example, a face of a cube
@ -1168,7 +1168,7 @@ void DrawPObject(PObject * ObjectToXform)
}
```
#### Shading: Implementation Details {#Heading7}
#### Shading: Implementation Details
In order to calculate the cosine of the angle between an incoming light
source and a polygon's unit normal, we must first have the polygon's

View file

@ -11,9 +11,9 @@ pages: 1031-1044
---
## Chapter 55\
Color Modeling in 256-Color Mode {#Heading1}
Color Modeling in 256-Color Mode
### Pondering X-Sharp's Color Model in an RGB State of Mind {#Heading2}
### Pondering X-Sharp's Color Model in an RGB State of Mind
Once she turned six, my daughter wanted some fairly sophisticated books
read to her*. Wind in the Willows.* *Little House on the Prairie.*
@ -44,7 +44,7 @@ color on a 256-color display adapter such as the VGA. Coincidentally,
VGA color modeling just happens to be this chapter's topic, and the
place to start is with color modeling in general.
#### A Color Model {#Heading3}
#### A Color Model
We've been developing X-Sharp for several chapters now. In the previous
chapter, we added illumination sources and shading; that addition makes
@ -340,7 +340,7 @@ To experiment with a different 256-color model in X-Sharp, just change
`ModelColorToColorIndex()` to map 24-bit RGB triplets into the palette
you've set up. It's that simple, and the results can be striking indeed.
#### A Bonus from the BitMan {#Heading4}
#### A Bonus from the BitMan
Finally, a note on fast VGA text, which came in from a correspondent who
asked to be referred to simply as the BitMan. The BitMan passed along a

View file

@ -11,9 +11,9 @@ pages: 1046-1059
---
## Chapter 56\
Pooh and the Space Station {#Heading1}
Pooh and the Space Station
### Using Fast Texture Mapping to Place Pooh on a Polygon {#Heading2}
### Using Fast Texture Mapping to Place Pooh on a Polygon
So, here's where Winnie the Pooh lives: in a space station orbiting
Saturn. No, really; I have it straight from my daughter, and an
@ -71,7 +71,7 @@ someone were standing in the window....
The rest is history.
### Principles of Quick-and-Dirty Texture Mapping {#Heading3}
### Principles of Quick-and-Dirty Texture Mapping
The key to our texture-mapping approach will be to quickly determine
what pixel value to draw for each pixel in the transformed destination
@ -96,7 +96,7 @@ slower.
![**Figure 56.1**  *Using reverse transformation to find the source pixel
color.*](images/56-01.jpg)
#### Mapping Textures Made Easy {#Heading4}
#### Mapping Textures Made Easy
To understand how we're going to map textures, consider Figure 56.2,
which maps a bitmapped image directly onto an untransformed polygon.
@ -190,7 +190,7 @@ the source image.*](images/56-04.jpg)
![**Figure 56.5**  *Mapping a texture onto a narrower polygon.*](images/56-05.jpg)
#### Notes on DDA Texture Mapping {#Heading5}
#### Notes on DDA Texture Mapping
That's all there is to quick-and-dirty texture mapping. This technique
basically uses a two-stage digital differential analyzer (DDA) approach
@ -247,7 +247,7 @@ performs DDA texture mapping. First, though, I'd like to take a moment
to thank Jim Kent, author of Autodesk Animator and a frequent
correspondent, for getting me started with the DDA approach.
### Fast Texture Mapping: An Implementation {#Heading6}
### Fast Texture Mapping: An Implementation
As you might expect, I've implemented DDA texture mapping in X-Sharp,
and the changes are reflected in the X-Sharp archive in this chapter's

View file

@ -11,9 +11,9 @@ pages: 1061-1075
---
## Chapter 57\
10,000 Freshly Sheared Sheep on the Screen {#Heading1}
10,000 Freshly Sheared Sheep on the Screen
### The Critical Role of Experience in Implementing Fast, Smooth Texture Mapping {#Heading2}
### The Critical Role of Experience in Implementing Fast, Smooth Texture Mapping
I recently spent an hour or so learning how to shear a sheep. Among
other things, I learned—in great detail—about the importance of
@ -42,7 +42,7 @@ graphics-programming approaches and algorithms. Second, computer
graphics is a matter of illusion, of convincing the eye to see what you
want it to see, and that's very much a black art based on experience.
#### Visual Quality: A Black Hole ... Er, Art {#Heading3}
#### Visual Quality: A Black Hole ... Er, Art
Pleasing the eye with realtime computer animation is something less than
a science, at least at the PC level, where there's a limited color
@ -76,7 +76,7 @@ continuous motion, much like watching a badly flickering movie.
> and blend the images together into continuous motion. Only experience
> can give you a feel for that sweet spot.
#### Fixed-Point Arithmetic, Redux {#Heading4}
#### Fixed-Point Arithmetic, Redux
In the previous chapter I added texture mapping to X-Sharp, but lacked
space to explain some of its finer points. I'll pick up the thread now
@ -135,7 +135,7 @@ Experience again: It's the difference between knowing which flaws (like
small texture shifts) can reasonably be ignored, and which (like those
that produce gaps between polygons) must be avoided at all costs.
#### Texture Mapping: Orientation Independence {#Heading5}
#### Texture Mapping: Orientation Independence
The double-DDA texture-mapping code presented in the previous chapter
worked adequately, but there were two things about it that left me less
@ -249,7 +249,7 @@ void ScanOutLine(EdgeScan * LeftEdge, EdgeScan * RightEdge)
}
```
#### Mapping Textures across Multiple Polygons {#Heading6}
#### Mapping Textures across Multiple Polygons
One of the truly nifty things about double-DDA texture mapping is that
it is not limited to mapping a texture onto a single polygon. A single

View file

@ -11,9 +11,9 @@ pages: 1077-1093
---
## Chapter 58\
Heinlein's Crystal Ball, Spock's Brain, and the 9-Cycle Dare {#Heading1}
Heinlein's Crystal Ball, Spock's Brain, and the 9-Cycle Dare
### Using the Whole-Brain Approach to Accelerate Texture Mapping {#Heading2}
### Using the Whole-Brain Approach to Accelerate Texture Mapping
I've had the pleasure recently of rereading several of the works of
Robert A. Heinlein, and I'm as impressed as I was as a teenager—but in a
@ -81,7 +81,7 @@ it.
As Exhibit \#1, I present my experience with speeding up the texture
mapper in X-Sharp.
### Texture Mapping Redux {#Heading3}
### Texture Mapping Redux
We've spent the previous several chapters exploring the X Sharp graphics
library, something I built over time as a serious exercise in 3-D
@ -105,7 +105,7 @@ But 3 jumps *per pixel?* Hmph!"
It was the "Hmph" that really got to me.
#### Left-Brain Optimization {#Heading4}
#### Left-Brain Optimization
That was the first shot of juice for my optimizer (or at least blow to
my ego, which can be just as productive). John went on to say he had
@ -223,7 +223,7 @@ don't you just draw vertical rather than horizontal scanlines?"
Why indeed?
#### A 90-Degree Shift in Perspective {#Heading5}
#### A 90-Degree Shift in Perspective
As I said earlier, how you look at an optimization problem defines how
you'll be able to solve it. In order to boost performance, sometimes
@ -326,7 +326,7 @@ and get caught up in particular implementations; if you bounce your
ideas off someone, you may well find them coming back with an
unexpected—and welcome—spin.
### That's Nice—But it Sure as Heck Ain't 9 Cycles {#Heading6}
### That's Nice—But it Sure as Heck Ain't 9 Cycles
Excellent as Chris's suggestion was, I still had work to do: Listing
58.2 is still more than twice as slow as John Miles's code.
@ -492,7 +492,7 @@ SCANOFFSET = SCANOFFSET + SCANWIDTH
ENDM
```
#### Don't Stop Thinking about Those Cycles {#Heading7}
#### Don't Stop Thinking about Those Cycles
Remember what I said at the outset, that knowing something has been done
makes it much easier to do? A corollary is that pushing past that point,
@ -580,7 +580,7 @@ every optimization task as if John Miles has just written to inform you
that he's made it faster than your wildest dreams, and you'll be amazed
at what you can do!
### Texture Mapping Notes {#Heading8}
### Texture Mapping Notes
Listing 58.3 contains no 486 pipeline stalls; it has Pentium stalls, but
not much can be done for them because of the size prefix on `ADD

View file

@ -11,9 +11,9 @@ pages: 1095-1114
---
## Chapter 59\
The Idea of BSP Trees {#Heading1}
The Idea of BSP Trees
### What BSP Trees Are and How to Walk Them {#Heading2}
### What BSP Trees Are and How to Walk Them
The answer is: Wendy Tucker.
@ -94,7 +94,7 @@ the most from them.
Before we begin, I'd like to thank John Carmack, the technical wizard
behind DOOM, for generously sharing his knowledge of BSP trees with me.
### BSP Trees {#Heading3}
### BSP Trees
A BSP tree is, at heart, nothing more than a tree that subdivides space
in order to isolate features of interest. Each node of a BSP tree splits
@ -117,7 +117,7 @@ powerful way to implement Constructive Solid Geometry (CSG). BSP trees
can also be used for hit testing, line-of-sight determination, and
collision detection.
#### Visibility Determination {#Heading4}
#### Visibility Determination
For the time being, I'm going to discuss only one of the many uses of
BSP trees: The ability of a BSP tree to allow you to traverse a set of
@ -158,7 +158,7 @@ trees.
![**Figure 59.1**  *The painter's algorithm.*](images/59-01.jpg)
#### Limitations of BSP Trees {#Heading5}
#### Limitations of BSP Trees
Powerful as they are, BSP trees aren't perfect. By far the greatest
limitation of BSP trees is that they're time-consuming to build, enough
@ -207,7 +207,7 @@ I'll present in the next chapter, which visually depicts the process of
spatial subdivision as a BSP tree is constructed, help a great deal with
BSP debugging.
### Building a BSP Tree {#Heading6}
### Building a BSP Tree
Now that we know a good bit about what a BSP tree is, how it helps in
visible surface determination, and what its strengths and weaknesses
@ -280,7 +280,7 @@ treated as a separate wall. As shown in Figure 59.6, each of the split
pieces then has a subspace to itself, and each becomes a leaf of the
tree. The BSP tree is now complete.
#### Visibility Ordering {#Heading7}
#### Visibility Ordering
Now that we've successfully built a BSP tree, you might justifiably be a
little puzzled as to how any of this helps with visibility ordering. The
@ -379,7 +379,7 @@ void WalkBSPTree(NODE *pNode)
> partition space identically and can't occlude one another, so it
> suffices to generate one splitting node for each collinear set.
### Inorder Walks of BSP Trees {#Heading8}
### Inorder Walks of BSP Trees
It was implementing BSP trees that got me to thinking about inorder tree
traversal. In inorder traversal, the left subtree of each node gets
@ -472,7 +472,7 @@ fully functional model to follow, with all the problems solved, but they
can't make the connection between that model and the code they're trying
to implement. Why is this?
#### Know It *Cold* {#Heading9}
#### Know It *Cold*
The problem is that these people don't understand inorder walking
through and through. They understand the concepts of visiting left and
@ -604,7 +604,7 @@ pants.
> the model down cold, you can always tell if the implementation is
> correct by comparing it with the model.
#### Measure and Learn {#Heading10}
#### Measure and Learn
How much difference does all this fuss make, anyway? Listing 59.5 is a
sample program that builds a tree, then calls `WalkTree` () to walk it
@ -749,7 +749,7 @@ run fast enough to keep up if you just keep at it.
Depths within depths indeed!
### Surfing Amidst the Trees {#Heading11}
### Surfing Amidst the Trees
In the next chapter, we'll build a BSP-tree compiler, and after that,
we'll put together a rendering system built around the BSP trees the
@ -761,7 +761,7 @@ must investigate at
up in the familiar Internet Frequently Asked Questions (FAQ) style, and
is very good stuff.
#### Related Reading {#Heading12}
#### Related Reading
Foley, J., A. van Dam, S. Feiner, and J. Hughes, *Computer Graphics:
Principles and Practice (Second Edition)*, Addison Wesley, 1990, pp.

View file

@ -11,9 +11,9 @@ pages: 1115-1129
---
## Chapter 60\
Compiling BSP Trees {#Heading1}
Compiling BSP Trees
### Taking BSP Trees from Concept to Reality {#Heading2}
### Taking BSP Trees from Concept to Reality
As long-time readers of my columns know, I tend to move my family around
the country quite a bit. Change doesn't come out of the blue, so there's
@ -103,7 +103,7 @@ optimization.
Onward to compiling BSP trees.
### Compiling BSP Trees {#Heading3}
### Compiling BSP Trees
As you'll recall from the previous chapter, a BSP tree is nothing more
than a series of binary subdivisions that partion space into
@ -139,7 +139,7 @@ choosing splitters shortly, but first let's look at the process of
splitting and assigning. To do that, we need to understand parametric
lines.
#### Parametric Lines {#Heading4}
#### Parametric Lines
We're all familiar with lines described in slope-intercept form, with y
as a function of x
@ -190,7 +190,7 @@ indeed.
![**Figure 60.2**  *Line segment storage in the BSP compiler.*](images/60-02.jpg)
#### Parametric Line Clipping {#Heading5}
#### Parametric Line Clipping
In order to assign a line segment to one subspace or the other of a
splitter, we must somehow figure out whether the line segment straddles
@ -236,7 +236,7 @@ normal; you could calculate the normal as the cross-product of two of
the polygon's edges, or precalculate it when you build the world
database.
#### The BSP Compiler {#Heading6}
#### The BSP Compiler
Listing 60.1 shows the core of a BSP compiler—the code that actually
builds the BSP tree. (Note that Listing 60.1 is excerpted from a C++
@ -526,7 +526,7 @@ copying some global variables that it uses.) The complete code is too
large to print here in its entirety, but it's on the CD-ROM in file
DDJBSP.ZIP.
### Optimizing the BSP Tree {#Heading7}
### Optimizing the BSP Tree
In the previous chapter, I promised that I'd discuss how to go about
deciding which wall to use as the splitter at each node in constructing
@ -583,7 +583,7 @@ surfaces that are being considered for that node. In other words, I
choose the wall that splits the fewest of the walls in the subspace it's
subdividing.
### BSP Optimization: an Undiscovered Country {#Heading8}
### BSP Optimization: an Undiscovered Country
Although BSP trees have been around for at least 15 years now, they're
still only partially understood and are a ripe area for applied research

View file

@ -11,9 +11,9 @@ pages: 1131-1144
---
## Chapter 61\
Frames of Reference {#Heading1}
Frames of Reference
### The Fundamentals of the Math behind 3-D Graphics {#Heading2}
### The Fundamentals of the Math behind 3-D Graphics
Several years ago, I opened a column in *Dr. Dobb's Journal* with a
story about singing my daughter to sleep with Beatles' songs. Beatles'
@ -55,7 +55,7 @@ important sort of difference.
Before we can talk about transforming between coordinate spaces,
however, we need two building blocks: dot products and cross products.
#### 3-D Math {#Heading3}
#### 3-D Math
At this point in the book, I was originally going to present a BSP-based
renderer, to complement the BSP compiler I presented in the previous
@ -89,7 +89,7 @@ chapter examining these basic tools and some of their 3-D applications.
If this is old hat to you, my apologies, and I'll return to BSP-based
rendering in the next chapter.
#### Foundation Definitions {#Heading4}
#### Foundation Definitions
The dot and cross products themselves are straightforward and require
almost no context to understand, but I need to define some terms I'll
@ -142,7 +142,7 @@ For additional information, you might want to check out Foley & van
Dam's *Computer Graphics* (ISBN 0-201-12110-7), or the chapters in this
book dealing with my X-Sharp 3-D graphics library.
### The Dot Product {#Heading5}
### The Dot Product
Now we're ready to move on to the dot product. Given two vectors `U` =
[u~1~ u~2~ u~3~] and `V` = [v~1~ v~2~ v~3~], their dot product,
@ -168,7 +168,7 @@ are the lengths of the vectors, as shown in Figure 61.1. Although it's
not immediately obvious, equation 3 has a wide variety of applications
in 3-D graphics.
#### Dot Products of Unit Vectors {#Heading6}
#### Dot Products of Unit Vectors
The simplest case of the dot product is when both vectors are *unit
vectors*; that is, when their lengths are both one, as calculated as in
@ -208,7 +208,7 @@ three additions—and no explicit cosine calculations—as
where `N`~s~ is the surface unit normal and `D`~l~ is the light unit
direction vector, as shown in Figure 61.2.
### Cross Products and the Generation of Polygon Normals {#Heading7}
### Cross Products and the Generation of Polygon Normals
One question equation 6 begs is where the surface unit normal comes
from. One approach is to store the end of a surface normal as an extra
@ -287,7 +287,7 @@ orthogonal unit vectors, you'll have to normalize the resulting vector;
that is, divide each of the vector's components by the length of the
vector, to make it a unit long.
### Using the Sign of the Dot Product {#Heading8}
### Using the Sign of the Dot Product
The dot product is the cosine of the angle between two vectors, scaled
by the magnitudes of the vectors. Magnitudes are always positive, so the
@ -335,7 +335,7 @@ understand the use of the dot product for projection.
![**Figure 61.5**  *Backface culling with the dot product.*](images/61-05.jpg)
### Using the Dot Product for Projection {#Heading9}
### Using the Dot Product for Projection
Consider Equation 3 again, but this time make one of the vectors, say
`V`, a unit vector. Now the equation reduces to:
@ -407,7 +407,7 @@ void LineIntersectPlane (float *linestart, float *lineend,
}
```
### Rotation by Projection {#Heading10}
### Rotation by Projection
We can use the dot product's projection capability to look at rotation
in an interesting way. Typically, rotations are represented by matrices.

View file

@ -11,9 +11,9 @@ pages: 1145-1162
---
## Chapter 62\
One Story, Two Rules, and a BSP Renderer {#Heading1}
One Story, Two Rules, and a BSP Renderer
### Taking a Compiled BSP Tree from Logical to Visual Reality {#Heading2}
### Taking a Compiled BSP Tree from Logical to Visual Reality
As I've noted before, I'm working on Quake, id Software's follow-up to
DOOM. A month or so back, we added page flipping to Quake, and made the
@ -78,7 +78,7 @@ Tools*, AP Professional, ISBN 0-12-627230-1.
Onward to rendering from a BSP tree.
#### BSP-based Rendering {#Heading3}
#### BSP-based Rendering
For the last several chapters I've been discussing the nature of BSP
(Binary Space Partitioning) trees, and in Chapter 60 I presented a
@ -561,7 +561,7 @@ void UpdateWorld()
}
```
#### The Rendering Pipeline {#Heading4}
#### The Rendering Pipeline
Conceptually rendering from a BSP tree really is that simple, but the
implementation is a bit more complicated. The full rendering pipeline,
@ -582,7 +582,7 @@ detail. Some sources for further reading are *Computer Graphics*, by
Foley and van Dam (ISBN 0-201-12110-7), and the *DDJ Essential Books on
Graphics Programming* CD.
### Moving the Viewer {#Heading5}
### Moving the Viewer
The sample BSP program performs first-person rendering; that is, it
renders the world as seen from your eyes as you move about. The rate of
@ -599,7 +599,7 @@ any tilted walls. For simplicity's sake, I have chosen not to implement
this in Listing 62.1, but you may find it educational to add it to the
program yourself.
### Transformation into Viewspace {#Heading6}
### Transformation into Viewspace
The viewing angle (which controls direction of movement as well as view
direction) can sweep through the full 360 degrees around the viewpoint,
@ -626,7 +626,7 @@ values result in narrower fields of view.
When this is done the walls are in viewspace, ready to be clipped.
### Clipping {#Heading7}
### Clipping
In viewspace, the walls may be anywhere relative to the viewpoint: in
front, behind, off to the side. We only want to draw those parts of
@ -675,7 +675,7 @@ near clip plane guarantees that no remaining polygon point can have
z\<=0, ensuring that when we project we'll always pass valid,
y-clippable screenspace vertices to the polygon filler.
### Projection to Screenspace {#Heading8}
### Projection to Screenspace
At this point, we have viewspace vertices for each wall that's at least
partially visible. All we have to do is project these vertices according
@ -686,7 +686,7 @@ as the last step for visible walls in `ClipWalls()`.
![**Figure 62.3**  *Why y clipping is more complex than x or z clipping.*](images/62-03.jpg)
### Walking the Tree, Backface Culling and Drawing {#Heading9}
### Walking the Tree, Backface Culling and Drawing
Now that we have all the walls clipped to the frustum, with vertices
projected into screen coordinates, all we have to do is draw them back
@ -744,7 +744,7 @@ the new frame to the screen. The frame of animation is complete.
![**Figure 62.4**  *Fast backspace culling test in screenspace.*](images/62-04.jpg)
#### Notes on the BSP Renderer {#Heading10}
#### Notes on the BSP Renderer
Listing 62.1 is far from complete or optimal. There is no such thing as
a tiny BSP rendering demo, because 3D rendering, even when based on a

View file

@ -11,9 +11,9 @@ pages: 1163-1175
---
## Chapter 63\
Floating-Point for Real-Time 3-D {#Heading1}
Floating-Point for Real-Time 3-D
### Knowing When to Hurl Conventional Math Wisdom Out the Window {#Heading2}
### Knowing When to Hurl Conventional Math Wisdom Out the Window
In a crisis, sometimes it's best to go with the first solution that
comes into your head—but not very often.
@ -94,7 +94,7 @@ quickly assumptions that once were completely valid can deteriorate.
For example, consider floating-point math.
### Not Your Father's Floating-Point {#Heading3}
### Not Your Father's Floating-Point
Until last year, I had never done any serious floating-point (FP)
optimization, for the perfectly good reason that FP math had never been
@ -132,7 +132,7 @@ this chapter I'll examine the basics of Pentium FP optimization, then
look at how some key mathematical techniques for 3-D—dot product, cross
product, transformation, and projection—can be accelerated.
### Pentium Floating-Point Optimization {#Heading4}
### Pentium Floating-Point Optimization
I'm going to assume you're already familiar with x86 FP code in general;
for additional information, check out Intel's *Pentium Processor User's
@ -188,7 +188,7 @@ instructions starts. There's a more exciting possibility here, though:
Given properly structured code, the FPU is capable of averaging 1 cycle
per FADD, FSUB, or FMUL. The secret is pipelining.
#### Pipelining, Latency, and Throughput {#Heading5}
#### Pipelining, Latency, and Throughput
The Pentium's FPU is the first pipelined x86 FPU. *Pipelining* means
that the FPU is capable of starting an instruction every cycle, and can
@ -258,7 +258,7 @@ two instructions. When dependencies like this occur, the FPU runs at
latency rather than throughput speeds, and performance can drop by as
much as two-thirds.
#### FXCH {#Heading6}
#### FXCH
One piece of the puzzle is still missing. Clearly, to get maximum
throughput, we need to interleave FP instructions, such that at any one
@ -297,7 +297,7 @@ multiplications, without incurring any stalls, as shown in Listing 63.1.
faddp st(2),st(0) ;starts on cycle 6
```
### The Dot Product {#Heading7}
### The Dot Product
Now we're ready to look at fast FP for common 3-D operations; we'll
start by looking at how to speed up the dot product. As discussed in
@ -355,7 +355,7 @@ potential, as we'll see when we discuss transformation.
; ends on cycle 14
```
### The Cross Product {#Heading8}
### The Cross Product
When last we looked at the cross product, we found that it's handy for
generating a vector that's normal to two other vectors. The cross
@ -442,7 +442,7 @@ of properly managing the Pentium's FP pipeline.
; ends on cycle 21
```
### Transformation {#Heading9}
### Transformation
Transforming a point, for example from worldspace to viewspace, is one
of the most heavily used FP operations in realtime 3-D. Conceptually,
@ -528,7 +528,7 @@ certainly feasible; at a frame rate of 30 Hz, that's an impressive
; ends on cycle 33
```
### Projection {#Heading10}
### Projection
The final optimization we'll look at is projection to screenspace.
Projection itself is basically nothing more than a divide (to get 1/z),
@ -554,7 +554,7 @@ precision-related problems, such as clipped values that vary more than
you'd expect from the precise clip point, or the need for using larger
epsilons in comparisons for point-on-plane tests.
### Rounding Control {#Heading11}
### Rounding Control
Another useful area that I can note only in passing here is that of
leaving the FPU in a particular rounding mode while performing bulk
@ -576,7 +576,7 @@ A final note: There are some speed-ups to be had by manipulating FP
variables with integer instructions. Check out Chris Hecker's column in
the February/March 1996 issue of *Game Developer* for details.
### A Farewell to 3-D Fixed-Point {#Heading12}
### A Farewell to 3-D Fixed-Point
As with most optimizations, there are both benefits and hazards to
floating-point acceleration, especially pedal-to-the-metal optimizations

View file

@ -11,9 +11,9 @@ pages: 1177-1190
---
## Chapter 64\
Quake's Visible-Surface Determination {#Heading1}
Quake's Visible-Surface Determination
### The Challenge of Separating All Things Seen from All Things Unseen {#Heading2}
### The Challenge of Separating All Things Seen from All Things Unseen
Years ago, I was working at Video Seven, a now-vanished video adapter
manufacturer, helping to develop a VGA clone. The fellow who was
@ -83,7 +83,7 @@ seemingly outlandish ideas can open up new design possibilities for you.
Case in point: The evolution of Quake's 3-D graphics engine.
### VSD: The Toughest 3-D Challenge of All {#Heading3}
### VSD: The Toughest 3-D Challenge of All
I've spent most of my waking hours for the last several months working
on Quake, id Software's successor to DOOM, and I suspect I have a few
@ -119,7 +119,7 @@ detailed. Already, a good-sized Quake level contains on the order of
10,000 polygons, about three times as many polygons as a comparable DOOM
level.
### The Structure of Quake Levels {#Heading4}
### The Structure of Quake Levels
Before diving into VSD, let me note that each Quake level is stored as a
single huge 3-D BSP tree. This BSP tree, like any BSP, subdivides space,
@ -135,7 +135,7 @@ the boundaries of the BSP leaves, facing inward, the polygons in a given
leaf can never obscure one another and can be drawn in any order. (This
is a general property of convex polyhedra.)
### Culling and Visible Surface Determination {#Heading5}
### Culling and Visible Surface Determination
The process of VSD would ideally work as follows: First, you would cull
all polygons that are completely outside the view frustum (view
@ -172,7 +172,7 @@ the world, more transformations and tests have to be performed to cull
polygons that aren't visible; at some point, that will bog considerably
performance down.
#### Nodes Inside and Outside the View Frustum {#Heading6}
#### Nodes Inside and Outside the View Frustum
Happily, there's a good workaround for this particular problem. As
discussed earlier, each leaf of a BSP tree represents a convex subspace,
@ -199,7 +199,7 @@ specifically for culling tests.
So culling to the frustum isn't a problem, and the BSP can be used to
draw back-to- front. What, then, *is* the problem?
### Overdraw {#Heading7}
### Overdraw
The problem John Carmack, the driving technical force behind DOOM and
Quake, faced when he designed Quake was that in a complex world, many
@ -241,7 +241,7 @@ By three months after I arrived, only one element of the original VSD
design was anywhere in sight, and John had taken the dictum of "try new
things" farther than I'd ever seen it taken.
### The Beam Tree {#Heading8}
### The Beam Tree
John's original Quake design was to draw front-to-back, using a second
BSP tree to keep track of what parts of the screen were already drawn
@ -294,7 +294,7 @@ proved to suffer from much the same malady as the painter's algorithm:
The worst case was much worse than the average case, and it didn't scale
well with increasing level complexity.
### 3-D Engine du Jour {#Heading9}
### 3-D Engine du Jour
Once the beam tree was working, John relentlessly worked at speeding up
the 3-D engine, always trying to improve the design, rather than
@ -311,7 +311,7 @@ are some of those approaches, presented in minimal detail in the hopes
that, like Tom Wilson with the Paradise FIFO, your imagination will be
sparked.
#### Subdividing Raycast {#Heading10}
#### Subdividing Raycast
Rays are cast in an 8x8 screen-pixel grid; this is a highly efficient
operation because the first intersection with a surface can be found by
@ -324,7 +324,7 @@ This scales very well, being limited by the number of pixels, with no
overdraw. The problem is dropouts; it's quite possible for small
polygons to fall between rays and vanish.
#### Vertex-Free Surfaces {#Heading11}
#### Vertex-Free Surfaces
The world is represented by a set of surface planes. The polygons are
implicit in the plane intersections, and are extracted from the planes
@ -332,7 +332,7 @@ as a final step before drawing. This makes for fast clipping and a very
small data set (planes are far more compact than polygons), but it's
time-consuming to extract polygons from planes.
#### The Draw-Buffer {#Heading12}
#### The Draw-Buffer
Like a z-buffer, but with 1 bit per pixel, indicating whether the pixel
has been drawn yet. This eliminates overdraw, but at the cost of an
@ -344,7 +344,7 @@ for drawing 0-8 pixels, in the process possibly taking advantage of the
ability of the x86 to do the perspective floating-point divide in
parallel while 8 pixels are processed.
#### Span-Based Drawing {#Heading13}
#### Span-Based Drawing
Polygons are rasterized into spans, which are added to a global span
list and clipped against that list so that only the nearest span at each
@ -353,7 +353,7 @@ because if there's any overlap, the span already in the list is nearer.
This eliminates overdraw, but at the cost of a lot of span arithmetic;
also, every polygon still has to be turned into spans.
#### Portals {#Heading14}
#### Portals
The holes where polygons are missing on surfaces are tracked, because
it's only through such portals that line-of-sight can extend. Drawing
@ -363,7 +363,7 @@ portals remain visible. Applied recursively, this allows drawing only
the visible portions of visible polygons, but at the cost of a
considerable amount of portal clipping.
### Breakthrough! {#Heading15}
### Breakthrough!
In the end, John decided that the beam tree was a sort of second-order
structure, reflecting information already implicitly contained in the
@ -421,7 +421,7 @@ still-in-development sorted-edge rasterizer that completely eliminates
overdraw, comes remarkably close to meeting the "perfect-world"
specifications we laid out at the start.
### Simplify, and Keep on Trying New Things {#Heading16}
### Simplify, and Keep on Trying New Things
What does it all mean? Exactly what I said up front: Simplify, and keep
trying new things. The precalculated PVS is simpler than any of the
@ -463,7 +463,7 @@ things better with less code.
So far, it seems to have worked out pretty well for him.
### Learn Now, Pay Forward {#Heading17}
### Learn Now, Pay Forward
There's one other thing I'd like to mention before I close this chapter.
Much of what I've learned, and a great deal of what I've written, has
@ -494,7 +494,7 @@ in a vacuum; we all stand on the shoulders of giants such as Wirth and
Knuth and thousands of others. Lend your shoulders to building the
future!
### References {#Heading18}
### References
Foley, James D., *et al.*, *Computer Graphics: Principles and Practice*,
Addison Wesley, 1990, ISBN 0-201-12110-7 (beams, BSP trees, VSD).

View file

@ -11,9 +11,9 @@ pages: 1191-1208
---
## Chapter 65\
3-D Clipping and Other Thoughts {#Heading1}
3-D Clipping and Other Thoughts
### Determining What's Inside Your Field of View {#Heading2}
### Determining What's Inside Your Field of View
Our part of the world is changing, and I'm concerned. By way of
explanation, three anecdotes.
@ -100,7 +100,7 @@ circulated a good bit of info about 3-D graphics, and plan to keep on
doing it as long as I can. Next, we're going to take a look at 3-D
clipping.
### 3-D Clipping Basics {#Heading3}
### 3-D Clipping Basics
Before I got deeply into 3-D, I kept hearing how difficult 3-D clipping
was, so I was pleasantly surprised when I actually got around to doing
@ -137,7 +137,7 @@ ways to speed up clipping under various circumstances, some of which
I'll mention, but the material covered below will give you the tools you
need to implement functional 3-D clipping.
#### Intersecting a Line Segment with a Plane {#Heading4}
#### Intersecting a Line Segment with a Plane
The fundamental 3-D clipping operation is clipping a line segment to a
plane. There are two parts to this operation: determining if the line is
@ -246,7 +246,7 @@ y, and z lengths of the line segment by that fraction, and add the
results to the inside endpoint, we get a new, clipped endpoint at the
point of intersection.
### Polygon Clipping {#Heading5}
### Polygon Clipping
Line clipping is fine for wireframe rendering, but what we really want
to do is polygon rendering of solid models, which requires polygon
@ -345,7 +345,7 @@ intersection with the clip plane can be used to advance the texture
coordinates as well, so only one extra multiply and one extra add are
required for each texture coordinate.
#### Clipping to the Frustum {#Heading6}
#### Clipping to the Frustum
Given a polygon-clipping function, it's easy to clip to the frustum: set
up the four planes for the sides of the frustum, with another one or two
@ -669,7 +669,7 @@ void UpdateWorld()
}
```
#### The Lessons of Listing 65.3 {#Heading7}
#### The Lessons of Listing 65.3
There are several interesting points to Listing 65.3. First,
floating-point arithmetic is used throughout the clipping process. While
@ -731,7 +731,7 @@ viewspace, then clipping them. However, the decision whether to clip in
worldspace or viewspace is not clear-cut and is affected by several
factors.
### Advantages of Viewspace Clipping {#Heading8}
### Advantages of Viewspace Clipping
Although viewspace clipping requires transforming vertices that may not
be drawn, it has potential performance advantages. For example, in
@ -771,7 +771,7 @@ the more frustum clipping you're doing, especially if most of the
polygons are trivially visible, the more attractive the performance
advantages of normalized clipping become.
### Further Reading {#Heading9}
### Further Reading
You now have the basics of 3-D clipping, but because fast clipping is
central to high-performance 3-D, there's a lot more to be learned. One

View file

@ -11,9 +11,9 @@ pages: 1209-1222
---
## Chapter 66\
Quake's Hidden-Surface Removal {#Heading1}
Quake's Hidden-Surface Removal
### Struggling with Z-Order Solutions to the Hidden Surface Problem {#Heading2}
### Struggling with Z-Order Solutions to the Hidden Surface Problem
Okay, I admit it: I'm sick and tired of classic rock. Admittedly, it's
been a while, about 20 years, since I was last excited to hear anything
@ -55,7 +55,7 @@ I've found that they're often worth considering.
Not that I should have needed any reminding, considering the
ever-evolving nature of Quake.
### Creative Flux and Hidden Surfaces {#Heading3}
### Creative Flux and Hidden Surfaces
Back in Chapter 64, I described the creative flux that led to John
Carmack's decision to use a precalculated potentially visible set (PVS)
@ -70,7 +70,7 @@ drawing perform the final stage of hidden-surface removal (HSR). This
was a terrific idea, but it was far from the end of the road for Quake's
design.
#### Drawing Moving Objects {#Heading4}
#### Drawing Moving Objects
For one thing, there was still the question of how to sort and draw
moving objects properly; in fact, this is the single technical question
@ -102,7 +102,7 @@ drawing and z-filling of the world is done, we can simply draw the
sprites and polygon models with z-buffering and get perfect sorting all
around.
#### Performance Impact {#Heading5}
#### Performance Impact
Whenever a z-buffer is involved, the questions inevitably are: What's
the memory footprint and what's the performance impact? Well, the memory
@ -117,7 +117,7 @@ vastly improved the visual quality and flexibility of the Quake engine,
and also simplified the code quite a bit, at an acceptable memory and
performance cost.
#### Leveling and Improving Performance {#Heading6}
#### Leveling and Improving Performance
As I said above, in the Quake architecture, the world itself is drawn
first, without z-buffer reads or compares, but filling the z-buffer with
@ -158,7 +158,7 @@ than back-to-front drawing.
And indeed there is.
### Sorted Spans {#Heading7}
### Sorted Spans
The ideal final HSR stage for Quake would reject all the polygons in the
PVS that are actually invisible, and draw only the visible pixels of the
@ -214,7 +214,7 @@ implement, with a couple of major design choices to be made, a subtle
mathematical element, and some tricky gotchas that I'll have to defer
until Chapter 67. Let's look at the design choices first.
### Edges versus Spans {#Heading8}
### Edges versus Spans
The first design choice is whether to sort spans or edges (both of which
fall into the general category of "sorted spans"). Although the results
@ -314,7 +314,7 @@ process, I'm going to have to make a few forward references to aspects
of edge-sorting that I haven't yet covered in detail; my apologies, but
it's unavoidable, and all should become clear by the end of Chapter 67.
### Edge-Sorting Keys {#Heading9}
### Edge-Sorting Keys
Now that we know we're going to sort edges, using them to emit spans for
the polygons nearest the viewer, the question becomes: How can we tell
@ -389,7 +389,7 @@ floating-point math sounds expensive but really isn't, especially on a
Pentium, where a plane's 1/z value at any point can be calculated in as
little as six cycles in assembly language.
#### Where That 1/Z Equation Comes From {#Heading10}
#### Where That 1/Z Equation Comes From
For those who are interested, here's a quick derivation of the 1/z
equation. The plane equation for a plane is
@ -410,7 +410,7 @@ Inverting and distributing yields:
We'll see 1/z sorting in action in Chapter 67.
#### Quake and Z-Sorting {#Heading11}
#### Quake and Z-Sorting
I mentioned earlier that Quake no longer uses BSP order as the sorting
key; in fact, it uses 1/z as the key now. Elegant as the gradients are,
@ -438,7 +438,7 @@ so they don't cross any solid world surfaces, to avoid complications
associated with interpenetration), along with all the world edges, and
1/z sorting takes care of the rest.
### Decisions Deferred {#Heading12}
### Decisions Deferred
There is, without a doubt, an awful lot of information in the preceding
pages, and it may not all connect together yet in your mind. The code

View file

@ -11,9 +11,9 @@ pages: 1223-1241
---
## Chapter 67\
Sorted Spans in Action {#Heading1}
Sorted Spans in Action
### Implementing Independent Span Sorting for Rendering without Overdraw {#Heading2}
### Implementing Independent Span Sorting for Rendering without Overdraw
In Chapter 66, we dove headlong into the intricacies of hidden surface
removal by way of z-sorted (actually, 1/z-sorted) spans. At the end of
@ -49,7 +49,7 @@ contained herein. Besides, the ultimate reference for any design is
working code, which you'll find, in part, in Listing 67.1, and in its
entirety in the file DDJZSORT.ZIP on the CD-ROM.
### Quake and Sorted Spans {#Heading3}
### Quake and Sorted Spans
As you'll recall from Chapter 66, Quake uses sorted spans to get zero
overdraw while rendering the world, thereby both improving overall
@ -152,7 +152,7 @@ For the remainder of this chapter, I'm going to look at the three main
types of 1/z span sorting, then discuss a sample 3-D app built around
1/z span sorting.
### Types of 1/z Span Sorting {#Heading4}
### Types of 1/z Span Sorting
As a quick refresher: With 1/z span sorting, all the polygons in a scene
are treated as sets of screenspace pixel spans, and 1/z (where z is
@ -168,7 +168,7 @@ they are: intersecting, abutting, and independent. (These are names of
my own devising; I haven't come across any standard nomenclature in the
literature.)
#### Intersecting Span Sorting {#Heading5}
#### Intersecting Span Sorting
Intersecting span sorting occurs when polygons can interpenetrate. Thus,
two spans may cross such that part of each span is visible, in which
@ -183,7 +183,7 @@ detect interpenetration, and additional work must be done to split the
spans as necessary. Thus, although intersecting span sorting certainly
works, it's not the first choice for performance.
#### Abutting Span Sorting {#Heading6}
#### Abutting Span Sorting
Abutting span sorting occurs when polygons that are not part of a
continuous surface can butt up against one another, but don't
@ -238,7 +238,7 @@ of caching sort results were outweighed by the additional overhead of
maintaining the caching information, and every caching variant we tried
actually slowed Quake down.
#### Independent Span Sorting {#Heading7}
#### Independent Span Sorting
Finally, we come to independent span sorting, the simplest and fastest
of the three, and the type the sample code in Listing 67.1 uses. Here,
@ -253,7 +253,7 @@ Independent span sorting is ideal for scenes with lots of moving objects
that never actually touch each other, such as a space battle. Next,
we'll look at an implementation of independent 1/z span sorting.
### 1/z Span Sorting in Action {#Heading8}
### 1/z Span Sorting in Action
Listing 67.1 is a portion of a program that demonstrates independent 1/z
span sorting. This program is based on the sample 3-D clipping program
@ -788,7 +788,7 @@ necessary. As you can see from Listing 67.1, it takes a fair bit of code
to implement this, but all that's really going on is a surface stack
driven by edge events.
#### Implementation Notes {#Heading9}
#### Implementation Notes
Finally, a few notes on Listing 67.1. First, you'll notice that although
we clip all polygons to the view frustum in worldspace, we nonetheless

View file

@ -11,9 +11,9 @@ pages: 1243-1256
---
## Chapter 68\
Quake's Lighting Model {#Heading1}
Quake's Lighting Model
### A Radically Different Approach to Lighting Polygons {#Heading2}
### A Radically Different Approach to Lighting Polygons
It was during my senior year in college that I discovered computer
games. Not Wizardry, or Choplifter, or Ultima, because none of those
@ -65,7 +65,7 @@ doing, and if it's getting stale, it's time to learn something new;
there's plenty of interesting programming of all sorts to be done.
Follow your interests—and don't forget to have fun!
### The Lighting Conundrum {#Heading3}
### The Lighting Conundrum
I spent about two years working with John Carmack on Quake's 3-D
graphics engine. John faced several fundamental design issues while
@ -89,7 +89,7 @@ and rock-solid, complex lighting proved to be difficult to achieve with
traditional lighting approaches; ultimately, a dramatically different
approach was required.
### Gouraud Shading {#Heading4}
### Gouraud Shading
The traditional way to do realistic lighting in polygon pipelines is
Gouraud shading (also known as *smooth shading*). Gouraud shading
@ -118,7 +118,7 @@ small amount of calculation and a compact data set that's a simple
extension of the basic polygon model. However, there are several
important drawbacks to Gouraud shading, as well.
#### Problems with Gouraud Shading {#Heading5}
#### Problems with Gouraud Shading
The quality of Gouraud shading depends heavily on the average size of
the polygons being drawn. Linear interpolation is used, so highlights
@ -157,7 +157,7 @@ that increases the rasterization load.
![**Figure 68.1**  *Adding an extra vertex directly beneath a light.*](images/68-01.jpg)
#### Perspective Correctness {#Heading6}
#### Perspective Correctness
Another problem is that Gouraud shading isn't perspective-correct. With
Gouraud shading, lighting varies linearly across the face of a polygon,
@ -229,7 +229,7 @@ not only would the world still be less than totally solid, because of
the limitations of Gouraud shading, but the engine would also be too
slow to support the complex worlds we had hoped for in Quake.
### The Quest for Alternative Lighting {#Heading7}
### The Quest for Alternative Lighting
None of which is to say that Gouraud shading isn't useful in general.
Descent uses it to excellent effect, and in fact Quake uses Gouraud
@ -251,7 +251,7 @@ possibilities and continued working with Gouraud shading for lack of a
better alternative—until the day John came into work and said, "You
know, I have an idea...."
#### Decoupling Lighting from Rasterization {#Heading8}
#### Decoupling Lighting from Rasterization
John's idea came to him while was looking at a wall that had been carved
into several pieces because of a spotlight, with an ugly lighting glitch
@ -303,7 +303,7 @@ because lighting is unrelated to vertices. In short, surface-based
lighting meets all of Quake's visual quality goals, which leaves only
one question: How does it perform?
#### Size and Speed {#Heading9}
#### Size and Speed
As it turns out, the raw speed of surface-based lighting is pretty good.
Although an extra step is required to build the surface, moving lighting
@ -357,7 +357,7 @@ the combination of surface building and unlit texture mapping a
potential performance problem, but that never posed a problem during the
development of Quake, thanks to surface caching.
### Surface Caching {#Heading10}
### Surface Caching
When he thought of surface-based lighting, John immediately realized
that surface building would be relatively expensive. (In fact, he
@ -392,7 +392,7 @@ cache initially looked to be very large, on the order of several
megabytes, even at 320x200—too much for a game intended to run on an 8
MB machine.
#### Mipmapping To The Rescue {#Heading11}
#### Mipmapping To The Rescue
Two factors combined to solve this problem. First, polygons are drawn
through an edge list with no overdraw, as I discussed a few chapters
@ -433,7 +433,7 @@ of texels, all at the mipmap level of the nearest vertex, and would
require huge amounts of surface cache space while displaying a great
deal of aliasing in distant regions due to a high texel:pixel ratio.
#### Two Final Notes on Surface Caching {#Heading12}
#### Two Final Notes on Surface Caching
Dynamic lighting has a significant impact on the performance of surface
caching, because whenever the lighting on a surface changes, the surface

View file

@ -11,9 +11,9 @@ pages: 1257-1271
---
## Chapter 69\
Surface Caching and Quake's Triangle Models {#Heading1}
Surface Caching and Quake's Triangle Models
### Probing Hardware-Assisted Surfaces and Fast Model Animation Without Sprites {#Heading2}
### Probing Hardware-Assisted Surfaces and Fast Model Animation Without Sprites
In the late '70s, I spent a summer doing contract programming at a
government-funded installation called the Northeast Solar Energy Center
@ -83,7 +83,7 @@ and the more information we have, the better. In that spirit, let's look
at more of the stuff that makes Quake tick, starting with what I've
recently learned about surface caching.
### Surface Caching with Hardware Assistance {#Heading3}
### Surface Caching with Hardware Assistance
In Chapter 68, I discussed in detail the surface caching technique that
Quake uses to do detailed, high-quality lighting without lots of
@ -135,7 +135,7 @@ the case in software. Second, there are at least two alternatives that
preserve the advantages of surface caching without many of the
disadvantages noted above.
#### Letting the Graphics Card Build the Textures {#Heading4}
#### Letting the Graphics Card Build the Textures
One obvious solution is to have the accelerator card build the textures,
rather than having the CPU build and then download them. This eliminates
@ -157,7 +157,7 @@ as it stores them in texture memory. Better yet, some accelerators
support 8-bpp palettized hardware textures that are expanded to 16-bpp
on the fly during texturing.)
#### The Light Map as Alpha Texture {#Heading5}
#### The Light Map as Alpha Texture
Another appealing non-caching approach is doing unlit texture-mapping in
one pass, then lighting from the light map as a second pass, using the
@ -193,7 +193,7 @@ heavily toward hardware accelerators, and at this point it's a tossup
whether the engine will use surface caching, Gouraud shading, or
two-pass lighting.
### Drawing Triangle Models {#Heading6}
### Drawing Triangle Models
Most of the last group of chapters in this book discuss how Quake works.
If you look closely, though, you'll see that almost all of the
@ -212,7 +212,7 @@ discuss some interesting aspects of our triangle-model architecture, and
present code for one useful approach for the rapid drawing of triangle
models.
#### Drawing Triangle Models Fast {#Heading7}
#### Drawing Triangle Models Fast
We would have liked one rendering model, and hence one graphics
pipeline, for all drawing in Quake; this would have simplified the code
@ -256,7 +256,7 @@ between the vertices that suffer slight warping.
![**Figure 69.1**  *Quake's triangle-model drawing pipeline.*](images/69-01.jpg)
#### Trading Subpixel Precision for Speed {#Heading8}
#### Trading Subpixel Precision for Speed
Another sacrifice at the altar of performance was subpixel precision.
Before each triangle is drawn, we snap its vertices to the nearest
@ -290,7 +290,7 @@ so the model is always lit from the same direction. Somewhat
surprisingly, in practice this looks considerably better than pure
ambient lighting.
#### An Idea that Didn't Work {#Heading9}
#### An Idea that Didn't Work
As we implemented triangle models, we tried several ideas that didn't
work out. One that's notable because it seems so appealing is caching a
@ -328,7 +328,7 @@ if necessary, but the sprite architecture just had the feeling of being
fundamentally not the right approach, so we tried thinking along
different lines.
#### An Idea that Did Work {#Heading10}
#### An Idea that Did Work
John Carmack had the notion that it was just way too much effort per
pixel to do all the work of scanning out the tiny triangles in distant
@ -519,7 +519,7 @@ D_PolysetRecursiveTriangle (lp3, new, lp2);
![**Figure 69.2**  *One recursive subdivision triangle-drawing step.*](images/69-02.jpg)
#### More Ideas that Might Work {#Heading11}
#### More Ideas that Might Work
Useful as subdivision rasterization proved to be, we by no means think
that we've maxed out triangle-model drawing, if only because we spent

View file

@ -11,7 +11,7 @@ pages: 1273-1285
---
## Chapter 70\
Quake: A Post-Mortem and a Glimpse into the Future {#Heading1}
Quake: A Post-Mortem and a Glimpse into the Future
*Why did not any of the children in the first group think of this faster
method of going across the room? It is simple. They looked at what they
@ -81,7 +81,7 @@ like Knuth, Foley and van Dam, Jim Blinn, Jim Kajiya, and hundreds of
others—are you ready to take a shot at making your own contribution to
the future?
### Preprocessing the World {#Heading2}
### Preprocessing the World
For the most part, I'll discuss Quake's 3-D engine in this chapter,
although I'll touch on other areas of interest. For 3-D rendering
@ -146,7 +146,7 @@ player can move, is completely surrounded by a solid region. This
eliminates a great many irrelevant polygons, and reduces the complexity
of the next step, calculating the potentially visible set.
### The Potentially Visible Set (PVS) {#Heading3}
### The Potentially Visible Set (PVS)
After the BSP tree is built, the potentially visible set (PVS) for each
leaf is calculated. The PVS for a leaf consists of all the leaves that
@ -229,7 +229,7 @@ radiosity lighting—a considerably more expensive process, but one that
produces highly realistic lighting—is performed, but I'll save that for
later.
### Passages: The Last-Minute Change that Didn't Happen {#Heading4}
### Passages: The Last-Minute Change that Didn't Happen
Earlier, I mentioned that we almost changed 3-D engines again in the
last month of Quake's development. Here's what happened: One of the
@ -287,7 +287,7 @@ future engine.
The more approaches you try, the larger your toolkit and the broader
your understanding will be when you tackle your next project.
### Drawing the World {#Heading5}
### Drawing the World
Everything described so far is a preprocessing step. When Quake is
actually running, the world is drawn as follows: First, the PVS for the
@ -361,7 +361,7 @@ Quake engine, but remains an inelegant solution, and, in the end, it
feels like there's something better we didn't hit on. However, as John
says, "I'm pragmatic above all else"—and the edge list did the job.
### Rasterization {#Heading6}
### Rasterization
Once the visible spans are scanned out of the edge list, they must still
be drawn, with perspective-correct texture mapping and lighting. This
@ -383,7 +383,7 @@ of 1/z is overlapped with drawing 16 pixels, taking advantage of the
Pentium's ability to perform floating-point in parallel with integer
instructions, so the FDIV effectively takes only one cycle.
#### Lighting {#Heading7}
#### Lighting
Lighting is less simple to explain. The traditional way of doing polygon
lighting is to calculate the correct light at the vertices and linearly
@ -422,7 +422,7 @@ splattered on a wall could be handled by drawing the splatter image as a
sprite into the appropriate surface buffer, so that drawing the surface
would draw the splatter as well.
#### Dynamic Lighting {#Heading8}
#### Dynamic Lighting
Here we come to a feature added to Quake after last year's Computer Game
Developer's Conference (CGDC). At that time, Quake did not support
@ -469,7 +469,7 @@ visually very solid and stable. This was an important design goal from
the start, both as a point of technical pride and because it greatly
improves the player's sense of immersion.
### Entities {#Heading9}
### Entities
So far, all we've drawn is the static, unchanging (apart from dynamic
lighting) world. That's an important foundation, but it's certainly not
@ -477,7 +477,7 @@ a game; now we need to add moving objects. These objects fall into four
very different categories: BSP models, polygon models, sprites, and
particles.
#### BSP Models {#Heading10}
#### BSP Models
BSP models are just like the world, except that they can move. Examples
include doors, moving bridges, and health and ammo boxes. The way these
@ -518,7 +518,7 @@ if the door opens). This makes BSP models most suitable for fairly
simple structures, such as boxes, which have relatively few polygons to
clip, and cause relatively few edges to be added to the edge list.
#### Polygon Models and Z-Buffering {#Heading11}
#### Polygon Models and Z-Buffering
Polygon models, such as monsters, weapons, and projectiles, consist of a
triangle mesh with front and back skins stretched over the model. For
@ -592,7 +592,7 @@ could be sent through a special fast path. The biggest breakthrough,
though, was a very different sort of rasterizer that John came up with
for relatively distant models.
#### The Subdivision Rasterizer {#Heading12}
#### The Subdivision Rasterizer
This rasterizer, which we call the *subdivision rasterizer*, first draws
all the vertices in the model. Then it takes each front-facing triangle,
@ -621,7 +621,7 @@ faster ways yet to rasterize distant models adequately well, but the
subdivider was clearly a win, and is a good example of how thinking in a
radically different direction can pay off handsomely.
#### Sprites {#Heading13}
#### Sprites
We had hoped to be able to eliminate sprites completely, making Quake
100% 3-D, but sprites—although sometimes very visibly 2-D—were used for
@ -637,7 +637,7 @@ similar to drawing a normal polygon, complete with perspective
correction, although of course the inner loop must detect and skip over
transparent pixels, and must also perform z-buffering.
#### Particles {#Heading14}
#### Particles
The last drawing entity type is particles. Each particle is a
solid-colored rectangle, scaled by distance from the viewer and drawn
@ -650,7 +650,7 @@ example, providing a trail of fire behind a polygon-model lava ball that
flies into the air, or generating an expanding cloud around a sprite
explosion core.
### How We Spent Our Summer Vacation: After Shipping Quake {#Heading15}
### How We Spent Our Summer Vacation: After Shipping Quake
Since shipping Quake in the summer of 1996, we've extended it in several
ways: We've worked with Rendition to port it to the Verite accelerator
@ -658,7 +658,7 @@ chip, we've ported it to OpenGL, we've ported it to Win32, we've done
QuakeWorld, and we've added features for Quake 2. I'll discuss each of
these briefly.
#### Verite Quake {#Heading16}
#### Verite Quake
Verite Quake (VQuake) was the first hardware-accelerated version of
Quake. It looks extremely good, due to bilinear texture filtering, which
@ -719,7 +719,7 @@ it seems most likely that the two approaches will be mixed together,
with surface caching used for special surfaces, and two-pass alpha
lighting used for most drawing.
#### GLQuake {#Heading17}
#### GLQuake
The second (and, according to current plans, last) port of Quake to a
hardware accelerator was an OpenGL version, GLQuake, a native Win32
@ -809,7 +809,7 @@ are standard equipment on accelerators, and it's a lot of fun seeing
what sorts of previously very difficult effects can now be up and
working in a matter of hours.
#### WinQuake {#Heading18}
#### WinQuake
I'm not going to spend much time on the Win32 port of Quake; most of
what I learned doing this consists of tedious details that are doubtless
@ -833,7 +833,7 @@ Still, when you get down to it, the future of gaming is a networked
Win32 world, and that's that, so if you haven't already moved to Win32,
I'd say it's time.
#### QuakeWorld {#Heading19}
#### QuakeWorld
QuakeWorld is a native Win32 multiplayer-only version of Quake, and was
done as a learning experience; it is not a commercial product, but is
@ -941,7 +941,7 @@ tradeoff of smoothness and perceived low latency for the frustration of
paradoxes—and that's the way it's going to stay until most people are
connected to the Internet by something better than modems.
#### Quake 2 {#Heading20}
#### Quake 2
I can't talk in detail about Quake 2 as a game, but I can describe some
interesting technology features. The Quake 2 rendering engine isn't
@ -1000,7 +1000,7 @@ considers this the game interface of the future.
By the way, Quake 2 is currently being developed as a native Win32 app
only; no DOS version is planned.
### Looking Forward {#Heading21}
### Looking Forward
In my address to the Computer Game Developer's Conference in 1996, I
said that it wasn't a bad time to start up a game company aimed at

View file

@ -8,7 +8,7 @@ category: 'Web and Software Development: Game Development,Web and Software Devel
Graphics and Multimedia Development'
---
# Introduction {#Heading1}
# Introduction
What was it like working with John Carmack on Quake? Like being strapped
onto a rocket during takeoff—in the middle of a hurricane. It seemed