Win32 Graphics Programming
By
Professional
Project - Year 2000
Last Updated On
02/05/2001
Introduction....................................................................................................................................... 3
1
Overviews.................................................................................................................................. 3
1.1
Graphics Device Interface (GDI) Programming..................................................................... 3
1.1.1
Device Contexts............................................................................................................ 3
1.1.2
Delphi and the GDI....................................................................................................... 4
1.1.3
Common Tools............................................................................................................. 4
1.1.4 3D
Concepts................................................................................................................ 4
GDI Example........................................................................................................................ 4
1.2
DirectX............................................................................................................................... 4
1.2.1 Dx
Device Independence.............................................................................................. 4
1.2.2
Common Tools............................................................................................................. 4
1.2.3
ActiveX Example.......................................................................................................... 4
1.3
OpenGL.............................................................................................................................. 4
1.3.1
OGL Use of Independence............................................................................................ 4
1.3.2
Common Tools............................................................................................................. 4
1.3.3
OpenGL Examples........................................................................................................ 4
2
Conclusion................................................................................................................................. 4
3
Resources.................................................................................................................................. 4
The topic of this paper is graphics programming
techniques on the Win32 platform. It
explains some of the most popular methods of writing Windows programs featuring
advanced graphics. The source code described
in this paper was written in
So, you want to learn about Graphics? It sounds like a simple enough topic but there is an incredible variety of technologies and techniques that can be used to produce a graphical application. This paper will hopefully teach you some of the basics and show you some of the common grounds between the three most popular technologies. Armed with that knowledge, you can then you can decide which technology is best for you.
There are some trade secrets out there but there is also a wide variety of information and tools available to the general public. When the initial research for this paper was done, the popular technologies were basic GDI, DirectX 6, OpenGL, 3dFx-Interactive, 3D-Now and VRML. Even in the span of a year, the market place has changed dramatically. Microsoft has come out with two new DirectX versions. 3dFx-Interactive, a video card chip manufacturer, has been dissolved and their technology sold to NVidia. And finally, 3D-Now, a property of chip manufacturer AMD, has continued to fall into obscurity. Despite the rampant release of new technologies, there are some leaders in this race. This paper describe GDI programming which is really the foundation for all other techniques, Microsoft’s DirectX with a concentration on Direct3d since it’s the most visual, and OpenGL with its cross platform extendibility.
The more things change, the more they stay the same. A decade ago, the last time I wrote such a paper, graphics programming was a very different beast. Even at that time, half a dozen major players were fighting to say their way of doing things was the best.
A hot new technology had just been introduced “SUPER VGA”! The ability to display 256 colors at resolutions never before achieved. Suddenly the landscape changed from one where a screen full of graphics takes up at most 150K (320x200@256 colors) to one where displaying an image can take upwords to a megabyte (1024x678@256 colors). Of course, no one could agree on the best way to store that much information on the video card. Each video card manufacture had their implementation. Some stored the whole image at one memory location, others split it by even and odd rows. Others used bands of a certain size to break apart the information.
At that time, one of the first decisions a programmer
had to make was “Which video card(s) will I support?” aka “Which video card
will my target users most likely own?”.
The developer was responsible for rewriting the output section of every
program for each video card out there.
If you were to run one or two of the hottest programs of 1990 (Yes, I
confess still have some on 51/4”), the first thing you see is a prompt asking
which video card you’re using. ATI,
Chips & Technologies,
Enter stage center Microsoft Windows 3.0 and its Graphics Device Interface. Amidst early scandals of Microsoft trying to monopolize the disk operating system arena, the beauty of Microsoft Windows was missed by many. Often thought of as a just another multitasker but with one of those gimmicky “mouse” things, Windows was indeed a solution to the hardware company rivalry.
Although the idea may not have originated with Microsoft, suddenly the answer to “Which video card will my target users most likely own?” was “Who cares!!!”. Windows required a “Device Driver” for each piece of hardware attached to the computer and that “Device Driver”’s job was to know everything there was to know about how to talk to the hardware it represented. Then between the Driver and the program, Microsoft added another layer called the Graphics Device Interface or GDI. So in order to talk to ANY of the graphics cards, the application just needs to know how to use Windows’ GDI. Then the GDI uses the Device Driver to translate the instructions into a format that the hardware understands.
As far as software engineers were concerned, most of their burden had been removed. Microsoft had to deal with the combative hardware manufactures and their slew of standards. The users had to work under with Microsoft’s “Hardware Compatibility” list (see http://www.microsoft.com/hcl) and handle the installation of the latest and greatest device drivers. The developer had only to learn the GDI and their programs would work beautifully on any computer out there. Well, that was the theory any way.
The GDI is a set of objects that represent the various graphic output devices that could be connected to the computer. The Microsoft Windows Software Developer’s Kit documentation says it most succinctly:
The graphics device interface (GDI) provides functions and related structures that an application can use to generate graphical output for displays, printers, and other devices.
The GDI follows the real world analogies of Windows and provides the programmer with tools such as pens and brushes so that you can “draw” lines rather than setting series of bits values and “paint” shapes rather flooding register values.
To manipulate a specific graphic device or even just a Window, the program must ask the GDI for a device context or DC. A device context is a representation of the device and all of its qualities and abilities. It can be used to retrieve information about the device and to tell the device what its properties should be. For instance, a device context is often used to determine how many colors a printer or graphics card supports and then to tell the device to only output in monochrome. When you draw something you either draw it to the context or store up the drawing instructions in a metafile and play them to the context in one fell swoop.
Most often the application will retrieve a handle to the device context (HDC), use in a series of function calls and then release it. An HDC is essentially a pointer, so it can be passed around within the program without using up excess memory. You can retrieve a HDC by calling GetDC(). The accompanying ReleaseDC() call returns full control of the device to Windows. It is very important that the handle is released as soon as possible. Otherwise, the unfriendly things can occur such as the Windows interface locking. So a program using HDC must include carefully placed error handling to insure that the device contexts are always released.
Since each of those TCustomControl objects encapsulate all of the functionality of a device context, each has a pen and brush so you can change the colors of what you are creating. They also have the simple MoveTo and LineTo functions that emulate the old Turtle graphics technique of dragging a pen across a page. Once you add in the ellipse function for drawing circles, polygon for easily drawing complex shapes and Draw for playing metafiles onto a canvas, you have the tools to create a rather complex graphical program.
In order to understand what this program does, you first need to understand some of the basic concepts and terminology used for 3d graphics.
A point indicates a location and has no size or shape. A point is expressed as a series of numbers specify its coordinates. For example in two-dimensional space, a point is indicated by two numbers. In three-dimensional space, a point is indicated by three numbers.
An axis is line used to provide an index into space. Two-dimensional space has two standard axes X and Y. Three-dimensional space has standard three axes: X, Y and Z. The illustration below shows the X, Y and Z axes. The arrows indicate the direction of positive values (i.e. Positive Z-axis value extends into the screen while negative values draw out towards the viewer).
A vector in simplest terms is a line indicating a direction. It consists of a point and an assumed origin. If the origin is 0, 0, 0 and the vector is 1, 1, 1, then the vector points up, to the right and into the screen. A vector can also be used as an arbitrary axis around which an object can rotate.
A plane is a flat 2 dimensional surface that extends infinitely within those two dimensions. A plane is often illustrated by a grid drawn along the X and Z axes but can actually extend at any angle to any two axes.
A vertex is the point at which two vectors intersect.
A face is an area on a plane defined by vectors and
vertices. This is the first term that
tends to have different meanings depending on which graphics technology you are
dealing with. Under GDI, a face can be
any shape. However, in other
technologies such as DirectX a face is a triangular region on a plane. Under other technologies like GDI or open, a
face can be redefined at will. Under
GDI, you will define whether or not you even have faces. In the sample program, triangles are used for
faces however many other options are available.
The documentation for OpenGL illustrates several of the options that can
be
chosen. The illustration examines six
points and use different face styles express them. A GDI application could emulate any of these
or develop new faces such as hexagonal.
A normal vector indicates a vector that is perpendicular to a face or even vertex. Normal vectors are often used to indicate the plane of a face. This is especially helpful when lighting a scene. Certain lighting techniques (Gourourd, Phong and others) use normal vectors to calculate affect that a light source will have on the surfaces (planes) of an object. This can produce realistic shading and radically enhance an image. Picture one of Escher’s stairwells, normal vectors on each stair face would provide the answer, to who was climbing the stairs correctly.
More than likely, once the vectors, vertices and faces combine to make object, you will want to do something to that image. Move it, scale it, rotate it or provide the user with some other interactive response. The manipulating of a shape is less complex than one might predict. It involves the multiplication of all vertices making an object by a matrix configured to produce the desired affect.
This paper does not delve deeply into the math behind matrices; that is beyond its scope. College texts with “Linear Algebra” in the title are devoted to the topic. This paper will only provide descriptions of common tasks, show the matrix used to achieve them and provide sample helper functions to achieve the goal.
A matrix simply put is a multi-dimensional array of numbers. Matrices have the unique behavior that when multiplied by vector the result is a different vector. When this is done to all of the vectors in an object, the whole object moves. There are many ways to configure matrices to simulate real world actions like rotating, scaling, reflecting and others. Some, but not all, of these matrices are shown below and used in the GDI example.
3D Identity
Matrix [ 1 0 0 0 ] 0 1 0 0 0 0 1 0 0 0 0 1 2D Identity
Matrix [ 1 0 0 ] 0 1 0 0 0 1
The identity matrix is a very special matrix.
Essentially, it does nothing.
When you multiply a point by an identity matrix, the point remains
unchanged. This is true in both 2D and 3D
drawings. In fact, all of the matrices
shown in this paper have two and three dimensional equivalents. In most cases, the elimination of the forth
dimension of the 3D matrix will produce the 2D matrix. Since the examples in this paper are all
three-dimensional, this definition for each transformation will only include
the three-dimensional matrix.
One of the reasons that the identity matrix is so important is that almost all transformations are based off of it. A helper function that produces an identity matrix can radically simplify the production of any of the matrices shown below. Once you have an identity matrix, replacing the values you need to replace makes coding a lot cleaner.
A translation matrix is used to move an object to a different
location on the screen. It can be moved
by any amount in any direction. [ 1 0 0 0 ] 0 1 0 0 0 0 1 0 Tx Ty Tz 1
As you can see the Translation Matrix
is very similar to the Identity matrix. Replacing
any of the bottom-left values in the matrix keeps the shape and size of the
object identical to the original but moves it along a matrix. By replacing each of the X, Y and Z values,
you can move the object to an arbitrary point in three-dimensional space.
The scaling matrix increases the size of an object along any or all axes. The Scaling matrix is also very similar to the identity matrix but replaces different values. In this case the ones extending diagonally across the center of the matrix are replaced by scaling factors (e.g. A 2 for SX will double the width of the object.).
|
[ 1 0 0 0 ] 0 1 0 0 a b 1 0 0 0 0 1
A standard shear will slide part of an object and keep the remainder in its
current location. A sheared cube will
produce a parallelogram. You can of course
combine several matrices to produce extended results. If you extend shearing, with scaling, you can
get a projector affect. This is similar
to the image seen on the projector room glass in the back of the theater is
small and up high yet the image on the screen keeps same aspect ratio while
increasing in size. The a and b values
shown, in what could be called the X and Y columns of this matrix, produce a
shear along the Z axis by changing the X and Y coordinates but keeping the Z
coordinates identical.
The introduction of Sin and
X Axis
[ 1 0 0 0 ] 0 Sinq 0 0 -Sinq 0 0 0 0 1
The X-axis matrix makes objects rotate around the X-axis. If the object were centered on the X-axis,
the object would spin as if it would roll toward you. If the object were off center from the
X-axis, it would spin rotate towards and then away from you. If you look carefully at the locations of the
Cosq’s
in the X-axis matrix, while picturing a Cos wave, you can understand why the
image would scale larger as it gets closer to you and shrink as it gets further
away.
[ 0 -Sinq 0 ] 0 1 0 0 Sinq 0