Writing HOT Games for Microsoft(r) Windows(tm) The Microsoft Game Developers' Handbook Microsoft Windows(tm) Multimedia 4/94 TABLE OF CONTENTS Table of Contents Microsoft Windows Multimedia We're serious about games Millions of new 32-bit game machines on the way! It ain't over yet The Windows Market Chicago as a Game Platform 1 Fast, Flexible Graphics WinG overview: Other graphic enhancements 2 Easy to Support 3 Powerful Development Environment 4 Built-in Digital Video Support 5 High Quality, Flexible Sound 6 Support for Multi-player Games 7 Synchronization 8 Toys 9 3D for Windows Appendix A: PRELIMINARY WinG Documentation Why WinG? Off-screen Drawing With WinG Using GDI With WinGDCs Halftoning With WinG Maximizing Performance With WinG 10. Take Out Your Monochrome Debugging Card 9. Store WinGBitmap Surface Pointer and BITMAPINFO 8. Don't Make Redundant GDI Calls 7. Special Purpose Code May Be Faster Than GDI 6. Time Everything, Assume Nothing (Ruminations on good coding practices) 5. Don't Stretch 4. Don't Blt 3. Don't Clip 2. Use an Identity Palette 1. Use the Recommended DIB Format DIB Orientation Top-Down DIBs Using an Identity Palette Static Colors Other Colors Creating an Identity Palette Palette Animation With WinG Accessing a Full Palette Using SYSPAL_NOSTATIC WinGBitBlt WinGCreateBitmap WinGCreateDC WinGCreateHalftoneBrush WinGCreateHalftonePalette WinGGetDIBColorTable WinGGetDIBPointer WinGRecommendDIBFormat WinGSetDIBColorTable WinGStretchBlt WING_DITHER_TYPE Debugging WinG Applications Shipping a Product With WinG Code Samples Balloon Doggie Sample Spinning Cube Sample WinG Timing Sample WinG Halftoning Sample WinG Palette Animation Sample WinG Glossary Further Reading MICROSOFT WINDOWS MULTIMEDIA Microsoft is committed to making Windows a leading force in multimedia technologies and systems. Our commitment takes many forms, but the most important one for independent software vendors is our commitment to substantial and ongoing investment in multimedia-related R&D. In this handbook we explain some new innovations in Windows that will be of particular interest to game developers. We're serious about games For the past year, the home market has been the fastest-growing segment of the PC business. More and more of our customers are telling us that they want games for Windows ¾ and at this point, there aren't many. Games are already the largest category of multimedia application, but most of today's computer games are running on MS-DOS(r). In fact, at the end of 1993 computer games were one of the last remaining software categories for which Windows product sales trailed MS-DOS product sales. Not that this should come as any surprise. Until now, game graphics under Windows made slug racing look exciting. The only way for Windows to succeed as a game platform is for developers to write great games for it. This Handbook is designed to help you do that. And the WinG library delivers graphics performance approaching raw MS-DOS speeds. Millions of new 32-bit game machines on the way! There are over 100 million MS-DOS based personal computers in the world ¾ and over 40 million of those are running Windows. The home PC market is growing fast, and a very large portion of the machines being sold into homes are equipped with the kinds of devices that should make game developers smile: CD-ROM drives, sound subsystems, and 4MB of RAM or more. With the release of Chicago, a GIANT new 32-bit game platform will be born. This handbook: 1 explains some of the new features and capabilities of Chicago that make it possible for you to write great games for the world's next PC operating system; and 2 introduces the WinG libraries, a development tool that you can use to write high-performance graphical games for Windows today. It ain't over yet It's important to emphasize that the technologies described in this handbook aren't the end of the story. Quite the contrary ¾ we've made some very important first steps, but there's a lot of work to be done in the years ahead. Please tell us how we can make Windows a great platform for your games! We've invested a lot of effort making Windows into the leading environment for "serious" applications. Now comes the fun part! To send a suggestion to the Microsoft Windows Multimedia team, GO WINMM in CompuServe(r) or send email to mmdinfo@microsoft.com. Microsoft, MS-DOS and Visual Basic are registered trademarks and Windows is a trademark of Microsoft Corporation. CompuServe is a registered trademark of CompuServe, Inc. VoiceView is a trademark of Radish Communications, Inc. THE WINDOWS MARKET It has now been over four years since the release of Windows 3.0, and the software market is greatly changed. For example: * The majority of new PCs sold now come with Microsoft Windows pre-installed. * Virtually every PC peripheral and add-in board on the market (including sound cards) ships with drivers and installation instructions for use with Microsoft Windows. * In virtually every software category (with the exception of games), sales of software for Windows outpace sales of software for MS-DOS. Windows is a growing, active platform, and coming developments will help to make it more so. "Chicago" is the code name for the next version of Windows. Analysts who have reviewed Chicago in its prerelease form are already concluding that this new operating system will be the biggest news to come from Microsoft since the release of Windows 3.0. Until recently, the Windows-based personal computer hardware and software businesses focused almost exclusively on the office desktop. That focus is broadening rapidly: * Home PCs are the fastest-growing category of the PC hardware business, and home buyers are demanding multimedia capabilities in their PCs. * Laptop and notebook computers are an increasingly important share of the business, and they are helping to establish the modem as a standard PC device. * Non-business software categories (including games) are rapidly growing into the multi-billion dollar range. These trends show no signs of stopping. As PCs become an increasingly common appliance in the home, we can count on the following corollaries: * The average level of computer knowledge among home users will decline. * The market will favor ease of installation and ease of use as features of home software products. Products that are obnoxious or scary to install won't sell well in the broad home market. These forces will help support the continued success of Windows software in the home market, which presents an important opportunity for the game development community. There are millions of PCs with Windows in homes today, and relatively few Windows-based games. The market forces above make it pretty clear that there's a big market out there, waiting for the right Windows-based game products to come along. Got any ideas? CHICAGO AS A GAME PLATFORM This chapter describes some (not all!) of the features of Chicago that will make it an important release for you as a game developer. In the case of our work on graphics speed, this chapter also describes how WinG makes it possible for games to smoothly transition to Chicago while maintaining compatibility with Windows 3.1 today. This document is an overview of our technology and development plans as they relate to games. Further technical articles about implementing games on Windows can be found in the Microsoft Developer Network. (For a subscription, call Microsoft at 1-800-759-5474. Outside the US and Canada, call 402-691-0173 for a distributor in your country.) Naturally, we are interested in your input in all of these areas, as we are very committed to making Windows the best game operating system possible. The best way to reach us is through the new CompuServe forum for game developers ¾ GO WINMM. Or send email to mmdinfo@microsoft.com. Discussed here are the following topics: 1 Fast, Flexible Graphics 2 Easy to Support 3 Powerful Development Environment 4 Built-in Digital Video Support 5 High Quality, Flexible Sound 6 Support for Multi-player Games 7 Synchronization 8 Toys 9 3D for Windows 1 Fast, Flexible Graphics The speed of graphics (or, more appropriately, the lack of it) in Windows 3.1 has been the most important obstacle keeping game developers from choosing the Windows platform for their games. We have addressed this issue head-on in a way that provides substantially improved speed while preserving the device independence that makes Windows appealing in the first place with a new graphic library called WinG. WinG provides close to the graphic performance of MS-DOS based games with all of the device independence of Windows. (For detailed information about the WinG library, see Appendix A) WinG overview: Fast graphics. Blts directly to the frame buffer from Device Independent Bitmaps in memory, allowing performance approaching raw MS-DOS speed on any given Windows compatible computer. Compatible with Windows 3.1 and Windows NT. Runs across Microsoft operating systems, including the millions of copies of Windows 3.1 installed today, and uses the fastest available blting mechanism on each OS. Color. WinG is optimized for all color depths and graphics resolutions under Chicago and Windows NT. For WinG on Windows 3.1, MS-DOS-class graphic performance is optimized for 256-color source animation. Free. The WinG library will be freely available to developers and redistributable at no cost. This library will be available on CompuServe in the WINMM forum by the end of May, 1994. 32 bit. WinG will be available in both 16- and 32-bit versions, allowing you to create full Win32 games. Other graphic enhancements Chicago games will also be able to take advantage of the following enhancements to the operating system: On-the-fly control of screen resolution makes it possible to dynamically configure the display to achieve optimal speed and graphics quality for your game. Offscreen buffering and other hardware-level video functionality not accessible in Windows 3.1 will also be supported in Chicago. Device-independent color support in Chicago will allow you to ensure that your graphic colors are consistent across all different types of video cards and displays. 2 Easy to Support Every support call might as well be a lost sale. Providing customer support for games ¾ or any software, for that matter ¾ is very, very costly. In fact, the margin that game developers typically make from the sale of a game are generally low enough that the cost of one support call for installation or configuration can actually eliminate the profit earned from that sale. Developing your game for Chicago and/or Microsoft Windows 3.1 will help you decrease support costs in four ways: * Windows memory management busts the 640K conventional memory barrier for you, gives you up to gigabytes' worth of linear 32-bit addressable memory and eliminating the need to fiddle with customers' CONFIG.SYS file during setup. A huge portion of all support calls relate to setup. * Windows device independence frees you from a lot of card-specific coding ¾ and support. Use the standard Windows APIs and your product will work with all Windows-compatible devices. * Not your dime. Importantly, if you've written your game for Windows and your user's sound card doesn't go "whoooosh!" when it ought to do so, your game isn't the culprit. Microsoft (or the sound card maker) gets the phone call, not you. * In Chicago, a new feature called Plug and Play will make it easier for users to add devices ¾ such as CD-ROM drives or sound cards ¾ to their systems. This will help to further increase the market for games, facilitate upgrades, and take support pressure off of game developers. Windows offers device-independent support for: * CD-ROM drives * Sound cards * Video Displays * Digital video acceleration boards (including MPEG) * Printing * Networking * Modem * Joystick, and * Pointing devices including the mouse (of course) 3 Powerful Development Environment The tools for writing Windows code have evolved greatly over the last few years. We aren't saying that your job is in danger ¾ the code doesn't write itself. But some of the least rewarding parts have been substantially automated, and there are good tools now available to help you write code that you can reuse from one project to the next. For example: * Microsoft Visual C++. Provides a fully integrated graphic development environment for Windows applications that makes it simple to create a GUI application utilizing sophisticated functionality such as networking, WinG, Object Linking and Embedding, sound, digital video, and so forth. * Object Linking and Embedding (OLE) is an object technology made available for all Microsoft operations systems and the Mac that greatly facilitates the exchange of information and functionality between unrelated applications. The availability of this technology creates game possibilities previously unimaginable in the MS-DOS world, such as: * Drag & Drop monsters from one game space to another; * provide standard interfaces that others can use to develop or extend functionality for your game worlds; * embedding game sessions into mail messages that can automatically connect you over a network or modem, etc. 4 Built-in Digital Video Support For the past several years, Microsoft has been developing a high-performance architecture for digital video ¾ Microsoft Video for Windows. In the past, Microsoft Video for Windows has been sold separately (principally as a Software Developers' Kit). With the release of Chicago, it will be built right into the operating system. For the first time, the ability to play digital video will ship with every copy of Microsoft Windows. If you include digital video in your game, Windows can play it back for your customers, regardless of the display board that the customer may have installed. Your customers don't need special hardware to play your game ¾ any VGA card will do. More information on Microsoft Video for Windows is available on MSDN and in the Microsoft Video for Windows software developers kit. 5 High Quality, Flexible Sound Microsoft Windows offers device independent sound allowing applications to call standard APIs to drive sound boards without worrying about the hardware-specific details. The high-level MCI sound APIs make it relatively straightforward to play a given sound with minimal coding effort. The low-level WAV APIs provide more precise control over arbitrary digital sound. MIDI APIs are also provided. For mixing sound, Microsoft offers a library called WAVEMIX.DLL, which can merge up to four channels of sound into a single stream on the fly. WAVEMIX can be found on CompuServe and on the Microsoft Windows Multimedia Jumpstart CD. To make the burden of storing and playing sound less onerous, Chicago includes a family of sound compression technologies ("codecs"). These codecs can be divided into two groups: * Music-oriented codecs (such as IMADPCM) are included that allow close to CD-quality sound to be compressed to about one-quarter size. * Voice-oriented codecs (such as TrueSpeech) are included to allow very, very efficient compression of voice data. This support for compressed sound is two-way ¾ you can play sound from a compressed sound file, or you can compress a sound file (using the built-in sound recording and editing utility). If you have a microphone, you can turn on voice compression when recording so that your file is compressed in real-time. 6 Support for Multi-player Games The much-touted information superhighway holds great promise in lots of areas, but one of the least controversial is the opportunity it might provide for cool multi-player games. Why wait for the information superhighway? Chicago offers two technologies that make Windows-based multi-player games viable right away: * Networks offer great promise for multi-player games, but network support has been added to relatively few MS-DOS-based games today. This is principally for technical reasons ¾ there are scores of different network hardware and software challenges, and even getting a game to run can be frustrating and expensive to support. It's much, much simpler in Windows ¾ you don't have to write the networking code, you don't have to work around the network's memory space, and you don't have to take the network support calls. A Windows technology called WinSockets makes it possible to write games for a broad variety of network types including Novell, Banyan Vines, Windows for Workgroups, LAN Manager, TCP/IP and others without worrying about which one is in use. * Modems. In addition to easy modem setup and configuration, Chicago provides support for a new modem technology called VoiceViewThis technology lends itself well to games that involve "taking turns," and will help to put the appeal of human interaction into modem-based games. VoiceView will be shipped as a standard feature of virtually every modem in 1995 Until now, modem users have had no choice ¾ they can either talk on the phone or use their modem, but not both. (If you want to talk, you generally have to disconnect the modem and call back, or else get a second phone line.) This makes modem-based 2-player games pretty unappealing, because talking to your opponent is half the fun, right? With VoiceView, you can play and talk to your opponent in the same phone call. Here's how it works: * Run one phone line from the wall to the "in" port of your VoiceView-capable modem, and another from the "out" port to your phone. * Turn on your PC and call up your friend (who also has a VoiceView-capable modem). * Talk for as long as you like. When you feel like it, launch a 2-player game ¾ we'll use chess as an example. * When you make a move, you will hear a brief beep, and your modems will take over the phone line for a moment. (You can't talk while the modems are conversing). A simple message like a chess move takes less than one second to communicate. * When you're done (or have to go eat dinner), hang up like you always do. 7 Synchronization Synchronization of sound with events is crucial for cutting-edge games. In Chicago, you can write 32-bit games that use threads to manage processes that occur simultaneously (such as sound, scoring and animation). In the past, many game developers have written their own multitasking engines under MS-DOS to build this sort of functionality. The multitasking support in Chicago will free you from this low-level coding so that you can invest more of your effort on features. Chicago has a default preemptive thread scheduling grain of 20 ms, meaning that if there are not a lot of other background activities, a foreground application (or high-priority thread) can be assured of constant and frequent attention from the OS. If that isn't fast enough, it's possible to set the grain as fast as 1ms. Chicago provides fine event control and scheduling objects that facilitate writing tightly synchronized multitasking applications. The ability to manage sound as a separate thread of your program allows multimedia titles and games to have a more smooth, finished feel to them. For example, a game might have a thread that plays background music continuously during game play. This would help smooth out the breaks between scenes, when the game is loading new data ¾ on another thread of the program. Threading provides for asynchronous I/O that makes it possible to carry on sound and animation while hitting the network or file system at the same time. Another area of synchronization that is important to a successful action game is synchronization of input with action. Again, using threading you can control the polling rate of input devices and ensure that your game feels crisp and responsive. In addition to a thread scheduler, Chicago also provides access to a configurable event timer that can generate clock messages at up to 1ms. 8 Toys Support for game devices will be built right into Chicago. Aside from the obvious support for the mouse and the keyboard, Chicago will also include built-in support for joysticks. 9 3D for Windows Windows NT (Daytona) will ship with the industry standard OpenGL libraries included as a standard part of the Windows Graphic API. We anticipate that this will make Windows NT a great authoring environment for 3D software. Microsoft will also make the OpenGL libraries available on Chicago, so that the same authoring tools can run on both Chicago and Windows NT. To enable the market for 3D accelerators, Microsoft will publish the 3D-DDI (device driver interface), which will make it possible for hardware vendors to accelerate 3D graphics for MS-DOS, Windows, and Windows NT. Our OpenGL implementation will utilize hardware acceleration via the 3D-DDI whenever it is available. The 3D DDI is an open interface, enabling other 3D rendering APIs such as HOOPS and PeX to coexist with OpenGL on Windows. Although general-purpose 3D libraries are not practical for most games today, we hope that our support for OpenGL and the 3D DDI will rapidly grow the installed base of 3D hardware accelerators. APPENDIX A: PRELIMINARY WING DOCUMENTATION Why WinG? Although business applications such as word processors and spreadsheets have moved overwhelmingly to Windows, MS-DOS remains the operating system of choice for games. These applications have not made the transition to Windows largely for performance reasons ¾ in a word, speed. The performance of games under Windows has suffered because of restrictions placed on the programmer by GDI's device independence, by the windowed environment, and by the inability of general graphics libraries to provide the necessary speed. Most MS-DOS game programmers use knowledge specific to their application and their hardware to write optimized graphics routines. Until now, Windows programmers could not use such methods because GDI prevents access to device-specific surfaces; programmers can not draw directly onto the surface of a GDI device context. WinG (pronounced "Win Gee") is an optimized library designed to enable high-performance graphics techniques under Windows 3.1, Chicago, and Windows NT. WinG has been developed as a key component of the Microsoft Windows Multimedia Initiative. WinG allows the programmer to create a GDI-compatible HBITMAP with a Device Independent Bitmap (DIB) as the drawing surface. Programmers can use GDI or their own code to draw onto this bitmap, then use WinG to transfer it quickly to the screen. WinG also provides halftoning APIs that use the standard Microsoft halftone palette to support simulation of true color on palette devices. Off-screen Drawing With WinG WinG introduces a new type of device context, the WinGDC, that can be used like any other device context. Unlike other DCs, programmers can retrieve a pointer directly to the WinGDC drawing surface, its BITMAPINFOHEADER, and its color table. They can also create and select new drawing surfaces for the WinGDC or modify the color table of an existing surface. DIBs become as easy to use as device-specific bitmaps and compatible DCs, and programmers can also draw into them using their own routines. Most often, applications will use WinGCreateDC to create a single WinGDC and will use WinGCreateBitmap to create one or more WinGBitmaps into which they compose an image. The application will typically draw into this buffer using DIB copy operations, GDI calls, WinG calls, and custom drawing routines, as shown here. A double-buffering architecture for WinG Once DIB composition for the current frame is complete, the application will copy the WinGDC buffer to the screen using WinGStretchBlt or WinGBitBlt. This double-buffering architecture minimizes flicker and provides smooth screen updates. Many games and animation applications draw their characters using sprites. On arcade machines, sprite operations are performed in hardware. Under DOS with a VGA, games simulate sprite hardware using transparent blts into an off-screen buffer. The DOGGIE sample application (in the SAMPLES\DOGGIE directory of the WinG development kit) uses WinG in the same way to perform transparent blts to a WinGDC and includes source code for an 8-bit to 8-bit TransparentDIBits procedure. Using GDI With WinGDCs WinG allows drawing onto the DIB surface of a WinGDC with GDI, but there are some anomalies to keep in mind. 1 Most importantly, GDI does NOT regard WinGDCs as palette devices. WinGDCs are actually RGB devices with a fixed 256-color color table. You happen to be able to modify the device color table using the WinGSetDIBColorTable API, but the color table is considered static by GDI. You can't select or realize palettes in a WinGDC. The Palette Animation With WinG article describes how to match a given palette to a WinGDC color table. 2 Drawing with GDI on a WinGDC surface does not always produce a pixel-perfect duplicate of the image you would see using GDI on a display device. The images will be similar, but some stray pixels will remain if you XOR the two images together. Brushes realized in a WinGDC will be aligned to the upper left corner of the WinGDC whereas brushes used in screen DCs are aligned to the upper left corner of the screen. This means that when you blt a WinGDC that has been filled with a pattern into a screen DC that has been filled with the same pattern, the patterns will not necessarily align correctly. If you have this problem, you can either change the brush origins and re-realize the brushes in either DC (see the section "1.6.8 Brush Alignment" in the Windows SDK Programmer's Reference Volume 1, also available on the Microsoft Developer Network CD) or you can make off-screen brushes align correctly with on-screen brushes by blting the WinGDC to a brush-aligned position on the screen. For example, an 8x8 brush pattern can be correctly aligned to the screen by blting the WinGDC to an x, y position when x and y are both multiples of 8. Halftoning With WinG WinG allows applications to simulate true 24-bit color on 8-bit devices through the WinG halftoning support APIs, WinGCreateHalftonePalette and WinGCreateHalftoneBrush. The halftone palette is an identity palette containing a carefully selected ramp of colors optimized for dithering true color images to 8-bit devices. The WinGCreateHalftonePalette function returns a handle to a halftone palette which applications can select and realize into a display device context to take advantage of the halftoning capabilities offered by WinG. The brushes returned by the WinGCreateHalftoneBrush API use patterns of colors in the halftone palette to create areas of simulated true color on 8-bit devices into which the halftone palette has been selected and realized. The CUBE sample application (in the SAMPLES\CUBE subdirectory of the WinG development kit) uses halftoned brushes to generate a wide range of shaded colors on an 8-bit display. The halftone palette gives applications a framework for dithering 24-bit images to 8-bit devices. The palette itself is a slightly modified 2.6-bit-per-primary RGB cube, giving 216 halftoned values. The 256-color halftone palette also contains the twenty static colors and a range of gray values. Given a 24-bit RGB color with 8 bits per primitive, you can find the index of the nearest color in the halftone palette using the following formula: HalftoneIndex = (Red / 51) + (Green / 51) * 6 + (Blue / 51) * 36; HalftoneColorIndex = aWinGHalftoneTranslation [HalftoneIndex]; The aWinGHalftoneTranslation vector can be found in the HALFTONE source code. The HALFTONE sample (in the SAMPLES\HALFTONE subdirectory of the WinG development kit) applies an ordered 8x8 dither to a 24-bit image, converting it to an 8-bit DIB using the WinG Halftone Palette. Applications should avoid depending on a specific ordering of the halftone palette by using PALETTERGB instead of PALETTEINDEX to refer to entries in the palette. Maximizing Performance With WinG Here is the WinG Programmer's Guide to Achieving WinG Nirvana, the Top Ten ways to maximize blt performance under Windows using WinG. 10. Take Out Your Monochrome Debugging Card Eight bit monochrome video cards can turn the 16 bit 8 MHz ISA bus into an 8 bit 4 MHz PC bus, cutting your video bus bandwidth by up to 75%. Monochrome cards are an invaluable aid when debugging graphical applications, but when timing or running final tests, remove the card for maximum speed. 9. Store WinGBitmap Surface Pointer and BITMAPINFO WinGCreateBitmap takes a BITMAPINFO, creates an HBITMAP, and returns a pointer to the new bitmap surface. Store the BITMAPINFO and pointer at creation time with the HBITMAP rather than call WinGGetDIBPointer when you need it. 8. Don't Make Redundant GDI Calls GDI objects such as brushes, fonts, and pens, take time to create, select, and destroy. Save time by creating frequently used objects once and caching them until they are no longer needed. Move the creation and selection of objects as far out of your inner loops as possible. 7. Special Purpose Code May Be Faster Than GDI There may be many ways to accomplish a given graphics operation using GDI or custom graphics code in your application. Special purpose code can be faster than the general purpose GDI code, but custom code often incurs associated development and testing overhead. Determine if GDI can accomplish the operation and if the performance is acceptable for your problem. Weigh the alternatives carefully and see number 6 below. 6. Time Everything, Assume Nothing (Ruminations on good coding practices) Software and its interactions with hardware are complex. Don't assume one technique is faster than another; time both. Within GDI, some APIs do more work than others, and there are sometimes multiple ways to do a single operation-not all techniques will be the same speed. Remember the old software development adage: 90% of your time is spent executing 10% of the code. If you can find the 10% through profiling and optimize it, your application will be noticeably faster. Timing results may depend on the runtime platform. An application's performance on your development machine may be significantly different from its performance on a different runtime machine. For absolute maximum speed, implement a variety of algorithms, time them at runtime or at installation, and choose code paths accordingly. If you choose to time at installation, remember that changes to video drivers and hardware configuration after your application has been installed can have a significant effect on runtime speed. 5. Don't Stretch Stretching a WinGBitmap requires more work than just blting it. If you must stretch, stretching by factors of 2 will be fastest. On the other hand, if your application is pixel-bound (it spends more time writing pixels to the bitmap than it does blting), it may be faster to stretch a small WinGBitmap to a larger window than it is to fill and blt a WinGBitmap with the same dimensions as the window. Your application can respond to the WM_GETMINMAXINFO message to restrict the size of your window if you don't want to deal with this problem. 4. Don't Blt "The fastest code is the code that isn't called." Blt the smallest area possible as seldom as possible. Of course, figuring out the smallest area to blt might take longer than just blting a larger area. For example, a dirty rectangle sprite system could use complex algorithms to calculate the absolute minimum rectangles to update, but it might spend more time doing this than just blting the union of the dirty areas. The runtime environment can affect which method is faster. Again, time it to make sure. 3. Don't Clip Selecting GDI clip regions into the destination DC or placing windows (like floating tool bars) over the destination DC can slow the blt speed. Clip regions may seem like a good way to reduce the number of pixels actually sent to the screen, but someone has to do the work. As number 4 and number 7 discuss above, you may be better off doing the work yourself rather than using GDI. An easy way to test your application's performance when clipped is to start the CLOCK.EXE program supplied with Windows. Set it to Always On Top and move it over your client area. 2. Use an Identity Palette WinGBitmaps without identity palettes require a color translation per pixel when blted. 'Nuff said. See the Using an Identity Palette article for specific information about what identity palettes are, how they work, and how you can use them. 1. Use the Recommended DIB Format WinG adapts itself to the hardware available at runtime to achieve optimum performance on every platform. Every hardware and software combination can be different, and the best way to guarantee the best blt performance is to use the DIB parameters returned by WinGRecommendDibFormat in calls to WinGCreateBitmap. If you do this, remember that your code must support both bottom-up and top-down DIB formats. See the DIB Orientation article for more information on handling these formats. DIB Orientation The most frustrating thing about working with DIBs is that DIBs are usually oriented with the bottommost scanline stored first in memory, the exact opposite of the usual device-dependent bitmap orientation. This standard type of Windows DIB is called a bottom-up DIB. WinG hides the orientation of DIBs from an application unless the application wants to know. Drawing into a WinGDC using GDI functions and blting the WinGDC to the display using either of the WinG DIB copy commands (WinGStretchBlt or WinGBitBlt) results in an image that is almost identical to one created using GDI to draw directly onto a display DC. See the Using GDI With WinGDCs article for more information. If you don't plan on writing custom drawing routines and will not be using existing Windows 3.1 DIB-to-screen functions (such as StretchDIBits or SetDIBitsToDevice), you can skip the rest of this section. If you do plan on writing custom drawing routines or just want to know how they work, this section will begin to alleviate the confusion. The Microsoft Technical Articles "DIBs and Their Use" by Ron Gery and "Animation in Windows" by Herman Rodent will flesh out the ideas presented here, provide helpful advice, and describe DIBs in depth. The TRIQ sample code from Microsoft's GDI Technical Notes shows how to draw triangles and quads into a memory DIB. These articles are listed in the section Further Reading. Confusion with bottom-up DIBs inevitably stems from the fact that the bottommost scanline is stored first in memory, giving a coordinate space where (0, 0) is the lower left corner of the image. Windows uses (0, 0) as the upper left corner of the display and of device dependent bitmaps, meaning that the Y coordinates of bottom-up DIBs are inverted. In the diagram below, the smiling face casts its gaze towards the DIB origin, but when translated to the display with WinGStretchBlt or WinGBitBlt, it looks away from the display origin. Bottom-Up DIBs are flipped when copied to the display WinGStretchBlt, WinGBitBlt, StretchDIBits, and SetDIBitsToDevice invert the bottom-up DIB as they draw it to the screen. For an 8-bit bottom-up DIB, the address in memory from which the screen pixel (X, Y) is retrieved can be found with these equations: // Calculate actual bits used per scan line DibWidthBits = (UINT)lpBmiHeader->biWidth * (UINT)lpBmiHeader->biBitCount); // And align it to a 32 bit boundary DibWidthBytes = ((DibWidthBits + 31) & (~31)) / 8; pPixelXY = DibAddr + (DibHeight - 1 - Y) * DibWidthBytes + X where DibAddr is the base address of the DIB, DibHeight is the height of the DIB, lpBmiHeader is a pointer to a BITMAPINFOHEADER describing the DIB, and DibWidthBytes is the DWORD-aligned offset of bytes in memory from any X in one scanline to any X in the next scanline. Top-Down DIBs Another kind of DIB, called a top-down DIB, is stored with the same orientation as most device-dependent bitmaps: the first scanline in memory is the top of the image. Top-down DIBs are identified by a negative biHeight entry in their BITMAPINFOHEADER structures. Sometimes, WinG can greatly improve the speed of a DIB-to-screen copy by using a top-down DIB because it can avoid inverting the DIB to a device-dependent format. When this is the case, WinGRecommendDIBFormat will return a negative value in the biHeight field of the passed BITMAPINFOHEADER structure. If you are writing custom DIB drawing routines, you will have to handle top-down DIBs for best performance because there is a good chance that WinG will recommend them with WinGRecommendDibFormat. WinGStretchBlt and WinGBitBlt recognize top-down DIBs and handle them correctly, but Windows 3.1 functions such as StretchDIBits and SetDIBitsToDevice will not work properly with top-down DIBs unless you intentionally mirror the image. Top-Down DIBs are copied directly to the display For an 8-bit top-down DIB, the memory address of the pixel (X, Y) can be found with this equation: PixelAddr = DibAddr + Y * DibWidthBytes + X where DibAddr is the base address of the DIB and DibWidthBytes is the DWORD-aligned offset of bytes in memory from the beginning of one scanline to the next. The PALANIM sample application (in the SAMPLES\PALANIM subdirectory of the WinG development kit) includes a routine to draw horizontal lines into a DIB. To do this, it determines the orientation of the target DIB and performs its calculations accordingly. The DOGGIE sample application (in the SAMPLES\DOGGIE subdirectory of the WinG development kit) includes a routine to copy one DIB into another with a transparent color. The assembly function that does this also behaves well with both DIB orientations. Using an Identity Palette The Windows Palette Manager, described in depth in Ron Gery's technical article "The Palette Manager: How and Why" (see the Further Reading section for details) arbitrates conflicts between Windows applications vying for color entries in a single hardware palette (known as the system palette). It gives each application it's own virtual 256-color palette, called a logical palette, and translates entries in the logical palette to entries in the system palette as they are needed for blting images to the screen. An identity palette is a logical palette which exactly matches the current system palette. An identity palette does not require translation of palette entries, so using an identity palette can drastically improve the speed with which you can blt WinGDCs to the screen. The WinG Halftone Palette is an identity palette. This article describes how to create your own identity palettes for maximum WinG blt speed. Static Colors The Palette Manager reserves a number of colors in the palette, called the static colors, which it uses to draw system elements such as window captions, menus, borders, and scroll bars. An identity palette must include the static colors in the appropriate palette entries. The display driver defines the actual RGB values of the static colors, so they must always be determined at run time. The GetSystemPaletteEntries will retrieve the colors currently in the system palette, and you can isolate the static colors using the SIZEPALETTE and NUMCOLORS capability indices with GetDeviceCaps and a little knowledge of how the Palette Manager works. The static colors are split in half and stored at either end of the system palette. If there are nColors possible entries in the system palette and there are nStaticColors static colors, then the static colors will be found in entries 0 through nStaticColors/2 - 1 and entries nColors - nStaticColors/2 through nColors-1 in the system palette. Typically, there are 20 static colors, found in indices 0-9 and 246-255 of a 256-color palette. The peFlags portion of these PALETTEENTRY structures must be set to zero. The SetSystemPaletteUse API turns use of the static colors on and off for the system. Using SYSPAL_STATIC, 20 entries will be reserved in the palette. SYSPAL_NOSTATIC reserves only 2 entries, which must be mapped to black and white. See the Accessing a Full Palette Using SYSPAL_NOSTATIC article for more information. Other Colors The remaining non-static colors in the logical palette may be defined by the application, but they must be marked as PC_NOCOLLAPSE (see the PALETTEENTRY documentation for a description) to ensure an identity palette. A palette containing the static colors in the appropriate entries with the remaining entries marked PC_NOCOLLAPSE, selected and realized into a DC, becomes an identity palette. Because no translation to the system palette is required, the Palette Manager can step aside gracefully and leave you to achieve maximum blt bandwidth. Creating an Identity Palette The CreateIdentityPalette() function below shows how to create an identity palette from a an array of RGBQUAD structures. Before you realize an identity palette for the first time, it may be a good idea to clear the system palette by realizing a completely black palette, as the ClearSystemPalette() function below does This will ensure that palette-managed applications executed before your application will not affect the identity mapping of your carefully constructed palette. To make sure that you have successfully created and are using an identity palette, you can tell WinG to send debugging messages to the standard debug output, as described in the Debugging With WinG article. The PALANIM sample (in the SAMPLES\PALANIM subdirectory of the WinG development kit) uses these routines to create a 256-entry identity palette filled with a wash of color. Click Here to copy the CreateIdentityPalette() code sample to the clipboard. Click Here to copy the ClearSystemPalette() code sample to the clipboard. HPALETTE CreateIdentityPalette(RGBQUADWin31_API aRGB[], int nColors) { int i; struct { WORD Version; WORD NumberOfEntries; PALETTEENTRY aEntries[256]; } Palette = { 0x300, 256 }; //*** Just use the screen DC where we need it HDC hdc = GetDC(NULL); //*** For SYSPAL_NOSTATIC, just copy the color table into //*** a PALETTEENTRY array and replace the first and last entries //*** with black and white if (GetSystemPaletteUse(hdc) == SYSPAL_NOSTATIC) { //*** Fill in the palette with the given values, marking each //*** as PC_NOCOLLAPSE for(i = 0; i < nColors; i++) { Palette.aEntries[i].peRed = aRGB[i].rgbRed; Palette.aEntries[i].peGreen = aRGB[i].rgbGreen; Palette.aEntries[i].peBlue = aRGB[i].rgbBlue; Palette.aEntries[i].peFlags = PC_NOCOLLAPSE; } //*** Mark any unused entries PC_NOCOLLAPSE for (; i < 256; ++i) { Palette.aEntries[i].peFlags = PC_NOCOLLAPSE; } //*** Make sure the last entry is white //*** This may replace an entry in the array! Palette.aEntries[255].peRed = 255; Palette.aEntries[255].peGreen = 255; Palette.aEntries[255].peBlue = 255; Palette.aEntries[255].peFlags = 0; //*** And the first is black //*** This may replace an entry in the array! Palette.aEntries[0].peRed = 0; Palette.aEntries[0].peGreen = 0; Palette.aEntries[0].peBlue = 0; Palette.aEntries[0].peFlags = 0; } else //*** For SYSPAL_STATIC, get the twenty static colors into //*** the array, then fill in the empty spaces with the //*** given color table { int nStaticColors; int nUsableColors; //*** Get the static colors from the system palette nStaticColors = GetDeviceCaps(hdc, NUMCOLORS); GetSystemPaletteEntries(hdc, 0, 256, Palette.aEntries); //*** Set the peFlags of the lower static colors to zero nStaticColors = nStaticColors / 2; for (i=0; i