Win32 Graphics Programming

 

By

 

Brian Layman

 

 

 

Professional Development

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 Delphi (a visual version of Pascal).  That means it will compile and run on the Microsoft Windows 9x, Windows ME, Win2K and Windows NT 3.5+ platforms.  However, some of the techniques described will not execute under Windows NT.  Details about such limitations are given in the appropriate sections.  Though the source samples included are in Delphi, most samples could easily be converted to C.  Since there are many C resources available for all of the techniques described in this paper, no attempt will be made to provide the details such a conversion.  This paper concentrates on 3d graphics most 2d operations can be easily extrapolated by simplifying a 3d example.Delphi 6 & 7 are available for free download if you look around.  

1 Overviews      

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.

1.1 Graphics Device Interface (GDI) Programming

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, Genoa, Paradise, Trident, Tseng Labs and Video 7 (Do any of these ring a bell?)  were the big boys and there were many other smaller companies and subdivisions, Oak to name one, selling close clones of these cards.  If you didn’t have one of those cards (or a good knock off) you were pretty much out of luck.  Often software companies would pick their favorite and one alternative and that was what their software required.  As you can imagine, it was expensive to rewrite each program seven plus times. 

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.

1.1.1 Device Contexts

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.

1.1.2 Delphi and the GDI

Delphi, doing what it does best, makes GDI programming simple by providing a wrapper.  In this case its called a TCanvas.  Simply put TCanvas is a wrapper for a device context.    TCanvas provides the functionality of a device context and handles all GetDC and ReleaseDC calls itself.  It also provides metafile handling and access to context settings through a list of common properties.  All Delphi controls that descend from TCustomControl have a Canvas property.  This list includes objects like TBitmap, TForm, TImage, TPanel and TPrinter.  With those five objects you can produce a very robust graphics program and even send screen shots to the printer.  

1.1.3 Common Tools

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.

1.1.4 3D Concepts

In order to understand what this program does, you first need to understand some of the basic concepts and terminology used for 3d graphics.

1.1.4.1 Point

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.

1.1.4.2 Axis

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).

1.1.4.3 Vector

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.

1.1.4.4 Plane

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.

1.1.4.5 Vertex

A vertex is the point at which two vectors intersect.

1.1.4.6 Face

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.

               

1.1.4.7 Normal Vector

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.

 

1.1.4.8 Transformations

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.

1.1.4.9 Matrices
1.1.4.9.1 What is a matrix?

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.

1.1.4.9.2 The Identity Matrix

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.

1.1.4.9.3 Translation

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.


1.1.4.9.4 Scaling

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.1.4.9.5

[

Sx

0

0

0

]

0

Sy

0

0

0

0

Sz

0

0

0

0

1

 


Shearing

[

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.

 

1.1.4.9.6 Rotation

The introduction of Sin and Cos to matrices produces cyclical results.  The object appears to rotate or spin.  The angle of rotation, represented by q, is sin’ed or cos’ed when the matrix is produced.  One simplification that can be made to rotation code is to always multiply the original image by the full amount of the rotation.  Contrary to the real world, you don’t save time by rotating the object less each time.  Rotating an object by 1,818 degrees is just as fast as rotating it by 18 degrees.  In that fashion to have a continuously rotating object, you don’t keep rotating by 5 degrees each time, you can have a for loop that steps by 5 and always rotates the original image by the for variable.  All rotation matrices work in the same fashion but replace different locations within the matrix.  


X Axis

[

1

0

0

0

]

0

Cosq

Sinq

0

0

-Sinq

Cosq

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.

 

[

Cosq

0

-Sinq

0

]

0

1

0

0

Sinq

0