Vous êtes sur la page 1sur 130

Video Game Programming with Allegro

Written by Eric Pietrocupo May 1, 2005



This book allows common C programmers to learn how to program video games. Since no book editor wanted to publish my work due to the fact that I am not a native English speaker, and surely many other reasons, this book is being distributed as donation-ware. Which mean that you can download, read and distribute this PDF book as you wish. Still, if you nd it really useful, if you are actually making money with things learned from this book or if you just have to much money and dont know what to do with it, you can always make a donation to support the author. This book is being distributed on my web site ariel.bdeb.qc.ca/~ericp/allegro. You can nd on this web site the latest updates of this book, source code example, some web links, some game engines and the required information to make a donation. Thank you very much for downloading this book and as you already know, I am not a native English speaker which mean that there can be some orthographic or grammar errors. Still, I am using Ispell to reduce to most obvious errors. The goal of this book is to allow all programmers to have access to some common video game programming knowledge. By doing so, it will increase the number of open source video games or the quantity of game programming tools and engines available on the Internet. A large quantity of home made video games could also inuence greatly the video game industry, but we wont discuss this subject in this book. Video programming knowledge is becoming even more important for open source video game console, like the Game Park 32, which give the players the possibility to make their own games for their iii

console. So it is a good idea to make this knowledge available to everybody. Whatever is your reason to read this book, I hope you will nd it very useful and you will have a lot of fun to read it. Enjoy! Thank You

Eric Pietrocupo The Shadow (a.k.a. Larienna) ericp@ariel.bdeb.qc.ca



Who am I
Making video games is like making a dream come true. When I was a kid, I remember making various maps and design for video game that I could someday create. I also remember making Zelda map for new adventures I would never be able to play (Zelda Classic 1 did not exist at this time). Of course, all those designs where a bit useless since there was no way to play them. Interested about making video games, I decided to study computer programming. At the beginning, I have learned some Gwbasic programming during high school. This was an horrible language where you needed to write your line numbers. The syntax was also done during execution since it was an interpreted language. I remember my friend making up this situation : Captain, we are under attack. Quick launch the torpedoes ... Syntax error in line 3208 I made a few graphic animations programs much like a fake movie and I have made many attempts to make video games. Unfortunately, due to the lack of computer memory, programming knowledge and hard disk, the results where very poor. The best I could do was some kind of text game like a book where the reader is the hero. At this time, I was still coding in spaghetti and all text and choices where hard coded (very ugly). Then I have started programming lessons in college and I have learned the C language. I started to learn structured programming in C. Unfortunately, the C compiler did not natively include some graphic routines so I was not able to make a graphic game. I tried to make a text based game but it did not work out. There is also

the fact that I did not know anything about relational database yet. So the idea of making video games in C was soon forgotten. A few years later, while shopping for computer books, I have fallen on a book called Tricks of the game programming gurus 2 . It was a nice book that taught many video game programming logic all coded in C. I was really amazed, I bought the book and start reading. I start to practice what I had learned from the book and made a small library. A few months later, I learned Object Oriented Programming in C++ and I decided to convert my library to an object oriented video game library I started to make a game called Star Empire which was a turn based strategy space warfare game. Of course it did not nish it for many reasons : The library had many limitations, the program I was compiling were under DOS in real mode (which mean 640K memory limitation), the code was not portable since a lot of things were done in assembly , the coding took a lot of time and there was serious memory bugs in the game. From now on, I was absolutely sure that I would never go back into video game programming again. While talking to some guys on the net who wanted to recompile Free DOS in 32 bit, I was informed that there was a new DOS compiler available named DJGPP which was in fact a port of GCC for DOS. Just the idea to be able to make software in protected mode was really nice : No more memory limitation, No more memory bug and computer crash. The DJGPP web site oered a small tool to select the package of the compiler according to my need. There was a package called
Andree LaMothe et al., Tricks of the game programming gurus, Indianapolis: Sams Publishing, 1994, 746 pages.


Allegro, Video game library 3 . I said to my self that a library would not be as ecient than coding all the game at bare hand so I thought it was really a joke. Still I downloaded the whole stu and take a look at it. I checked the API of the library and I had almost lost my sanity. It had more stu that a video game programmer could ever need : conguration System, User input, Video management, Bitmap & Sprite management, Drawing function, Music, Sound, Audio Stream, Translucency, File Archive management, 3D polygons, 3D Scenes , Unicode text and even a Graphic user interface. The library compiles on many operating system and it can make the same code portable on many OS. All the hardware is auto-detected, it can take advantage of hardware acceleration if the user has the appropriate material. Surprised by everything it could do, I found quickly a tutorial4 and start learning. Using this library was so easy to learn, the functions were clear and everything you needed was there. Of course, it was easier for me to learn since I already known the video game programming logic. I only needed to know how to do this and that in Allegro. The only new thing I have learned from this FAQ was the concept of frame skipping. In about 15 minutes, I became an Allegro programmer. Finally, I decided to try making another video game which was a remake of wizardry called Wizardry Legacy 5 . It is now 70% complete available with the source code, and might never be completed. Anyways, I have learned a lot of things during this 2 years of wizardry programming and it was a nice experience even if it did not reach the end. While I was programming Wizardry Legacy, I also started, with my friend, another project called Rockman Battle Arena. It was supposed to be a ghting game containing the megaman characters and using the same kind of game play. I have learned alot of things about real-time programming while coding this game,
http://www.talula.demon.co.uk/allegro George Foot, Allegro Vivace Tutorial, http:// www.glost.eclipse.co.uk/gfoot/vivace/vivace.txt. 5 ariel.bdeb.qc.ca/~ericp/wizardry
4 3

which was totally dierent than wizardry. The only things I have not touched is the Object Spawning and Sprite to Sprite collision. I might nish these later, just for practice, since I am going to talk about it in this book. Of course the game is not nished, it is merely a demo. But on my point of view, making an engine is much more important for your video game programming experience than making a complete game. Since home made video games is not really a protable business, I am not sure if I am going to make video games again. I might make some engine or micro engines since they are small and a bit more fun to code. So I wanted to take all my knowledge about video game programming and teach it to programmers who want to actually make video games. It seems that I could not get published by a book company and I could not nd a place where I could teach video game programming. So I said to my self that I will write a virtual book and distribute it on the net to nally pass my knowledge to the next generation. So I hope you will like this book, and I hope it will help you understand better video game programming. Enjoy reading and have fun.

What is Allegro
Allegro is a recursive acronym which stand for Low LEvel Game ROutines. Allegro is a library of plain C functions and procedures that are used specically for video game programming. The whole library is in plain C except for one class (x) which has been made for those who want to code in C++. Even if the library is in C, you can still make your game in C++ without any problem. When I say C++, it mean using an Object Oriented programming structure, not using the C++ Libraries like Iostream or container classes. In fact, you should not use Iostream or any other library that has not been optimized for maximum speed as required in video games. The library was started by Shawn Hargreaves and it is now being developed by a group of independent programmers. They continuously vi

Video Game Programming with allegro add new features to the library and some people are managing the various ports of the library. The library is distributed as gift-ware which mean that you can make free-ware, share-ware and even make commercial games without having to pay any royalties. This can be interesting if you want to make some prot with your games, still it could be a good idea to show at the beginning of your game that is was powered by Allegro. There are many pictures and logo that you can download from their web site to incorporate them in your game. As I have said before, the library support many things. The sections that you will mostly use is the User input, the graphic output, bitmap management, audio output and the datale management. There are a few thing that you might never use like the graphic user interface (a window like interface), the unicode string conversion, Conguration function (conguration is generally done automatically). Allegro comes with many examples that you can look at in order to test the performance on your computer or learn how to do it. Allegro comes also with 2 utility program : the grabber and the setup. The grabber is a program that allows you to import les like images, music and sound to group them all into one compressed archive le which will be opened during the game by the datale routines. The setup program is a small hackable program that you include with your game to set the Audio, Joystick and some other conguration of your game. This setup will produce a conguration le "allegro.cfg" loaded automatically by allegro. In these days, most video games runs on Windows but who said that windows was the best OS to run a game? On my point of view, the multitasking, instability and the permanent GUI environment of this OS makes it the worst. This is why, allegro is not dependent to only one operating system, it supports : Linux, Windows, DOS, BEos, Unix, MacOS, QNX and maybe more. Which means you compile on the OS you like and recompile on all other OS to allow everybody to play. Porting is not magical, there is a few adjustment and precautions to make but you can make the same source code recompilable on many OS. Linux is the most picky OS, but if it runs on Linux vii without segmentation fault, you are almost sure that there is no memory bugs. By the way, DOS has been mentioned in the list. Yes, DOS still exist and it is not obsolete. In fact, it is one of my favorite OS and I think that this should be the perfect OS to run Video games since it is is monotasking and the OS layer is very thin. When you compile under DOS, you should use DJGPP in order to get a 32 bit protected mode application. You will have to include a driver called cwsdpmi 6 with your game in order to access protected memory. This driver is normally used by most recent DOS application so it should normally already be installed on the users machine.

About this book

This book it primarily the target of C programmer who know all the programming basics and many programming concepts and algorithms like : Pointers, Chained lists, Recurrence, Sorting, etc. You must also know a bit about the computer internal like interrupt vectors, but still Ill try to give some basic information to make sure you wont get lost. For those who knows little about C programming and computers, you will probably be able to use the rst and second part of this book. It will allow you to draw pictures, play sound, make graphics, etc. It can still have some uses to you but you wont be able to make a full professional video game. Most of the book covers 2D video game programming. In this age, 2D games seems to be forgotten. 3D games are not necessarily better that 2D games, they are just dierent. The logic behind 2D and 3D games looks alike. Of course, some stu in this book will be useless in a 3D game but I dont think it is a good idea to directly start with 3D programming. Video game programming is complex and 3D game programming is even more complex. I think we should start with something simple, it will make it easier for your to understand. Then if you wish, you can promote your knowledge to 3D programming. I will also take a lot of examples from


the NES, SNES, SMS and Genesis video game consoles. These consoles make the golden age of video games, there is a lot of interesting examples that we can examine. When nished with this book, you will easily nd color palette animations in the games you play and you will criticize the collision detection when you die. This book is divided in 4 parts. The rst parts explain the basic concepts of the hardware used in video games like the graphic card, the sound card and the various input devices, and it teach the various allegro routines to manage this hardware. The 2nd part explain other allegro function really useful but that does not necessarily manage some hardware. In the third part, we now enter deeply into video game programming. You will learn various concept and algorithms used in video games. These algorithms have nothing to do with Allegro, but we will use Allegro to experiment them. Finally, the last section is reserved for the design of the game. It talk about many popular game engines, Articial intelligence and some ideas and guide lines to build a well balanced and interesting video game. Again, this section is not specic to Allegro and it can be implemented by using another library. Of course this will not cover all aspect of allegro but it should cover most aspect of video games. The problem is just to get started, when you nally know the logic behind video games, you can start making your own algorithms and innovations. Even if the book is missing some points, you will now have the required experience to investigate yourself and this is what I want you to have.

including the fact that it must run at a reasonable speed, makes video game programming a bit more complex than a normal application. When you create a video game there are various areas to develop which does not necessarily require the same expertise. A video game generally need more than one person in its sta. Some do the coding, some the artwork, another one is managing the teams, etc (take a look at any video game credits). What ever is the video game, all the video games should have the same concept, take a look at this diagram below. Figure 1: Video Game Abstract

Video game structure

What is a video game? It is a program where the main objectives is to have fun ( something forgotten by game companies in theses days who invest everything in the graphics ). This program use much more resources than a normal program in order to make the game more interesting. It use Audio, Video, Input and Processing power all at the same time. The usage of all these resources,

Any video game can be represented by this diagram. All the entities located to the left side of the doted line requires some computer programming while all entities located on the right side can be done by non-programmers. To the right, we have the game data which includes all the levels, maps, equipment, monster stats, etc. It mostly contain information related to the design and the rules of the game. The artwork contains all the images, sounds, movies and other media used by the game to make it more beautiful and attractive. To the left, inside the big square, we have the engines. Engine is the core of the game and its coding is generally small but complex. A game can use many engine : Menu engine, Side Scroller engine, map engine, database engine, etc. These engines can also be subdivided into micro engines. viii

Video Game Programming with allegro The advantage of engines is that you can reuse them in other video games with minor modications in order to reduce the coding time of the whole game. The entity include the engines contains the code to make the engine communicate and the code specic to the design of the game. It allows to implement the rules and the game-play of the game. This is the long but simple part of video game programming. Reducing the the size of the games code by using more sophisticated engine can reduce the development time of the game. If you wish, you can nd an engine made by somebody else on the net and make a game with this engine. Finally, the controller entity contains all the code that inuence the action of the game. User input, articial intelligence and network communication are part of the controller entity. All these parts can be of dierent size according to the type of the game. For example a Tetris game, will have no game data, a few artwork, The puzzle engine, little game code and almost not controller code. For my wizardry legacy game, there was few game data since I did not supply any adventure, there was many artwork (textures and monsters), there was 3 engines (Maze, Windows and Database) a lot of game coding to implement the rules and interfaces and few controller code since the AI was fairly easy and there was no network support. Just to make you see the dierence between the engine and the game code take a look at any Grant Turismo game (Car race game on Play Station). The racing with your car in done by the engine of the game. This racing engine dont know anything about if you are currently making a test run, tournament or a drivers license test. The only things it knows is : Use this track with this car and these opponents, then return the result of the race when nished. When the race is over, the game code will take the results and say Good, you nished 3rd, so you earn X points. Since you are in a tournament you must continue with a 2nd race. Then it tells the engine : Play this track with this car. Which mean that the engine has actually no idea of whats really going on in the upper level of the game, it just follows orders. ix There is also the concept of micro engine which works for similar engines. For example, lets take a space shooter and a Z-Scroller (side scroller with a Z axis. Ex: Golden Axe). We divide our space shooter engine in three micro engines : Background (scroll and parallax), level(map and sprite), Foreground(eect and distortions). Since we need a background and maybe a foreground engine in or Z-Scroller too, we reuse theses engines and we replace the level engine by a Z-Level Engine. It can be some way to reduce development since we dont have to recode the background and foreground. Still, a completely different game engine, like a GUI, will not be able to reuse theses micro-engines except maybe for the foreground engine ( it could be cool to have some mist hide the windows ). It is a good idea to plan in advance what needs to be done. It will allows you to know the size of the project and if you need other people to the the job you cans do. As a programmer, you can be more interested in engine programming than game programming (which is currently my case). You might not also be a good artist (besides doing stick mens). So planning, will let you know where you are going and will prevent you to trace back your steps. Too much planning can slow you down too so nd the balance. Now that you have seen the concept of a video from high above, we will now start to go more deeply into video game programming but rst, you need to have the right tools to make a good job.

Table of Contents

Preface Introduction Who am I . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . What is allegro . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .

iii v v vi

About this book . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . vii Video game structure . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . viii

Technical Procedures and Harware control

3 3 5 6 9 9

1 Installation and conguration 1.1 1.2 1.3 Installation of allegro . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . Making an Allegro Program . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . Overview of the Library . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .

2 User Input 2.1 2.2 2.3 The Keyboard . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .

The Mouse . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 11 The Joystick . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 13 17

3 Video Output 3.1 3.2 3.3 xi

Video Hardware . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 17 True Color Video Mode . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 18 Palette Video Mode . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 20

TABLE OF CONTENTS 4 Audio Output 4.1 4.2 4.3 4.4 4.5


Basics of Sound . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 23 Sound Sampling . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 24 Instrumental Music . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 24 Allegro Audio . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 26 Other Audio Format . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 27


Logical Procedures used in Video Game Programming


5 Graphic Drawing Functions 5.1 5.2

Drawing Primitives . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 33 Writing text . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 35 39

6 The Allegro Bitmaps 6.1 6.2

Managing the Bitmaps . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 39 Bitmap Blitting Procedures . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 41 47

7 Translucency and Lighting 7.1 7.2

Drawing Routines Alteration . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 47 Color Blending . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 48 53

8 3D Polygons 8.1

Pre-calculated 3D Polygons . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 53 57 59

9 Allegro Conguration 10 Allegro File System

10.1 Allegro Datales . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 59 10.2 File and Compression Routines . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 62


Video Game Logic and Algorithms

69 71 xii

11 Advanced User Input 12 Advanced Video and Graphics

Video Game Programming with allegro 13 Special Eects 14 Sprites 15 Scrolling 16 Game Objects 17 Collision Detection 18 The Main Game Loop 19 Optimisations 20 Fake movies and Sprite Theaters 73 75 77 79 81 83 85 87


Video Game Design and Engines

91 93 95 97 99 101 109 113 113 115

21 Articial Intelligence 22 Data Structure 23 Popular Game Engines 24 Game Conception and Design A Exercice : Gradius Duel B How its Made References Allegro Functions and Procedures Index Allegro Variables and Constants index Index





Part I Technical Procedures and Harware control


Installation and conguration

In this chapter, you will learn how to setup your library and compiler correctly in order to start programming. If you cannot continue this book if you cant successfully compile an Allegro application. This is why we will make a test program to make sure you can compile correctly.

come with a package manager and it allows you to download allegro from there. You will need the following packages:
DJGPP 2.01 or later (djdev*.zip). GCC compiler 2.91.x or later (gcc*b.zip).


Installation of allegro

Binutils 2.9.x or later (bnu*b.zip). GNU make (mak*b.zip).

You need to install the compiler and the library. First you need to download the Allegro library at ???AllegroDownloadpage and then a C compiler if you do not have any currently installed. The library will not only give you the source code of the whole library but it will also give you all the documentation to install and download the required les according to your operating system. Look in the \docs\build directory of the library, you will see a series of text les according to your operating system. I will recopy the most important information in this book, you can always take a look at the original documentation. I am going to describe the installation for each OS, so just jump to the OS you are using.

Texinfo (txi*b.zip). Optional: rm (l*b.zip). Optional: sed (sed*b.zip).

I also strongly suggest you download RHIDE which is an Interactive development environment for DJGPP. Most of the following information can be found in the readme.1st of the djgpp installation. First uncompress all the les in a directory that does not contains a directory name \dev in the path. Let just say you install it in c:\djgpp, unzip it there with the -d ag (pkunzip) in order to create subdirectories. In c:\djgpp, there should be a djgpp.env le. Make a environment variable in you autoexec.bat called DJGPP which must point to this le. Then you should add djgpp\bin to your search path in order to compile from anywhere on your system. Here are the commands to perform these operations. SET DJGPP=c:\djgpp\djgpp.env set PATH=C:\DJGPP\BIN;


DOS Installation

There is only one compiler you can use for DOS : DJGPP. This compiler is a port from the Unix GCC. It allows you to make 32 bit protected mode applications. The compiler can be downloaded from either /pub/simtelnet/gnu/djgpp/ or http://www.delorie.com/djgpp/. I suggest you download it from delorie since the web site 3

Installation and conguration Reboot your computer. When you are back, execute "go32-v2" without argument and it will give you the amount DPMI memory available. You can also run "gcc -v" to see if your compiler works correctly. If it works, you are now ready to compile. Uncompress allegro in a separate directory with the -d option (pkunzip) to create subdirectories. Go to the root directory of allegro and type "fix djgpp" in order to x the text les for the compilation. Then run "make" to start the compilation and do something else while waiting. Then run "make install" to install the library where your compiler is located. There is two last things to note about the hardware support in DOS. First, if you have an old video card that does not support VESA 2 or above, you will have to download sci-tech display doctor 1 to correct a bug in the BIOS of the video card. This will allow you to support high resolution and high color modes correctly. This driver is not free but ... there is a way to hack the time limit ... oops! did I say something? If you have a video card with acceleration routines and you want them to be supported by DOS, you need to get the FreeBE/AF driver 2 which is a free version of VBE/AF. Download the driver and follow instructions. It will create a driver le called "vbeaf.drv" that you will have to copy in c:\ to make it works. Allegro will automatically detect it. 1.1.2 Linux Installation chmod +x fix.sh ./fix.sh unix

1.1 Installation of allegro

Then you must run "./configure" to congure the makeles according to your system. Then run "make" and go drink a coee. When every thing is compile you must install the library as root user. You can also install the help les as man pages or info pages. Here are all the commands to do the above : su -c "make install" su -c "make install-man" su -c "make install-info" By default, allegro will be installed to /usr/local so you should add a /usr/local/lib entry to your /etc/ld.so.conf le and then run ldconfig to add the path to the list. Some parts of allegro requires root privilege when executing the game. So you might need to run the game always as root, or modify the rights of the game le as follow : chown root.allegro exhello chmod 4750 exhello This will set the group of the le to allegro and it will set the suid bit. All the users who want to play the game will have to be part of the group allegro. If you want to set the suid to all the programs in the library, run "make suid" at the root of the library. When distributing the game, make sure that the user receives in with the package of your game liballeg.so. Since linux programs are linked dynamically, he need the allegro library in order to be able to run the game. 1.1.3 Windows Installation

The installation procedure is close to Unix, so you can take a look at linux.txt and unix.txt for more information. Generally, linux comes with development tools, so check you linux distribution and install the gcc compiler. Then you can install any development interface you wish, they are just so many of them so take the one you like. Once the compiler is set up, a "gcc -v" should work to test you installation. First you need to run the x program to change the text les.
1 2

http://www.scitechsoft.com/ http://www.talula.demon.co.uk/freebe/

There is two compilers available for windows: The famous Visual C++ and Mingw32 which is the GCC port for windows. I strongly suggest that you use Mingw32 since it is compatible with GCC and because you do not need to supply additional DLLs to make it work. There is a development environment for Mingw32 which is named 4

Video Game Programming with allegro dev-cpp. For the windows installation, you must also download from allegros web site the direct X support code. You can download it at http://alleg.sourceforge.net/wip.html and the name of the le is dx70 mgw.zip( you can download a more recent direct X version source if you wish). You can chose to download the compiler and the dev-cpp tool separately, or download the dev-cpp tool that includes the gcc compiler. The compiler is found here http: //www.mingw.org and the development environment here http://www.bloodshed.net/dev/ download.html. Since there is many les to download on the mingw download page, it can be confusing to know which le to download, so I strongly suggest you to download the development tool with the compiler included. Unzip you mingw32 compiler, or you devcpp package with the compiler, in a directory like "c:\mingw32" or "c:\dev-cpp". The path of the directory must not contain spaces or fancy character which means no installations in Program Files. Then unzip the direct X le into the same directory and overwrite all les. Then you need to add the c:\mingw32\bin folder to the beginning of your path. Add the path in your autoexec.bat if you have windows 9x else use the GUI to change the path ( Control Panel System Advanced Environment ). You must then dene the MINGDIR environment variable. You can also use the GUI or add the following line to your autoexec.bat. set MINGDIR=c:\mingw32 Reboot your computer and then run "gcc -v" at the command line, you should receive the compiler information. To compile allegro, unzip the library in a separate folder and use the command prompt in the allegro root folder. Execute : fix.bat mingw32 To adapt the source code to a mingw32 installation. When you are ready to compile, run 5 "make" and take a coee. When its done, run "make install" to install the library. Since the Windows programs are compiled dynamically, you must include the alleg40.dll le with your games when you distribute them in order to let the user support Allegro.


Making an Allegro Program

To get started, we will make an Hello World program. Then I will give some general explanations. I will also tell you how to compile this program for each operating system. Take a text editor or your compilers development environment and type the listing 1 on page 8( You can also nd the sources on my web site ). 1.2.1 Compiling under DOS

To compile under DOS from the command line, you must rst make an object like this : gcc -c allo.c -o allo.o Then you make the executable program by adding the allegro library : gcc allo.o -o allo.exe -lalleg This should make the allo.exe hello world program. Take note that under the DOS operating system, the allegro library is linked statically to the program. You cannot link it dynamically like on Windows and Linux. It has the disadvantage of raising the size of programs you make by 500K to 800K. If you use the Rhide environment, you can set the allegro as a default library to include in your projects compilation. Select the Options Libraries menu and add the alleg entry to the list. It is also a good idea to add the allegro function help les in order to have some help on Allegro functions. To do so, select the menu help Syntax Help Files to Search and add "allegro" to the line. Then go into the \docs\info directory of the library, copy allegro.inf help le into your \c:\djgpp\info directory of your compiler.

Installation and conguration 1.2.2 Compiling under Linux

1.3 Overview of the Library install keyboard which will setup allegro to read the user keyboard. This is essential if you wish to use keyboard functions or variable. set color depth allows to determine the color depth we wish, in this case it is 16 bits while set gfx mode actually congure and initiate the graphic mode. The rst parameter of this function is the video driver which in this case is GFX AUTODETECT. The video resolution is set 640x480 and the two other 0 are for virtual resolution which we dont use. The clear to color function allows to clear the whole bitmap screen with the color black generated by the function makecol which requires the red, green, blue values as parameters. textout centre is a text printing function which center text according to the X coordinates. We draw the text Hello World on the bitmap screen with the system font named font. The center X position is 320, the y position is 230 and the color white is generated by makecol. Then there is a while who waits for the user to press enter. readkey wait for a key to be pressed and return the result. The bit shifting with the ">> 8" command allows us to get the scan code from the result (you will see later). We compare this scan code with the code of the key ENTER hold in the constant KEY ENTER. When the user press ENTER, it pass through allegro exit which is the closing function of the library. Finally, it is very important to add END OF MAIN and the end of your main. This is a macro which magically convert your main() correctly according to the operating system you are compiling on. For example, main() will be converted to winmain() under windows.

When you compile objects, you must add "allegro-config --libs" to the command line: gcc allo.c -o allo allegro-config --libs This allow to make some special complex conguration in order to make it work. Take note that the character is not an apostrophe but a back quote. There is surely a way to add this option line to your development environment, check your tools documentation. 1.2.3 Compiling under Windows

To compile under windows, you must also add the -lalleg command during the linking. gcc -c allo.c -o allo.o gcc allo.o -o allo.exe -lalleg Of course, Dev-cpp can do this for you like Rhide does it. I am not familiar with dev-cpp so I wont describe it in details. Check in the project conguration. Another thing is that there is no .HLP help les for allegro functions. The help can be still be accessed as html pages in the \docs\html folder of the allegro library. 1.2.4 Quick view at the Hello world Program

The Hello World program we have see above is a simple program that shows an hello world string on the screen and wait for the user to press enter. Here is a line by line description of the allegro functions. First we need to include the allegro header le. #include <allegro.h> Then we start and ordinary main which can return either int or void, there is no restriction. We start our program with the allegro init function. This is an initialization function required to start using allegro, it is essential. Then we call


Overview of the Library

There are various tools and examples included with this library which are available when the library is compiled. Ill give an overview of theses programs in this section, it is a good idea to check them. The lists below contains the full path of the 6

Video Game Programming with allegro program le starting from the root of the library. Take note that the ".exe" wont appear under linux systems and that the backslash are actually slashes. 1.3.2 Allegro Demonstration

These are demos and examples program that you can check for your pleasure. The source code is supplied if you want know how it has been made. The Demo Game (demo\demo.exe): This is a demo game made by Shawn Hargreaves. It is far from being the best game in the world. It is there to test you library and see what can be done in Allegro. Examples (examples\}: This directory contains all the examples with their source code. The examples covers almost all aspect of the allegro library : Video, Audio, Input, 3D, Unicode, Translucency, etc. An index le named examples.txt indicates what each example does. Try them all, it worth it. So this is it, now that you have a library that should be running correctly, we will start programming for real with allegro.


Allegro Tools

Theses are various tools that can be useful during the development of your game.

The Grabber (\tools\grabber.exe): This is a very useful program that allows you to create datales. Datales are le archive where you place all your images, music, sound, fonts, etc. The archive can also be compressed with a fast compression algorithm. All the data in this archive is already decoded and is ready to use by allegro functions once loaded in memory. Testing Utility (\tests\test.exe): This is an interesting testing utility that allows you to evaluate the performance of allegro on your computer. You can perform some test on many 2D and 3D routines available in allegro. Command Line Test Programs (tests\): This directory contains also various small command line utilities that allows you to identify the features of many hardware devices. Setup Utility (\setup\setup.exe) This is the setup utility which can be included with you games to allow your users to congure your game according to their computer hardware. This setup program source can be modied. You can change the image drawn in the background, the sound and musics used for sound test, and you can also change the title of the program. This setup program can also be fusion to your game program le for more convenience. Under DOS, it saves disk space since there is no need to include allegro in both the game and the setup utility. 7

Installation and conguration

1.3 Overview of the Library

Listing 1 Quick Start Hello World Program /***************************************************************************/ /* Quick start Hello world */ /* By Eric Pietrocupo */ /***************************************************************************/ #include <allegro.h> int main () { allegro_init(); install_keyboard(); set_color_depth ( 16 ); set_gfx_mode (GFX_AUTODETECT, 640, 480, 0, 0 ); clear_to_color ( screen, makecol( 0, 0, 0 ) ); textout_centre ( screen, font, "Hello World", 320, 230, makecol (250, 250, 250 ) ); while ( ( readkey() >> 8 ) != KEY_ENTER ); allegro_exit(); return (0); } END_OF_MAIN();


User Input

In this chapter, we will learn how the various input device can be accessed with the allegro functions. The devices covered are the Keyboard, Mouse and Joystick.


The Keyboard

hooked on the keyboard interrupt to interpret the make and break codes sent by the keyboard. The driver creates a buer to hold the keys pressed, remember the states of the shift keys, and who convert the scan codes in ASCII characters according to the state keys. For example, if the a key is pressed and the caps lock is on, it will send a capital A to the software. First, in order to use the keyboard routines, you must call install keyboard with no parameters. Then you can use the allegro functions and variables to read the keyboard. By default, the keyboard is managed through interrupts, put you can also read with the polling method.

The keyboard allows us to read any key pressed by or text written by the user. When a key is pressed, the keyboard send a make code which tell the computer that the key has been pressed. When the same key is released, it send a break code which indicates to the computer that the key has been released. Figure 2.1: keyboard System


Keyboard Reading

The keyboard does not send only ASCII characters to the user, it also send a scan code. A scan code is unique for each key of the keyboard. Which mean a and capital A return the same scan code. Scan codes will allows you to read keys which does not send character: Insert, End, Arrows, Ctrl, etc. For each scan code, a series of constants has been made in order to compare the key pressed with these constants. Here is a few examples: KEY KEY KEY KEY A INSERT ENTER PAD RSHIFT KEY KEY KEY KEY ENTER UP LSHIFT 2 PAD

As you can see on gure 2.1, the keyboard hardware communicates with a driver which communicate with the software. The Interrupt handler on this gure is the place where you can hook a function to handle the keyboard yourself. If you do not hook an handler, The driver will be 9

The easiest way read the keyboard is with the readkey function. This function wait for the user to press a key and it then returns a pair

User Input of scan code and ASCII character. The highest 8 bits contains the scan code, the lowest 8 bits contains the ASCII character. Figure 2.2: Scan Code and Ascii

2.1 The Keyboard Another useful function is keypressed which return true if a key is currently waiting in the keyboard variables. This function is the equivalent of kbhit() libc function. Here is an interesting function which can be used for demo playback. The following function simulate the key passed in parameter to the Allegro keyboard system. void simulate keypress (int key)

In order to get the Scan code, we simply shift the result to the right by 8 bits. You can use a simple shift operator (readkey() >> 8) to do the job. If you want to read the Ascii code, simply make an AND with a mask to eliminate the scan code (ex: (readkey() \& 0xff) ). The problem with readkey is that it stop the program until a key is pressed. This is generally not useful since we want to be able to do something else while the user does nothing (like moving enemies). This is why you have access to the key pressed by using a global array dened as : extern volatile char key [KEY MAX] The array key is ordered by scan codes, so you can use the same scan codes constant to access the table. For example, to test if the enter key has been pressed, you could write the following code : if (key[KEY_ENTER]) printf("Enter is pressed\n"); The shift states of the keyboard can be read through a variable dened as: extern volatile int key shifts ; This is a bit eld where each bit set determine that the key state is on. There is a series of constants mask that you can use to mask the bits you want to read. Here are a few of them: KB KB KB KB KB SHIFT FLAG CTRL FLAG ALT FLAG NUMLOCK FLAG CAPSLOCK FLAG

If you do not wish to read the keyboard through interrupt, you can use the polling method. This mean that you must call a function to update the keyboard variables. The poll keyboard function set the keyboard in poll mode and will also update the keyboard variables. When using the polling method, you must call this function each time you want to update the keyboard keys. Keyboard functions like readkey and keypressed automatically call this procedure, so there is no need to call poll keyboard before calling theses.


Keyboard interrupt handler

For simple games, the material above can do a good job. But for some games, we need a last key system. The last key system can only be done by hooking our own interrupt handler. But rst let start to explain why we need the last key. Let say you are playing an RPG like dragon warrior and you are walking on the world map. If you hold the left key in order to move left, you keyboard will read your keys much faster than the game since your character walk slower than your keyboard input. Which mean that your keyboard will accumulate left keys in the buer. When you release the key, instead of stopping, your sprite will continue to move left until you buer is empty. And if your keyboard does not read the keys fast enough, you will even hear a beep when the buer is full. This is something we do not want to happen. So I have made what I call a last key system. Each time a key is pressed, this key is backed up in a separate variable and replaced by subsequent 10

Video Game Programming with allegro key press. When we read the keyboard, we read the last key instead of the buer and we clear the buer to make sure it does not overow, since we will never read the buer. Figure 2.3 will illustrate this. Figure 2.3: Last Key System to pass the key to the rest of the Allegro keyboard system. Yes, it mean that you can change the key pressed. For examples, you can make an interrupt routines than changes all a keys to y. There are a few important things to note. The END OF FUNCTION is like and END OF MAIN. It is a macro which makes some conguration to make sure it can be used correctly as an interrupt handler. Input last key must be declared as volatile variable like this : volatile int Input last key; The volatile indicates that the variable can be changed anytime during the process of the game. The compiler will make sure the variable never gets corrupted or transfered into a register variable. Then you must lock your variables and functions. Locking allows to prevent the memory manager from caching to disk theses variables and functions since they always need to be available in memory. You can lock them with the following commands: LOCK VARIABLE ( Input last key ); LOCK FUNCTION ( Input inspect key ); If is possible that you receive a compiler error with LOCK FUNCTION. You can cast its parameter as a (void*) to solve the problem. Then we need to tell allegro that this is the keyboard handler that we want to use. Allegro has a function pointer variable named keyboard callback. We only need to give it the address of our function like this: keyboard callback = Input inspect key; When this is done, the routine will be called for each key pressed.

You do not use this technique when reading the keyboard for text input because you will lose some letters. Each time you read the last key, you should clear the keyboard with the clear keybuf function. If you do not read the keyboard fast enough to avoid a buer overow, you can always call this function inside the interrupt handler but I am not sure if this function take a lot of time to execute. The last key can only be made by an interrupt handler which will back up the key before the driver receives it. This handler must be small and must not do time consuming operations because each time a key is pressed the processor is interrupted and it execute this routine. Here is the last key keyboard handler: int Input_inspect_key ( int key ) { Input_last_key = key; return ( key ); } END_OF_FUNCTION ( Input_inspect_key ); The keyboard interrupt handler must be dened as an "int function (int)". The key variable is the key pressed on the keyboard which is backed up in the global variable Input_last_ley. The "return (key)" allows 11


The Mouse

Like the keyboard, there is a driver who interpret the data sent by the mouse. Even if we can hook an interrupt on the mouse, it is not so useful because the Allegro mouse functions does correctly the job. The mouse send its coordinates

User Input as Mickeys. This is a measurement unit independent from the resolution of the screen. You do not need to worry since Allegro will convert them for you. First you need to call install mouse to install the mouse driver. When you are done, you call the function : void show mouse (BITMAP *bmp); This function determines on which bitmap the mouse must be shown. Most of the time, you will show it on screen, but you can draw it somewhere else. When you blit an image on the screen while the mouse pointer is show, it will produce some kind of glitch. To solve this problem, you must hide the mouse pointer before drawing the screen. Calling scare mouse will temporarily hide the mouse pointer. When the blitting is nished, you call unscare mouse to show the pointer. This will become more obvious when you will have learned double buering and page ipping.

2.2 The Mouse Figure 2.4: mouse b bit eld

The mouse pos is a variable containing both X and Y positions. This is useful for reading both value at the same time in case the mouse change position during the delay between X and Y variable reading. The X position is contained in the highest 16 bit while the lower bit hold the Y value. Figure 2.5: mouse pos variable


Reading the mouse If you wish, you can force yourself the movement of the mouse with the following function : void position mouse (int x, int y); The mouse can also be read with the polling method. The poll mouse procedure set the mouse driver in poll mode and will it will the status of the mouse. You must call the procedure each time if you want to update the mouse variables shown above. Another interesting feature is done by function get mouse mickeys. Some time in video games, like space shooter or an arkanoid, you want the mouse to control the movement of a sprite. In this case, you do not want to know the coordinates of the mouse, you only want to know if the mouse has moved left or right. get mouse mickeys will return how far the mouse has moved since its last call. The mouse will continue to generate movement even if the mouse pointer reach the end of the screen. Of course, it is a good idea to hide the pointer since you dont use it. Here is the denition of this function: 12

The mouse is managed by interrupts, which mean that the position is updated while the program is running. The current status of the mouse is stored in the following variables : extern extern exterm extern extern volatile volatile volatile volatile volatile int int int int int mouse mouse mouse mouse mouse x ; y ; z ; b ; pos ;

mouse x and mouse y contains the X,Y position of the mouse. These values range from 0 to the bottom right corner of the screen. Which mean that the values range depend on your screen resolution. The mouse z variable contains the state of the wheel position of the mouse. The mouse b variable is a bit eld where each bit represent the status of a button. You can read them with masks like in this example:

if (mouse_b & 1) printf("Left button is pressed\n");

Video Game Programming with allegro void get mouse mickeys (int *mickeyx, int *mickeyy); 2.2.2 Conguring the mouse parallel port. Allegro now support console joystick wired for the parallel port. Note that USB joysticks are not joysticks, they redirect their input on the keyboard through a driver software. If you use a usb joystick which is redirected to the keyboard, simply read the keyboard. The Allegro joystick driver support up to 4 joysticks ( you can plug many controllers on the same parallel port ). This is why most of all the joystick variable are arrays of 4 elements. To install the joystick, you must call install joystick with the joystick type in parameter. To catch all joystick type you normally use is JOY TYPE AUTODETECT which will attempt to auto-detect the joystick installed on your computer. Which mean you will normally call it like this: install joystick (JOY TYPE AUTODETECT); To know how many joystick have been detected you can read the following variable to get the results: extern int num joysticks ;

It is possible to inuence the behavior of the mouse. First, you can change the movement speed of the mouse with function : void set mouse speed (xspeed, yspeed); The parameter of this function are virtual values which slowdown the movement of the speed when the value is higher. The speed can be congured independently for each axis. Another interesting function is: void set mouse range (x1, y1, x2, y2); Which denes an area of the bitmap where the mouse is allowed to move. This is useful if you want to mouse to stay locked in an area of the screen. Finally, you can change the mouse pointer image according to the need of you game. You must rst change the bitmap by calling set mouse sprite with the mouse pointer image in parameter. void set mouse sprite (BITMAP *sprite); The you must set the focus point of the mouse according to the bitmap. By default, the value is 0,0 since the mouse point to the top left corner of the bitmap. But for example, you could make a cross hair pointer, in this case the focus point will need to be in the center of your bitmap. The focus point can be set with: void set mouse sprite focus ( x, y);


Calibrating the joystick


The Joystick

The reason why calibration is necessary is due to the fact that all joysticks have a dierent ranges of values. This is why, the software must know what are the limits values of you joystick and calculate the movement in proportions to theses values. The best way to calibrate a joystick is by using the Circle around, center and press button technique. With this technique, you push the joystick to the maximum limit it can reach. Then Allegro convert this value in a standard proportional range. To calibrate a joystick you can call the following function with the id number of the joystick in parameter ( 0 if you have only 1 joystick ): int calibrate joystick (int n); This function does not show anything on the screen. So you show on the screen circle joystick around and press a button and then you call calibrate joystick.

The joystick does not use interrupts, so we need to use the polling method. The Joystick is not dependent from any driver (like the sound card for example), this is why the software must read the joystick itself. Joystick can be either plugged into the midi port of the sound card or in the 13

User Input If you do not want the user to calibrate the joystick each time he plays the game, you can call the following function to save and load all the joystick calibration data on the disk. int save joystick data (const char *filename); int load joystick data (const char *filename); You pass the lename of the conguration le you want to save or load but you can also pass a NULL value which will save or load the joystick conguration from the Allegro conguration le.

2.3 The Joystick int num_buttons; JOYSTICK_STICK_INFO stick[n]; JOYSTICK_BUTTON_INFO button[n]; } JOYSTICK_INFO; This is the structure array joy where N is the ID number of the joystick. If you only read 1 joystick, it should always be 0. The joy array is made of the structure JOYSTICK INFO which contains come information about the joystick. You must read button to get the button status and stick to access the joystick position. You can also check how many buttons and sticks there are with num sticks and num buttons. Let start with button.This variable is an array of structures called JOYSTICK BUTTON INFO which is dened as follow:


Reading the Joystick

The reading part is a bit more complicated. First you need to call poll joystick each time you want to read the joystick input else the joystick variables wont change. The joystick variables are stored as a tree of structures. Sometimes you must dig in very deep to get the variable you want. Look at gure 2.6 to see the structure. Figure 2.6: Joystick variable structure

typedef struct JOYSTICK_BUTTON_INFO { int b; char *name; } JOYSTICK_BUTTON_INFO; The eld which interest us is the b eld which is a boolean indicating if the button is pressed. Each element of the button array represent a button of the joystick. Which mean that if we want to read the 1st button of the 1st joystick, we will use the following code:

if ( joy [ 0 ] . button [ 0 ] . b == true ) printf {"The first button is pressed"} Here is the code to read the 3rd button : The top level structure is dened as follow: extern JOYSTICK_INFO joy[n]; typedef struct JOYSTICK_INFO { int flags; int num_sticks; if ( joy [ 0 ] . button [ 2 ] . b == true ) printf {"The first button is pressed"} For reading the joystick position, we must go deeper into the stick array which is dened as follow: 14

Video Game Programming with allegro typedef struct JOYSTICK_STICK_INFO { int flags; int num_axis; JOYSTICK_AXIS_INFO axis[n]; char *name; } JOYSTICK_STICK_INFO; The stick array has an element for each stick of the keyboard. For example, an analog play station controller will have 3 sticks: the Dpad, the left analog and the right analog. If you only have 1 stick, you will always use sick 0. In the stick structure we have the axis array where each element represent an axis. A normal dpad have 2 axis : the X and Y axis but a throttle stick will only have 1 axis. Axis 0 is used for X and axis 1 is used for Y. The axis structure is dened as follow: typedef struct JOYSTICK_AXIS_INFO { int pos; int d1, d2; char *name; } JOYSTICK_AXIS_INFO; The pos variable is the analog value represented by a value ranging from -128 to 128 or from 0 to 255 according to the type of stick (ex: throttle stick ). The d1 and d2 variables are used to know the digital direction of the joystick. These are boolean which are set when the joystick is pressed in this direction. Since an axis has 2 directions, there is 1 variable for each direction. Which mean that if we want to read the analog value of the X position, on the 1st stick of the 1st joystick, we use the following code: x_pos = joy[0] .stick[0] .axis[0] .pos; The y position would have been read like this : y_pos = joy[0] .stick[0] .axis[1] .pos; While If you want to test the digital directions pressed on the joystick, you will use the following code: 15 if ( joy[0] .stick[0] .axis[0] .d1 printf ("User pressed left"); if ( joy[0] .stick[0] .axis[0] .d2 printf ("User pressed right"); if ( joy[0] .stick[0] .axis[1] .d1 printf ("User pressed up"); if ( joy[0] .stick[0] .axis[1] .d2 printf ("User pressed down"); > 0 ) > 0 ) > 0 ) > 0 )

As you can see, the joysticks structures are very complex but it is essential to support all the special features and goodies available on the market. This is all there is to learn. There is a few details I have not talked about yet that I will keep for later. You can take a look at the allegro examples for managing the joystick and other devices if you wish. In the next chapter, we will talk about the most important device, the video screen.

User Input

2.3 The Joystick



Video Output

In this chapter, you will learn how to manage the video screen. We wont draw anything yet, except for testing purposes. There is still a lot of thing to talk about even if we dont really draw anything on the screen.


Video Hardware

Vesa is a standard BIOS in the card which allows to congure various video resolution an color depth without tweaking the register yourself. There are various version of Vesa, but most recent video cards should support Vesa 3. For version 1.x, you might need sci-tech s display doctor or use another driver system to congure the registers correctly (see below). 3.1.1 Initiating the Video Mode

The video card contains some memory in order hold the information drawn on the screen. The screen monitor ask the video card to send the content of its memory regularly in order to update its screen. The screen refresh is called Vertical Synchronization. A monitor with a speed of 70 Hz will refresh the screen 70 times per second. The video memory is interpreted dierently according to the video modes you are in. For example, the text mode will represent the screen with characters while the graphic mode will represent it with pixels. The video card possess a series of registers. These registers allows to congure how the video card will work. In the ROM of the video card, there are some Video Modes which is a predened conguration of the video card register to get a specic video output. For example, the famous 13h VGA video mode ( 320x200x256 colors ) can be congured automatically by calling a function from the BIOS. It prevents you from knowing how to congure the registers. There are other video modes like the mode X ( 320x240x256 colors ) which has been achieved by actually tweaking the video card s registers. When many SVGA cards arrived on the market, the Vesa standard has been adopted. 17

In allegro, initiating the video mode is just a matter of resolutions and colors. The video buer is just a big 2 dimensional table. Each element in the table represent a pixel. The X coordinates goes from left to right while the Y coordinates start from the top to the bottom. Figure 3.1: Video Buer

Which mean that when you want to write on the screen, you simply need to change a value

Video Output in this table. The content of each element in the table depends on the color depth you have selected. There are dierent kinds of video information. The allegro function which set the video mode is: int set gfx mode (card, w, h, v w, v h); The w and the h parameters is actually the width and the height resolution of the screen you want. What you ask, is not necessarily what you get. If you ask for non-standard video resolution or if your user does not support this resolution, due to his video hardware or to the lack memory, you will either receive another resolution or a failure to execute this function. This function return a negative number on failure else it return 0. There are 2 macros which allows you to check the current resolution of the screen: SCREEN W SCREEN H The card parameter is the name of a driver system to use. The driver is not a specic driver to a video card like in Windows. Some examples of driver system are: Vesa, Vesa 3, Mode X, VBEAF, etc. It does not matter if you actually have an ATI, S3 or any other model of video card. Normally, you will call GFX AUTODETECT which will take the best video driver available according to Allegro. There is also the GFX AUTODETECT FULLSCREEN and GFX AUTODETECT WINDOWED constants used for windowed OS. The v h and v w parameters are use for virtual screens. It allows you to allocate a video buer larger than the screen and use hardware scrolling procedures to scroll the screen. Of course, you cannot allocate more than the video memory available on the card. One allocated, you can scroll the screen with hardware routines with function : int scroll screen (int x, int y); Still, not all video cards support hardware scrolling. When PC technology evolved, they have decided to implement some hardware routines into the card in order to speed up the process like they do it in some video game consoles

3.2 True Color Video Mode like the SNES. This allowed do to some common video operation much more faster. When the 3D revolution arrived, the video cards also added 3D routines into their card to relieve the processor from excessive math calculation. When the video mode is set, there is a bit eld containing a small list of hardware routines available in the system. This bit eld is denes as: extern int gfx capabilities ; The are some mask constant to test the bits of this variable, here is a few examples: GFX GFX GFX GFX GFX CAN SCROLL HW HLINE HW FILL HW VRAM BLIT HW MEM BLIT

If you run in DOS, you might have to use the FreeBE/AF driver to take advantage of theses. Take note that if you do not support GFX HW MEM BLIT, you will have to copy the images you want to draw into video memory, in order to benet from the hardware acceleration GFX HW VRAM BLIT. I have made a small test program which show all features of the card, this program should be available on my web site with its source code.


True Color Video Mode

As I have said before, beside the text mode, there is 2 way to manage the video buer: True Color and palette video modes. In the true color video mode, you simply write the right color value into the video buer table. This color value is made of 3 other values which each represent the primary light colors: Red, Green, and Blue. The number range of each value varies according to the color depth of the video mode you want. Take a look at gure 3.2: As you can see on gure 3.3, there is an RGB value for each element in the table. The number of bit of each RGB value varies according to the color depth. Of example, in the 15 Bit video mode, 5 bit is reserved for each value. A 5 bit value can range from 0 to 31, if we combine 18

Video Game Programming with allegro Figure 3.2: RGB values the correct color value according to the current active color depth. You should always use this function when you want a color for any drawing operation in true color video mode. 3.2.1 Calculating Resource Usage

You might thought that more color and pixels is better, so why bother with low color depth or even low resolution. Let just use 32 bit colors with a 1280x1024 pixel video mode and show superb graphics. As you will see, doing so might not be possible on all computer. There is 2 major limitation: Memory, speed and hardware. Figure 3.3: True Color video buer First, lets calculate the video memory required to allocate the video buer above: 32 bit is stored in 4 bytes. We need 4 bytes for each element of the video buer which makes 4x1280x1024 for 5242800 bytes. 5 megs! not that bad, my video card have 64 Megs. Still, you will see later in this book that we need a temporary buer to draw our frames. Which mean that you need to allocate another 5 meg of video memory. Then you must consider that all the images in the game must also be bigger in order to ll the screen. So a full screen image will also take 5 Megs of memory and disk space. If you make an intro movie for your game at this resolution, I am curious to see the size of your le. The second reason is the speed. A normal video game should run at 60 frames per seconds. What this mean is that you must draw all the sprites, images and special eect on the screen and repeat the whole process 60 times in a second. With the resolution dened above, this mean that we must at least draw 5242800 pixels for each frame but since there is generally layers overlapping for the background, level and sprite, we will write at least 3 times more pixel than the screen resolution for a total 15728400 pixel in 1/60th of second, multiply it by 60 for 1 second. Which mean that we must draw 943704000 pixel in 1 second. With that much pixels to draw, you will need a lot of processing power. We can vaguely calculate the processing speed required by dividing this number by 1 Million to get the number of MHz required. In this

the 3 values together we can make up to 32768 colors (32x32x32). On the 24 bit video mode, we have 3 values of 8 bit which each can range from 0 to 256 giving up to 16777216 dierent colors. The alpha in the 32 bit video mode represent the translucency of the pixel in case you would want to make some part of the image translucent. We can still perform complete translucency in any color depth. In allegro, the color depth is determined by set color depth which must be called before set gfx mode. You pass in parameter the color depth you wish: 15, 16, 24, 32. void set color depth (int depth); Since the color depth have all dierent ranges of values, there is a standard function named makecol which take 3 the RGB values as parameter. The values range from 0 to 255 whatever is the current color depth and it will return 19

Video Output case, it would be 943 MHz but it is not a precise value since we exclude command operation, other process to do in the game, the temporary buer creation, and the fact that some processes like translucency takes much more time. We also do not consider Video card acceleration and MMX support for example. Still, this should be the speed required in order to simply transfer the data without optimization. Yes, some computer can make it today but it is not every body that has the latest super computer on the market. It is even possible that the users hardware cannot support the 32 bit resolution. This is why you should select a more convenient resolution. Lets take the example above and reduce the parameters by 1 rank: 24 bit color and 1024x768 pixel. In this mode, We would require 2359296 bytes of video memory and we would have needed to write 424673280 pixels in a second. Which make a reduction of 55% for memory usage and processing power required. The best of it, is that the user will barely see a dierence in the graphic output. Take note that when you are doing 3D graphics, the resolution dierence is even more dicult to perceive. I have played Unreal Tournament in 400x300 and it was still playable. Here is a small table which indicates the video memory required for each resolution versus color depth. Table 3.1: Video Buer Memory Size
640x480 800x600 1024x768 1280x1024 15,16 614 K 960 K 1.57 M 2.62 M 24 921 K 1.44 M 2.35 M 3.93 M 32 Bit 1.22 M 1.92 M 3.14 M 5.25 M

3.3 Palette Video Mode RGB value in the video buer, we copy the index of the palette where the color is stored. Check gure 3.4. Figure 3.4: Video Buer in Palette mode

The rst advantage of this mode is that it takes even less resources since there is only 1 byte per pixel. It can be an advantageous mode for low processing machines like a Game park 32 or a Pocket PC. The second advantage is that you can make palette animation eects or color variation ( Use the same sprite but change the colors ). The disadvantage is that you must make come palette management before drawing of the screen, you are also limited to use 256 colors at once and you must take some precautions when making your images (See later). Take note that there is only one palette mode available which is referred as 8 bit. So you cannot have another palette mode with a larger palette for example but the palette video mode is supported by many video resolutions. 3.3.1 Managing the Color Palette


Palette Video Mode

The color palette is a table of 256 elements. This table of elements is dened as a PALETTE type. Each element of this table is an RGB structure which is dened below: typedef struct RGB { unsigned char r, g, b; } RGB; This structure contains the RGB value of the color. These values range from 0 to 63, in 20

The second type of video mode is the palette video mode. It is referred as the 8 bit video mode even if it is not necessarily an 8 bit color depth. In a palette video buer, we indicate an index number which refer to an element of the color palette. The color palette is a table of 256 color dened with RGB values. Instead of copying the

Video Game Programming with allegro fact, they are 6 bit value. The palette video mode, could be considered as an 18 bit color depth since it can reach up to 626144 colors, but even if we have more colors than the 15 bit video, we can still only use 256 of them at the same time. Figure 3.5: Color Palette Entry will conform themselves to this palette. Allegro supplies a function to generate a 8 bit set of colors in the palette. Figure 3.6: 8 Bit color depth Emulation

You can change a color palette by modifying each value independently. To do so you use set color. You can also write the whole palette at once with the set palette procedure. Here is the denition of these two functions: void set color (int index, const RGB *p); void set palette (const PALETTE p); Reading the color from the palette is done the same way with the 2 following functions which are somewhat self explainable. void get color (int index, RGB *p); void get palette (PALETTE p); Just take note that the palette changes must be done while the screen is not being refreshed. Changing colors during the screen refresh can cause some ickering on the screen. set palette will automatically wait for screen refresh to end, it is done with the vsync function which we will see later. We will also see in a later chapter how to make color sets in order to make sure that the palette of various images does not overlap each other. A popular technique consist to divide the palette in 16 color sets of 16 colors and make each images use one color set with its own unique 16 colors. These colors must be uploaded into the palette before being used. 3.3.2 8 Bit Video Mode Emulation

The idea is to generate all the possible colors which can be drawn in an 8 bit color depth and place them in the palette. You can call generate 332 palette to generate a 8 bit palette made of 3 bits red, green and 2 bits blue. void generate 332 palette (PALETTE pal); You make a program that generate this palette and make a screen shot of the screen with save bmp or alegsave pcx. Then you load this le in your image editor. Save the palette of this le according to your software s format and each time you make a new image, load this palette. If you proceed this way, all you images will have the 3-3-2 palette and you will never bother changing or loading palette anymore, you just call generate 332 palette. By the way there is also a demo, in the allegro examples, that shows how to make a 12 bit video mode by tweaking the video card. You might want to take a look if you need more color. So this is it, there is still a lot of things to learn about the video screen that we will see in the following part. I have decided to make 2 small test program which each start the video mode and draw a rectangle around the screen. On is done in true color and the other one in palette mode. I also use the function rect, which allows to draw a rectangle on the screen. You will learn it with the drawing primitives.

Another way to solve the problem illustrated in the paragraph above can be done my making the palette video mode emulate a 8 bit video mode. By doing so, we will dene a unique palette that will never change during the game. All the images 21

Video Output

3.3 Palette Video Mode

Listing 2 True Color Video Mode Usage /**************************************************************************/ /* True Color Video Mode Initialisation and Usage */ /* By Eric Pietrocupo */ /**************************************************************************/ #include <allegro.h> int main ( void ) { allegro_init(); install_keyboard(); set_color_depth (16); set_gfx_mode(GFX_AUTODETECT, 640, 480, 0, 0); rect( screen, 0, 0, 639, 479, makecol(255, 255, 255)); while ( (readkey() >> 8) != KEY_ENTER ); allegro_exit(); return (0); } END_OF_MAIN();

Listing 3 Palette Video Mode Usage /**************************************************************************/ /* Palette Video Mode Initialisation and Usage */ /* By Eric Pietrocupo */ /**************************************************************************/ #include <allegro.h> int main ( void ) { allegro_init(); install_keyboard(); RGB tmpcolor = { 63, 63, 63 }; // White Color set_color_depth (8); set_gfx_mode(GFX_AUTODETECT, 320, 240, 0, 0); set_color ( 1, &tmpcolor ); rect( screen, 0, 0, 319, 239, 1); while ( (readkey() >> 8) != KEY_ENTER ); allegro_exit(); return (0); } END_OF_MAIN();



Audio Output

Playing sound in allegro is easy, in fact there is just a few functions to learn. This is why I will also cover in this chapter how the sound hardware works and explain the dierence between Sound Sampling and instrumental music.


Basics of Sound

A sound wave must actually go up and down to produce a at line wont produce anything. But the wave form of the sound can be of dierent shape to produce various output. The pitch of the sound is determined by the frequency of the wave. The frequency determine how many times in a second does the wave actually goes up and down. Figure 4.2 show the dierence between a lower and higher frequency wave. Figure 4.2: Frequency Variations

Sound is made by waves which are sent in the air. The speaker is made of an electric magnet which must receive power variation to send these waves. The form of the power variation will inuence the type of sound generated. A basic beep sound can be perform by a sinus wave type like on gure 4.1. Figure 4.1: A sound Wave

The pointed line indicate 0 volt, when the wave drop below the pointed line, it has a negative voltage. The height of the wave is called amplitude, it somewhat determines the volume of the sound. When listening to AM radio, if there is some interferences, the amplitude might raise and produce some glitch. The y axis is the wave length which is actually the time where the sound is played. The longer the wave, the longer it last. 23

An higher frequency will produce high pitched sounds, while lower frequency produce low ones. The frequency can be measured in Hz. An 1000 Hz sinus waves means that the wave goes up and down 1000 times per seconds. The Sound card is an independent device that will manage the sounds processing itself to relieve the processor. Since we want to play sound an music while doing something else in our game, we gives orders for sound and music playing to the sound card, and it will make sure that the audio

Audio Output automatically get updated while the processor is doing something else. For process not managed automatically by the sound cards, Allegro install a series of interrupt handler to update constantly the sound card information. So the game will never wait for the sound to end before continuing its process.

4.3 Instrumental Music Figure 4.4: Various Sampling Frequency


Sound Sampling

For sinus waves, we can easily make a math formula that will always produce the same sound wave anytime we want. But math cannot produce all the possible waves forms we will need. This is why sampling becomes necessary. A sound wave is an analog output, we need to convert it into a numeric format in order to save it and use it by your computer. Sampling a sound wave consist to take samples of the wave at a certain rate which will allow us to reproduce the original wave after. If we take more sample in a second, reproduction of the wave is more likely to look like its original.Figure 4.3 show a low sampled sinus wave. Figure 4.3: Sampled Sound Wave

An higher sampling rate will produce higher quality sound. Take note that some hardware does not support all bit rate and frequencies. Also consider that sampling sound take a lot of space and memory. A 44100 Hz 16 bit sample which last 1 second need 88200 Bytes. Not so bad for a sound, but you generally have more than one sound in a game. Dropping the sampling 22050 Hz can produce reasonable sound quality. If you are making stereo samples, you must record a sample for each panning side. Which mean that the size of the samples is doubled. So a 1 second 44100 Hz 16 bit stereo sample will require 176400 bytes of memory and disk space. If you use sound sampling to produce music stream, 2 minutes of music sampled at 44100 Hz in 16 bit stereo will use 20 meg of memory or disk space. This is why the MP3 compression has been made. Still, generally audio streaming system load blocks of music to play them in order to save memory usage. I wont talk about audio streaming but there is a another way to produce good music with few resources.

The amplitude of the wave is recorded as a negative or positive value which is proportional to the voltage of the wave. The value range is determined by the bit rate of the sample. An 8 bit sample value will range from -127 to 127 while a 16 bit sample will range from -32768 to 32768. A higher bit rated samples will produce higher quality sound since the resolution data is higher. The sampling frequency determines how many times in a second does the wave has been samples. A music CD use a sampling rate near to 44100 Hz. Look on gure 4.4 to see the dierence between lower and higher sampling frequency.


Instrumental Music

A music is a series of instruments with generally somebody who sing on the top of the music. An MP3 music simply take the wave output of all the instruments and the singer together, sample it and then compress it. But we can do almost the same thing in a dierent way. 24

Video Game Programming with allegro Let say, we do not have a singer, we only have instruments. Each instrument will always produce the same wave form, the only thing that changes is the frequency of the wave produced for various notes. So instead or recording the wave output of all instruments, we record which notes are played by each instrument and when are they played. Figure 4.5: Music Partition a 15 pin connector on your sound card that you can use to plug a music keyboard or a joystick. There is also the sound card hardware to manage the MIDI les and input. And nally, the General MIDI, which is a table of instrument denition that we will see below. When a track want to play an instrument, it need the wave form of that instrument. There are 2 methods which can be used by sound cards. First, the general MIDI contains a huge table of at most 256 instruments. There are up to 128 Melody instruments and 128 percussion instruments. The General MIDI contains all the wave forms for all instruments, so when the card need to play a note, it use the wave form in the table played at the right frequency. The second method is done with a synthesizer. A synthesizer is a series of operators and cells which are organized to produce the wave form of an instrument. By passing the correct parameters to these components, we can reproduce the instruments in the General MIDI table. The Yamaha OPL2 synthesizer, which only have 2 cells per operators (Instrument), oer 2 ways to place there cells: Modulation and Addition (See gure 4.6). Figure 4.6: synthesizer Cell Operations

We rst divide the music in tracks, each track represent an instrument. The track contains all the notes that must be played at a specic time. All track are played simultaneously. When a note must be played, it use the instrument wave form and play it at a specic frequency. There is a table, in the sound card, which indicates what is the frequency required to play a specic music notes. This way of recording music is know as a format called MIDI. Some of you might thought that MIDI sucks. It might sucks on your computer, but this is not the problem of the MIDI format. It is your sound hardware that determines the quality of the sound output since the MIDI le only know which notes must be played. It does not possess any information about the instrument wave form. Video Games Consoles like Play station One and Game Cube still use MIDI for their music, but the hardware produce dierent quality of instruments. The major advantage of MIDI music is the size. A 2 minute music can take only 30 K of memory and disk space. If you search in the Internet for MIDI, which stand for Musical Instrument Digital Interface, you might nd several kind of information. MIDI rst refer to the MIDI les where the notes are recorded. It also refer to the MIDI port which is 25

Each cell produce a dierent wave and both wave form can be fused in 2 dierent ways. This allows to produce various wave output for the instrument. There is also more sophisticated hardware like the OPL3 which have more cells per operator allowing to produce higher quality instruments but most driver and software, including allegro, does not support more than 2 cells per operators. The advantage of a synthesizer, is that you can redene the instrument conguration. In allegro, this can be done by loading an .IBK le from the Allegro Setup Program. The IBK les

Audio Output is a format made by James Connell1 for his MIDI driver utility. He oers various .IBK les to changes the instruments according to your taste. It will only works if your sound card is actually using a synthesizer to play music. Finally, since the instrument are waves like sound, it is possible to emulate MIDI on the Digital Sound device. For example, Super Jukebox 2 possess its own waves table for each instrument and play them on the digital output which also allows you save it directly in a .WAV le. 4.4.1 Playing Samples

4.4 Allegro Audio

Playing sample is fairly easy. There is a SAMPLE data type dened by allegro to hold sound samples. You can load a .WAV or a .VOC le with the two functions below, but this will be a bit useless when we will see the Allegro Datales. SAMPLE* load wav (const char *filename); SAMPLE* load voc (const char *filename); You should call this procedure to deallocate the sound sample from the memory when you dont need it anymore. You can call this function even if the sample is currently playing. void destroy sample (SAMPLE *spl); When you want to play a sample, you must use the play sample function: int play sample (const SAMPLE *spl, int vol, int pan, int freq, int loop); The spl parameter is pointer on the SAMPLE structure of a loaded sound. The vol and pal variables, range from 0 to 255 and inuence the volume and the panning position ( left 0, right 255 ). The freq allows you to change the original frequency of the sample. A value of 1000 will leave it intact while 2000 will speed it up twice faster and 500 slow it down by half. If you set 1 as the loop parameter, the sound sample will continue to repeat it self until you call: void stop sample (const SAMPLE *spl); If you want to change the parameters of a sound while he is looping, you can use the following function which works the same was as play sample : void adjust sample (const SAMPLE *spl, int vol, int pan, int freq, int loop); You can also play more that one sample simultaneously. Allegro add up the waves of the samples in order to play them together. There is still a limit to the number of sound you can play at once, it depends on your sound card. But if you do not intend to exceed 8 sounds, it should never be a problem for most sound cards. 26


Allegro Audio

In order to play samples and music we must call some initialization functions. Before calling any MIDI related functions, you must install the timer system by calling install timer. The timer is used internally by Allegro, so we wont need to use any of these routines yet. Then you need to call these procedures: int detect digi driver (int driver id); int detect midi driver (int driver id); This will allow you to detect if a digital sound or MIDI device is currently available. You can pass in parameter DIGI AUTODETECT to detect digi driver and MIDI AUTODETECT for detect midi driver. Finally you must call install sound to install the sound system. int install sound (int digi, int midi, const char *cfg path); You also pass DIGI AUTODETECT and MIDI AUTODETECT for digi and midi parameters. cfg path is only there for backward compatibility, ignore it, pass NULL. There is also an interesting function which adjust the volume of the sound and music. The parameters are values ranging from 0 to 255. void set volume (int digi volume, int midi volume);
http://www.midiox.com/?http://www.midiox. com/jsoft.htm 2 http://superjukebox.zophar.net

Video Game Programming with allegro 4.4.2 Playing Music instrument denition is stored in the le allowing your instruments to play the same way on any computer. The .MOD les, and his friends, do not use the midi system for output, it use the digital output. I have checked my Unreal Tournament game and the .it les (renamed as .UMX ) takes from 800 K to 3 Meg. That look as huge as MP3 but consider that there is no compression, the whole song will never take more than 3 Meg of disk and memory while an MP3 music will require much more memory once decompressed. Most video games consoles, like PS2 and Game Cube, and PC games use .MOD les for instrument music. 4.5.2 Audio Stream

Playing MIDI les is also easy. You will learn the most useful procedures here. Allegro denes a MIDI data structure to hold MIDI information. You can use load midi and destroy midi to load midi le or deallocate a MIDI object. But as you will see later, load midi be become obsolete when we will have learned Datales. MIDI* load midi (const char *filename); void destroy midi (MIDI *midi); When a music is loaded, you can play it with play midi procedure: int play midi (MIDI *midi, int loop); You can set the loop parameter to 1 and the music will loop indenitely. To stop a music currently playing, you must call stop midi with no parameters. Playing a new music will stop the previous music and start the new one. So you cannot play two MIDI music simultaneously. You can pause the music with midi pause and resume it with midi resume (useful for pausing the game).

Allegro support some sort of audio stream system but you can also download the AllegroMP3 library which will allow you to load MP3 les in your game. The basics of audio streaming is that the le take to much space uncompressed. From what I know, MP3 can compress a le up to 12:1. which mean that a 3 Meg MP3 le can take 36 Meg of memory. You can test this by exporting your MP3 to WAV and compare the le sizes. Since you generally cannot load all uncompressed music in memory, you must do some kind of music manager. Audio streaming consist in loading chunks of music into memory. When the chunk is played, you delete it and load the next following chunk. You continue the process while the song is being played. Besides MP3, there is the compressed WAV format which is used today by more than 80% of PC video games. The compressed WAV format does not alter the song to improve the compression, the music stay intact. MP3 compression removes high inaudible frequency and it can make other changes to the sample to get a better compression. This is all there was to say about sound an music. There are a few things I have not


Other Audio Format

There are a few other audio format available that we wont talk about since they are not natively supported by allegro. But you can still download on Allegro Game Development Community Network 3 add on libraries to support these formats. 4.5.1 Another Instrument Music

Instrument music saves space but the output is dierent from a computer to another. To solve this problem, another format of instrument music has been made. They are known as .MOD .IT .S3M les. This type of music works exactly like midi, it contains a series of event that will be played at a specic time. But the improvement is that the



Audio Output talked about like the MIDI and Sound recording routines. Anyways, you should have everything needed to play music in your game. The following code example load a sample and a music which will play indenitely. When you press space, it plays the sample and when you press enter it exit the program.

4.5 Other Audio Format


Video Game Programming with allegro Listing 4 Playing Music and Sound /**************************************************************************/ /* Audio Sample/Music demo Programm */ /* By Eric Pietrocupo */ /**************************************************************************/ #include <allegro.h> #include <stdio.h> int main ( void ) { SAMPLE* smp_test; MIDI* mid_test; int key; allegro_init(); detect_digi_driver(DIGI_AUTODETECT); detect_midi_driver(MIDI_AUTODETECT); install_keyboard(); install_timer(); install_sound(DIGI_AUTODETECT,MIDI_AUTODETECT, NULL); smp_test = load_sample ("bad.wav"); mid_test = load_midi ("w2fight.mid"); printf ("Press ENTER to end or SPACE to play Sample\n"); // note that we // are currently not in graphic mode so using printf is OK play_midi ( mid_test, 1 ); key = KEY_ESC; while ( key != KEY_ENTER ) { key= readkey () >> 8; if ( key == KEY_SPACE ) play_sample(smp_test, 200, 128, 1000, 0 ); } allegro_exit(); return (0); } END_OF_MAIN();


Audio Output

4.5 Other Audio Format


Part II Logical Procedures used in Video Game Programming



Graphic Drawing Functions

In this chapter, you will learn the basic functions which can be used to draw on the screen. To be able to use them, you need to set the video graphic mode. All of these functions requires a bitmap parameter which is the location where the function will perform its drawing operations. For now, you should use screen as the bitmap for output. There is also the color parameter which vary according to the color mode. In a palette video mode, you pass the index of the color while in true color video mode, you must use makecol to get the right color value.

mon to all functions, you must specify the x and y coordinates which indicate where you want the point to be draw or read on the bitmap. Use these functions to write or read pixels. void putpixel (BITMAP *bmp, int x, int y, int color); int getpixel (BITMAP *bmp, int x, int y); getpixel will return -1 if the point lies outside the bitmap. Since these functions can be pretty slow, there is an optimized, in-line assembler routine for each color depth. The declaration start with an underscore and end with the color depth. void putpixel (BITMAP *bmp, int x, int y, int color); void putpixel16 (BITMAP *bmp, int x, int y, int color); void putpixel24 (BITMAP *bmp, int x, int y, int color); ... Beware, you cannot use these function in mode-X and if you draw 1 pixel outside the bitmap, you program will crash horribly because it does not do the clipping. When we are done with point we can start drawing lines. There are various line functions available. Of course there is the standard diagonal line which is declared as: void line (BITMAP *bmp, int x1, int y1, int x2, int y2, int color); If you want to draw vertical or horizontal lines, there is two other functions which are more faster than line:


Drawing Primitives

Besides being the name of a music band in Reboot, drawing primitives are basic functions needed to draw basic line and polygons. They are rarely used in a tile based games, like on the NES and SNES, since these games use bitmaps most of the time but they are still useful for drawing special eects, energy bars, status windows, etc. Most of these functions are self-explanatory. Which mean that we will explain only a few of them and just list the rest of the procedures. All these functions, except the in-line ones, get clipped to the bitmap size. Which mean you can set coordinates located outside the bitmap ( screen ) and it wont produce any bug or computer crash. 5.1.1 Points and Lines

First there is the pixel drawing/reading functions. Besides the bitmap and the color, which is com33

Graphic Drawing Functions void vline (BITMAP *bmp, int x, int y1, int y2, int color); void hline (BITMAP *bmp, int x1, int y, int x2, int color); If you want to draw a curve, you can use arc. It draws a circular arc with center x,y and a circle radius of r. It make an anti clockwise arc that start at angle a1 and end at angle a2. These angles range on values from 0 to 256. Since they are xed decimal variables, use itox to convert you angles in xed variable type. void arc (BITMAP *bmp, int x, y, fixed ang1, ang2, int r, int color);; Figure 5.1: Arc and Circle 5.1.2 Polygons

5.1 Drawing Primitives

Besides drawing points and lines, you can draw polygons. The most basic polygons you can draw is the rectangle which can be drawn using rect and passing in parameter the top left and bottom right coordinates. void rect (BITMAP *bmp, int x1, int y1, int x2, int y2, int color); You can also draw round shaped polygons. circle will require the radius and x,y coordinates while ellipse need a radius for each axis (rx and ry). void circle (BITMAP *bmp, int x, int y, int radius, int color); void ellipse (BITMAP *bmp, int x, int y, int rx, int ry, int color); Figure 5.3: Ellipse

Finally, there is the spline function which is really interesting : It draw some sort of serpent line. You need to pass in parameter 4 x,y coordinates through a table of 8 values. The rst (points[0],points[1]) and the last (points[6],points[7]) coordinates determine the beginning and the end of the curve. While the 2 other points and actually attraction points that will attract the line toward theses points. spline is dened as: void spline (BITMAP *bmp, int points[8], int color); Figure 5.2: Spline

All the functions above draw outlined polygons. There is another version of these functions which can draw lled polygons: void rectll (BITMAP *bmp, int x1, int y1, int x2, int y2, int color); void circlell (BITMAP *bmp, int x, int y, int radius, int color); void ellipsell (BITMAP *bmp, int x, int y, int rx, int ry, int color); There are also other polygon functions which draw lled polygons by default. void triangle (BITMAP *bmp, int x1, y1, x2, y2, x3, y3, int color); void polygon (BITMAP *bmp, int vertices, int *points, int color); triangle is pretty obvious but polygon is much more complicated. First you set the number of vertices in the vertices parameter. Then 34

Video Game Programming with allegro *points must point on an array of x,y coordinates. It works like spline except that the array is not limited to 4 coordinates. If you want to ll any portion of the screen, you can use oodll which works like the paint bucket tool. Still I do not recommend using this function inside some real time processing. void oodll (BITMAP *bmp, int x, int y, int color); A small note about speed. Most functions that have a round shape will take much more time to execute since they need to calculate sine, cosine and its friends. Do not overuse drawing primitives during real-time process, it can slowdown the game. 5.1.3 do drawing Procedures screen. The callback function receive a copy of the bitmap and the d parameter while the x and y variables are the coordinates of the point calculated by the function . The d parameter is an optional parameter that you can use to change the behavior of your callback, its your personal parameter. If we want to produce the example stated above, our callback would store in a table the coordinates of each point on the circle. When its time to move the sprite, you will update the position of the sprite according to the coordinates written in the table. The function calc spline does almost the same thing except that there is no callback. The values are stored into an array of x and y coordinates. void calc spline (int points[8], int npts, int *x, int *y);

There is another series of function which is somewhat related to drawing primitives but does not actually draw anything. For example, if you want to move a sprite in circle pattern, instead of actually drawing a circle, you want to know what are the coordinates of each point on the circle. This process can be done through the do something functions. Here are their complex denitions: void do line (BITMAP *bmp, int x1, y1, x2, y2, int d, void (*proc)(BITMAP*,int,int,int)); void do circle (BITMAP *bmp, int x, int y, int radius, int d, void (*proc)(BITMAP*,int,int,int)); void do ellipse (BITMAP *bmp, int x, int y, int rx, ry, int d, void (*proc)(BITMAP*,int,int,int)); void do arc (BITMAP *bmp, int x, int y, fixed a1, fixed a2, int r, int d, void (*proc)(BITMAP*,int,int,int)); Beside the usual function parameters you must also pass the d parameter and a call back functions address which has been declared as: callback name(BITMAP *bmp, int x, int y, int d); This callback function will be called for each point that should normally be drawn on the 35


Writing text

Allegro provides a series of text output routines to draw text on the screen. Of course you can still use printf and cout but the problem is that they cannot draw in graphic mode. This is why Allegro supplies its own functions. Allegro also comes with a font system. It can load fonts from .fnt or bitmap les. Font loading will be seen in the chapter about Allegro datales. Even if you do not have loaded fonts, there is the system bios font which is always available. Allegro has created the variable font which point on this system font. extern FONT * font ; Most functions has a font parameter, you can use this font for testing. There also have the bitmap parameter which we will set to screen for now and of course the color parameter.

Graphic Drawing Functions 5.2.1 Text Printing

5.2 Writing text void textprintf (BITMAP *bmp, const FONT *f, int x, y, color, const char *fmt, ...); void textprintf centre (BITMAP *bmp, const FONT *f, int x, y, color, const char *fmt, ...); void textprintf right (BITMAP *bmp, const FONT *f, int x, y, color, const char *fmt, ...); void textprintf justify (BITMAP *bmp, const FONT *f, int x1, int x2, int y, int diff, int color, const char *fmt, ...); 5.2.2 Other Procedures

The most basic text drawing function is textout. void textout (BITMAP *bmp, const FONT *f, const char *s, int x, y, int color); This function draw character string s at the x,y position corresponding to the top left corner of the whole string. There are a few variations of this function which allows you to draw centered text or right aligned text. void textout centre (BITMAP *bmp, const FONT *f, const char *s, int x, y, color); void textout right (BITMAP *bmp, const FONT *f, const char *s, int x, y, color); Note that the x coordinates for textout centre represent the middle of the string. Which mean that if you want to draw in the middle of a 640x480 screen, x will be set to 320. When using textout right, x indicates the right end of the string. Figure 5.4: Textout functions relative X position

Here are a few other useful procedures. When you draw your text, the characters are drawn using the color in parameter and the background color is black. You can change this default black color with the function : int text mode (int mode); You use the index of the color palette or the color value with the makecol function. You can also set this value to -1 to draw transparent text. Which mean that the strings background will not overwrite what is currently drawn on the screen but the letters themselves are not translucent. If you want to know the height of a font to plan correctly your text output, you can use function :

You can also draw justied text. The text will be draw between the x1 and x2 region. If the spare space is greater than di, the string will draw as left aligned text. void textout justify (BITMAP *bmp, const FONT *f, const char *s, int x1, int x2, int y, int diff, int color); When drawing text, you also want to show variables on the screen. You might even want to draw formated text on the screen. To do so, allegro as supplied the textprintf functions which works like printf with the Allegro parameters. fmt hold the format of the data and ... contains the list of the variables that will used. Refer to printf documentation for more informations.

int text height (const FONT *f); This will return the height, in pixels, of the font passed in parameter. To get the length of a string using a specic font, use: int text length (const FONT *f, const char *str); The reason why you must pass a character string in parameter is because some fonts are proportional. Which mean that each letters does not have the same width. So you cannot simply take the width of a letter and multiply it by the length of the string. So you must supply the whole string to get an accurate value. text height does not need this since all letter have the same height. 36

Video Game Programming with allegro 5.2.3 Allegro Fonts

There are no loading functions for fonts, you must use the allegro datale system to load fonts. I wont discuss this here but there is still few thing I wanted to say about how fonts are used in allegro. Font comes in various formats, rst they is xed and proportional fonts. As I said before, proportional fonts have a dierent width for each character. A font generally have one series of 128 characters. You can extend the font to two series of 128 characters in order to get the accented characters in the ASCII table. But there is also unicode font which contains a total of 32768 characters. These fonts are huge but you can draw all characters available in the world including Chinese ideograms. It is also possible to have multicolored font ( 16 colors) I have not use theses yet. For example, the setup program use multicolored font. Allegro can load font from bitmaps or from the .FNT format which is a format dened by the GRX graphic library. The bitmap font must have a specic format to be loaded correctly. There is a good tool to do the job, it is called Allegro Font Editor 1 . This software allows you to import .TTF les into the software, edit the font pixel by pixel and then save it into a bitmap that will be loadable with the Allegro grabber. There is also an add-on called the Allegro Font Library 2 which allows you to draw antialiased fonts. It make the fonts look better but I strongly suggest you do not use them during real-time process: they might be too slow. The example in this chapter consist in drawing an happy face with the message smile! centered in the middle of the screen.

1 2

http://www.geocities.com/miran014 http://nekros.freeshell.org/delirium/alfont.



Graphic Drawing Functions

5.2 Writing text

Listing 5 Drawing an Happy Face /**************************************************************************/ /* Drawing Primitives Demo Programm */ /* By Eric Pietrocupo */ /**************************************************************************/ #include <allegro.h> int main ( void ) { allegro_init(); install_keyboard(); set_color_depth(16); set_gfx_mode( GFX_AUTODETECT, 640, 480, 0, 0 ); circlefill ( screen, 320, 200, 200, makecol (225, 225, 0 )/*yellow*/);//face circlefill ( screen, 230, 130, 25, makecol (0, 0, 225 )/*Blue*/);//L eye circlefill ( screen, 410, 130, 25, makecol (0, 0, 225 )/*Blue*/);//R eye // Mouth arc ( screen, 320, 200, itofix(128), itofix(256), 150, makecol (0, 0, 225 )/*Blue*/); arc ( screen, 320, 200, itofix(128), itofix(256), 140, makecol (0, 0, 225 )/*Blue*/); hline ( screen, 170, 200, 180, makecol (0, 0, 225 )/*Blue*/); hline ( screen, 460, 200, 470, makecol (0, 0, 225 )/*Blue*/); floodfill( screen, 320, 345, makecol (0, 0, 225 )/*Blue*/); textout_centre (screen, font, "Smile!", 320, 440, makecol(225, 225, 225)); textout_right ( screen, font, "Press ENTER to exit", 640, 460, makecol(225, 225, 225) ); while ( (readkey() >> 8) != KEY_ENTER ); allegro_exit(); return (0); } END_OF_MAIN();



The Allegro Bitmaps

Allegro use a system of bitmaps to manage images in a game. The bitmap routines are the ones you will use most of the time in tile based video games. A bitmap, has nothing to do with the .BMP le, it is an object type in itself. A bitmap object is declared as a BITMAP structure. A bitmap can also be something else than a game image. For example the screen is a bitmap. Here is the denition: typedef struct BITMAP { int w, h; // int clip; // int cl, cr, ct, cb; // int seg; // unsigned char *line[]; } BITMAP;


Bitmap Types and Allocation

There are 5 kinds of bitmaps which have all a dierent use: Screen Bitmap : This is a bitmap that point directly to the screen located in the hardware of the video card. Drawing on a screen bitmap draws directly at the screen. Memory Bitmap : This kind of bitmap is used to store images or create video buers. You can draw in them or draw them on another bitmap. This is the most common type of bitmap you will use. Sub Bitmap : This is a virtual bitmap which is in fact a part of another memory bitmap or screen bitmap. If you change the content of a sub bitmap, its parent bitmap will also change. It is useful for dividing a bitmap in smaller units like for example a large image that contains many sprite frames. in this case, you could make 1 sub bitmap for each frame. Video Memory Bitmap : This bitmap is allocated using the memory of the video card. This kind of bitmap can be used to draw on the screen to benet from hardware accelerated routines. Hardware acceleration generally take place when you copy data from video memory to video memory. It can also be used to create a second video screen for page ipping operations. System Bitmap : System bitmap is some way between a memory and video memory

Width,Height Enable Clip Clipping area segment ptr // image data

You might never need to go inside the structure of a BITMAP but it is always useful to know how it works. This structure contains 3 group of information: the size of the bitmap, the clipping area and the image data of the bitmap. Note that the ocial structure contains other variables which we will never use.


Managing the Bitmaps

Most functions which manage bitmap are memory allocation routines, bitmap attribute testing routines and a few other. There are various types of bitmap and each of them has a specic allocation routines. The bitmap attribute routines can test the type of bitmap or the kind of video memory. 39

The Allegro Bitmaps bitmap. It is allocated in system memory and it can be used for drawing with hardware acceleration. Still, not all operating system can support this kind of bitmap and they might not support it the same way. By default, there is a screen bitmap already available that will point on the screen. It is dened as screen: extern BITMAP* screen ; All other bitmap types must be allocated by using bitmap allocation routines. There is a routine for each bitmap type. All routines requires that you pass the width and the height of the bitmap you want. It will then allocate the memory correctly and then return a BITMAP pointer on that bitmap. Here are the allocation routines: BITMAP* create bitmap (int width, int height); BITMAP* create sub bitmap (BITMAP *parent, int x, y, width,height); BITMAP* create video bitmap (int width, int height); BITMAP* create system bitmap (int width, int height); Once you are nished with the bitmaps, you should call destroy bitmap to free the memory used by these. void destroy bitmap (BITMAP *bitmap); 6.1.2 Other Bitmap Functions

6.1 Managing the Bitmaps All these routines return either TRUE or FALSE. When you are running on a non-DOS operating system, especially windows, you will need to lock the screen before starting the drawing operations. The allegro routines will do it automatically if you dont but they might call it more than once. Since locking the screen under Direct X takes a lot of time, it could be desirable to lock it yourself. void void void void acquire screen (); release screen (); acquire bitmap (BITMAP *bmp); release bitmap (BITMAP *bmp);

acquire screen will lock the screen while release screen will unlock the screen. You must call release screen the same number of time that you called acquire screen. There is also the acquire bitmap and the release bitmap functions that does the same job on any other bitmap than screen. When you draw on a bitmap, all pixels drawn outside a bitmap are simply not drawn. This is implemented with the clipping area of a bitmap. By default, the clipping area is the same size than the bitmap. You can reduce the size of the clipping area by using the following function. void set clip (BITMAP *bitmap, int x1, int y1, int x2, int y2); The clipping area is a rectangle than must be SMALLER than the bitmap size, else it could make the game crash if you draw outside the bitmap. X1,Y1 it the top left corner and X2,Y2 is the bottom right corner of the clipping rectangle. If you set all these coordinates to 0, clipping will be turn o and if might increase the drawing speed, but if you draw 1 little pixel outside the bitmap, it will crash horribly. Finally, you can load or save bitmap to les. Except for making screen shots, these are not generally used because you normally use the datale system to load images into your game. Then again, for testing purpose it could be useful. These functions will work according to the color depth you have currently selected. So using save bitmap i n a 16 bit video mode will make a 16 bit image le. 40

There is a few series of functions that you do not use every day but that you still should be aware of. First there is the testing routines which allows you to test an aspect of a bitmap. I wont get through them in details, but here is the list: int int int int int int int is is is is is is is linear bitmap (BITMAP *bmp); planar bitmap (BITMAP *bmp); memory bitmap (BITMAP *bmp); screen bitmap (BITMAP *bmp); video bitmap (BITMAP *bmp); system bitmap (BITMAP *bmp); sub bitmap (BITMAP *bmp);

Video Game Programming with allegro Figure 6.1: Clipping area of a bitmap You should avoid blitting from screen to screen in SVGA mode since it can b e really slow but in Mode-X, it can be faster. It is a good idea to have a source and destination bitmap which have the same color depth else the conversion routines will have to be called, slowing the blitting process. The basic blitting routine is blit which possess 8 parameters: void blit (BITMAP *source, BITMAP *dest, int source x, int source y, int dest x, int dest y, int width, int height); source indicate the bitmap where the data come from and dest indicate where the data will go to. You must rst specify the source and destination bitmap. Then you indicate whats the relative x,y position to start reading in the source bitmap, and what are the x,y where we should start writing in the destination bitmap. The width and height parameters indicate the size of the rectangle to copy. Figure 6.2: Blitting a part of a bitmap to another bitmap

BITMAP* load bitmap (const char *filename, RGB *pal); int save bitmap (const char *filename, BITMAP *bmp, const RGB *pal); load bitmap support .BMP, .LBM, .PCX and the .TGA les while save bitmap support .BMP, .PCX and .TGA les. There is some addon libraries that allow you to load other kind of image formats like .GIF, .PNG and .JPG. Check the Allegro Game Development Community Network 1 web site to download these libraries.


Bitmap Blitting Procedures

To draw images into a bitmap, you can use the blitting and the sprite routines. Blitting allow simple data transfer while sprite can perform a lot of special eects on the image. 6.2.1 Blitting Routines

First there are a few routines which can be used to clear the content of a bitmap. The function clear bitmap allow you to set all the pixel in a bitmap to the color 0 or black. If you want to clear a bitmap to a specic color, you can use clear to color. void clear bitmap (BITMAP *bitmap); void clear to color (BITMAP *bitmap, int color); Then there is a blitting routines which allows you to draw a part of a bitmap to another part of a bitmap while applying the clipping area.


Copying a buer to the screen, which has the same size, will be called like this:


The Allegro Bitmaps blit (buffer, screen, 0, 0, 0, 0, 640, 480 ); There are some other blitting routines which does almost the same job with an added eect on it. void masked blit (BITMAP *source, BITMAP *dest, int source x, int source y, int dest x, int dest y, int width, int height); void stretch blit (BITMAP *source, BITMAP *dest, int source x, source y, source width, source height, int dest x, dest y, dest width, dest height); void masked stretch blit (BITMAP *source, BITMAP *dest, int source x, source y, source w, source h, int dest x, dest y, dest w, dest h); The masked blit routine simply does not draw all the pixel with the color index 0, in 8 bit color depth, or any pixel of color R255,G0,B255 ( some sort of ugly fuchsia ), in true color video mode. This mean, for example, when you are making a sprite, the contour of the sprite that should not be drawn will have to be set to this color. Figure 6.3: Image with transparent contour

6.2 Bitmap Blitting Procedures you must specify the width,height for the destination and the source bitmap. masked stretch blit does the same but it mask color 0 or fuchsia. 6.2.2 Sprite Routines

The dierences between sprites and blitting routines is that sprites does transparency, like masked blit, and it draws the whole source to the destination, so no need to specify width and height. Here is the generic sprite drawing routine. void draw sprite (BITMAP *bmp, BITMAP *sprite, int x, int y); The bmp bitmap is where the sprite will be draw, the sprite bitmap is the image to draw on bmp, and X,Y is the relative position where the sprite will be drawn on bmp. In the example below, we have taken the megaman sprite seen before and we have drawn it into a screen shot of Mighty Bomb Jack. As you can see in the 2nd image, the fuchsia contour has not been draw. Figure 6.4: Draw Sprite Transparent Drawing

There is a set of constants for this transparent color dened for each color depth. #define #define #define #define #define MASK MASK MASK MASK MASK COLOR COLOR COLOR COLOR COLOR 8 15 16 24 32

Figure 6.5: Draw Sprite Transparency Close up

The stretch blit routines allow you to stretch with bitmap bigger or smaller in the target bitmap. Since you are doing some stretching, the width and height of the area to copy will be dierent in the source and destination. So

But the coolest things you can do with the sprite routines is adding some eect. 42

Video Game Programming with allegro void draw sprite BITMAP *sprite, void draw sprite BITMAP *sprite, void draw sprite BITMAP *sprite, v ip (BITMAP *bmp, int x, int y); h ip (BITMAP *bmp, int x, int y); vh ip (BITMAP *bmp, int x, int y); angle); void rotate scaled sprite (BITMAP *bmp, BITMAP *sprite, int x, int y, fixed angle, fixed scale); void rotate scaled sprite v ip (BITMAP *bmp, BITMAP *sprite, int x, int y, fixed angle, fixed scale); The scaling routines use a xed value as scale which is a proportion of the original image. Setting it to 0.5 will shrink the image by half its original size while setting it to 3 will triple the size of the image. Since these parameters are xed, you should use itox and ftox to convert your parameter correctly. Figure 6.8: Sprite rotation and Scaling

These routines allows you to ip vertically, horizontally or both ways the sprite drawn on the screen. The relative x,y position will always be the top left corner and the ip axis is the center of the sprite Figure 6.6: Sprite ipping routines

void stretch sprite (BITMAP *bmp, BITMAP *sprite, int x, int y, int w, int h); Like stretch blit, this routines allow you to stretch a sprite drawn on the screen. You will only need to add, in parameter, the nal width and height you want for your sprite. Figure 6.7: Sprite stretching

You can also rotate the sprite on another rotation point than the center. The pivot routines allows you to rotate the sprite around a point you specify. Here are the routines: void pivot sprite (BITMAP *bmp, BITMAP *sprite, int x, int y, int cx, int cy, fixed angle); void pivot sprite v ip (BITMAP *bmp, BITMAP *sprite, int x, int y, int cx, int cy, fixed angle); void pivot scaled sprite (BITMAP *bmp, BITMAP *sprite, int x, int y, int cx, int cy, fixed angle, fixed scale)); void pivot scaled sprite v ip (BITMAP *bmp, BITMAP *sprite, int x, int y, int cx, int cy, fixed angle, fixed scale); The only new parameter is cx and cy which is the location of the new rotation center. There are a few other routines that I will talk about later in the translucency chapter. Finally, the sample program takes a bitmap that contains 16 sprites of megaman, it make 1 sub bitmap with the rst sprite. Then if hold

There are also some rotation routines which allows to rotate the sprite around its center. void rotate sprite (BITMAP *bmp, BITMAP *sprite, int x, int y, fixed angle); You only need to specify an angle which is a value ranging from 0 to 255. You can also combine rotation with other eects by using these routines: void rotate sprite v ip (BITMAP *bmp, BITMAP *sprite, int x, int y, fixed 43

The Allegro Bitmaps any key, it rotates the sprite continuously on the screen, else if you press enter, it exit. There is some ickering on the screen and I could not make a real-time rotation ( no key holding). To do so require some larger implementation and you must also learn about game timing and screen double buers to produce an animation without ashes.

6.2 Bitmap Blitting Procedures


Video Game Programming with allegro Listing 6 Dizzy Megaman /**************************************************************************/ /* Blitting Routines Demo Programm */ /* By Eric Pietrocupo */ /**************************************************************************/ #include <allegro.h> int main ( void ) { PALETTE tmpal; BITMAP *master_bmp; BITMAP *megaman; RGB black = {0, 0, 0}; RGB white = {255, 255, 255}; bool exit_loop = false; fixed angle; int tmpkey; allegro_init(); install_keyboard(); set_color_depth(8); set_gfx_mode( GFX_AUTODETECT, 320, 240, 0, 0 ); clear_bitmap ( screen ); master_bmp = load_bitmap ("megasprt.bmp", tmpal ); set_palette ( tmpal ); set_color ( 0, &black ); set_color ( 255, &white ); megaman = create_sub_bitmap ( master_bmp, 0, 0, 32, 32 ); angle = itofix (0); while ( exit_loop == false ) { textout_centre ( screen, font, "Hold any key to rotate", 160, 200, 255 /*white*/ ); textout_centre ( screen, font, "Press ENTER to stop this madness", 160, 220, 255 /*white*/ ); rotate_sprite(screen, megaman, 140, 100, angle ); angle = angle + itofix(5);// change angle if ( angle < 256 ) angle = 0; tmpkey = ( readkey() >> 8 ); if ( tmpkey == KEY_ENTER ) exit_loop = true; clear_bitmap ( screen ); } allegro_exit(); return (0); } END_OF_MAIN(); 45

The Allegro Bitmaps

6.2 Bitmap Blitting Procedures



Translucency and Lighting

This chapter talks about a group of functions that can change the behavior of drawing primitives, polygons and even 3D polygons. They enable pattern mapping, lighting and translucency.

Figure 7.1: Two Circle in XOR mode


Drawing Routines Alteration

Drawing Modes indicates the bitmap to use and x,y indicates where, in the pattern, you must start copying the pattern. There are some shortcut routines to do the job. void xor mode (int on); void solid mode (); xor mode will toggle the XOR mode on or o by passing TRUE or FALSE in parameter. solid mode will simply set back the drawing mode to its default. 7.1.2 Drawing Patterns

The alteration is done through drawing modes. Allegro set various modes that you can choose from: DRAW DRAW DRAW DRAW DRAW DRAW MODE MODE MODE MODE MODE MODE SOLID XOR COPY PATTERN SOLID PATTERN MASKED PATTERN TRANS

The DRAW MODE SOLID is the default mode. In this mode, all the drawing routines you know so far works like we have seen it. In the exclusive-OR mode, pixels will erase pixels already in the destination if they are drawn one over each other. The DRAW MODE TRANS is used for translucency while the other modes are use for pattern drawing. If you want to change the behavior of drawing routines, you must call: void drawing mode (int mode, BITMAP *pattern, int x anchor, int y anchor); The mode parameter is one of the constants listed above. The three following parameters are only used for pattern drawing. Pattern 47

Pattern drawing consist in mapping a texture across the surface of a polygon you have drawn. So you can for example, draw a textured circle, rectangle and even a line. To do so, you must set the drawing mode for patterns and supply a given pattern that will be used by all drawing routines until changed. The patterns dimensions must be in exponents of 2. So you can use the following values as width or height : 2, 4, 8, 16, 32, 64, 128, etc. The

Translucency and Lighting Figure 7.2: textured Polygon

7.2 Color Blending oers the possibility to build the palette in a way that would allow you some sort of translucency, but it is really easier in true color video mode. In palette video mode, you can always use fake translucency. Here is an example of translucency from Rockman and Forte: Figure 7.3: Translucent Water

width does not need to be the same size than the height. There is 3 type of pattern drawing mode. The DRAW MODE COPY PATTERN mode simply recopy the pattern as it is on the target area. This mode will ignore the color parameter of the drawing routine. The DRAW MODE SOLID PATTERN will draw a pixel of the drawing routiness color if the pixel in the pattern is solid else it will write color 0 . Which mean that the colors in the pattern are ignored, it is a monochrome pattern. Finally, DRAW MODE MASKED PATTERN works like the solid pattern except that transparent pixels are ignored to make the pattern transparent.

Figure 7.4: No more water


Color Blending
In the rst image, you can see the translucent eect. The blue water over the green pillar change the color of the pillar under water to grey. So they blended the color Blue and Green together to get the color grey. Since you need to calculate the derived color or each pixel drawn this way, translucent drawing is really slow. The Super Nintendo can do this easily because translucency was implemented in the hardware of the console. So the processor was not slowed down. It also allowed translucency to be used in palette video mode since the translucent eect was done just before sending the information to the TV. So there is no need to store the derived color. To do some translucent drawing, you must rst set the drawing mode to DRAW MODE TRANS. This will change 48

What is the dierence between transparency and translucency? As we have seen it in the last chapter, transparency is a part of a sprite which is not drawn on the screen. Translucency consist in drawing a color over another: the color below will be altered by to the color above giving out a new color. For example, If you look through red sun glasses, all the colors you see will be changed to a red tint.


True Color Translucency

Translucency can only be achieved in true color video mode. The reason why is that a new color is created from the combination of 2 other color. So in a palette mode, you will have to store all the possible color combination in the palette. Allegro

Video Game Programming with allegro all the drawing routines behavior. But we also need to set the translucency color blender with the following function: void set trans blender (int r, int g, int b, int a); This routines is some sort of control panel for translucency. All parameters take a value from 0 to 255. The value we are interested in is a which stand for alpha. This is the opacity level of the pixels drawn. Figure 7.5: Opaque VS Clear 7.2.2 Fake Translucency

The Genesis video game console had a palette video mode with no translucent capabilities in its hardware. So it was not capable to do translucency at all. Still, there is a way to get around this by using what I call fake translucency. It is not as beautiful than true translucency but it allow you to do some translucent eects in palette video mode. Here is some examples of fake transparency taken from Revenge of the Shinobi 3 : Figure 7.6: Foots in water

The r,g,b values are used for lighting. In will indicate how the sprite will be lit. If you raise the red value, a lit sprite will look more red while if you raise all values it will look more white. Since the drawing mode only aect drawing primitives, what about drawing translucent sprites. There is 2 sprite routines that I did not talk about in the previous chapter that allows translucency and lighting. void draw trans sprite (BITMAP *bmp, BITMAP *sprite, int x, int y); void draw lit sprite (BITMAP *bmp, BITMAP *sprite, int x, int y, int color); Transparent sprite is inuenced by the values set in set trans blender and the color parameter in lighten sprite indicates the light level. If you are using the 32 bit video mode, you must rst call the following routine to enable 32bit translucency: void set alpha blender (); Once this function is called, all further calls of draw trans sprite will use the alpha values in the pixels to apply translucency since all pixels are saved as (red, green, blue, alpha) in 32 bit video mode. 49

Figure 7.7: Behind the waterfall

In the rst image, you can see that the feet are not completely hidden by the water. This technique is what I call grid Translucency. The idea is to draw 1 pixel out of 2 in a grid pattern. Which mean that half of the foots pixel will be hidden by the water. This is why you can see the gray water pixel and some part of the feet. Figure 7.7 use the same technique but use stripes of pixel instead of a grid. For each odd X position, a line of waterfall pixel is being drawn over the ninja sprite leaving the even X position pixel lines intact. The advantages of this form of translucency is rst the fact that we can use it in palette video

Translucency and Lighting Figure 7.8: Grid and Stripes

7.2 Color Blending

mode since there is no derived color. Second, it is much more faster because we do not need to calculate the derived color for each pixel. Fake transparency can look ugly on the screen shots above but in an higher resolution mode, it will be better since the pixels are smaller on the screen. Still, it will never be as good than a true translucent picture. 7.2.3 Other Color Blender

Besides translucent color blending, there are other kind of color blending available. Most of these color blenders are available in graphic painting software. You must call a function to set the appropriate color blender active. Each color blender has a dierent behavior, look at the documentation for more details. Here is a list: set set set set set set set set set set set set add blender burn blender color blender dierence blender dissolve blender dodge blender hue blender invert blender luminance blender multiply blender saturation blender screen blender

Figure 7.9: Various Color Blending

I wont get through these in detail. I listed them only for you to be aware that they exist. Here are some examples of color blending made with some of the routines above. The example for this chapter demonstrate the usage of pattern copy and translucency. I made a small program that map a texture on the screen, draw a circle with another texture and then draw 8 translucent circles of dierent colors around the main circle. 50

Video Game Programming with allegro Listing 7 Translucent Color Palette /**************************************************************************/ /* Drawing modes and Translucency */ /* By Eric Pietrocupo */ /**************************************************************************/ #include <allegro.h> int main ( void ) { allegro_init(); install_keyboard(); set_color_depth(16); set_gfx_mode( GFX_AUTODETECT, 640, 480, 0, 0 ); clear_bitmap ( screen ); PALETTE tmppal; BITMAP *texture1 = load_bmp ("hrgreen2.bmp",tmppal ); BITMAP *texture2 = load_bmp ("hryelow4.bmp",tmppal ); drawing_mode ( DRAW_MODE_COPY_PATTERN, texture1, 0, 0 ); rectfill ( screen, 0, 0, 640, 480, 0 ); drawing_mode ( DRAW_MODE_COPY_PATTERN, texture2, 0, 0 ); circlefill ( screen, 320, 240, 100, 0 ); drawing_mode ( DRAW_MODE_TRANS, NULL, 0, 0 ); set_trans_blender ( 0, 0, 0, 150 ); circlefill ( screen, 220, 240, 50, makecol ( 255, 100, 100 circlefill ( screen, 250, 170, 50, makecol ( 255, 255, 100 circlefill ( screen, 320, 140, 50, makecol ( 100, 255, 100 circlefill ( screen, 390, 170, 50, makecol ( 100, 255, 255 circlefill ( screen, 420, 240, 50, makecol ( 100, 100, 255 circlefill ( screen, 390, 310, 50, makecol ( 255, 100, 255 circlefill ( screen, 320, 340, 50, makecol ( 255, 255, 255 circlefill ( screen, 250, 310, 50, makecol ( 100, 100, 100 while ( (readkey() >> 8) != KEY_ENTER ); allegro_exit(); return (0); } END_OF_MAIN();

) ) ) ) ) ) ) )

); ); ); ); ); ); ); );


Translucency and Lighting

7.2 Color Blending



3D Polygons

Allegro comes with a series of 3D polygons routines. I am not sure if they are really more performing than other 3D engines. It might not be the best 3D engine, but for doing simple 3D polygons, it will work perfectly. For example, Final Fantasy Tactics use polygons to draw the terrain and they used sprites for the characters and special eects. This can easily be done with Allegro. There is also an extension library called Allegro GL1 which allow support of OpenGL with the Allegro library.


3D Vertex

There is 2 way to store 3D coordinates in Allegro, use oat or use xed variable. I strongly suggest you use the xed variables since the routines are much more faster. Still, you have to make sure you use itox routines or shift by 16 bit to the left when you initialize xed variables (ex: 15016). Here is the main structure of a 3D vertex: typedef struct V3D { fixed x, y, z; - position fixed u, v; - texture map position int c; - color } V3D; V3D is the xed version of a 3D vertex. If you want to use the oat version, you should use V3D f instead. All routines that use oat will have the f sux on them. For example : polygon3d and polygon3d f. For the vertex structure, the X, Y and Z position represent the coordinates of the polygons its virtual environment. The U, V are coordinates for the texture to be mapped on the polygon. The C parameter is used for the color of the vertex on the polygon. Its interpretation is dierent according to the polygon drawing type. Normally, you set the virtual coordinates of the polygon in the x,y,z variables and then you multiply the vertex by the camera matrix. The result will set in the x,y variable the 2D coordinates where the polygon must appear on the screen according to the vector of the camera while


Pre-calculated 3D Polygons

It is possible to do some 3D polygons without bothering about virtual environment, camera and vectors. This technique is called Pre-calculated 3D polygons. This is the technique I have used for the maze engine of Wizardry Legacy. The advantage is that it is more simple to implement and it requires less processing power but you cannot make real time 3D animation. In some games, it can be useful. It can allow you to pre-generate a landscape or a stage and use the generated landscape as a background that you will scroll during the game. This technique is an easy way for us to learn how to use the 3D polygons routines. When you will have assimilated the basics, you can start using camera and 3D scene routines.



3D Polygons Z will only used for mapping perspective texture correctly. If you want to pre-calculate your polygons, you can set the 2D X,Y position yourself and set an arbitrary Z value for the perspective calculation. So no need to set a camera matrix. You specify where, on the screen, you want the polygons to appear. No need to create a virtual environment. The U,V coordinates are virtual coordinates to map a texture across a polygons. If you have a 128x128 pixel texture, you can map the texture to your vertex like this: (0,128),( 0,0),(128,0),(128,128). You should start from the bottom left corner of the polygons and move clock wise. If you want to map half of the texture, replace the values to 64 while if you want to map the texture twice over the polygon, set the values to 256. From the test I have made in my maze engine, you should set the vertex in the same order as illustrated on gure 8.1. This is his not an absolute rule, but doing it this way works correctly. Figure 8.1: Vertex Order

8.1 Pre-calculated 3D Polygons You can also use the color for lighting when drawing in lighten polygon mode. After various testing of my maze engine in Wizardry Legacy, the green value of RGB determine the light level. In the 15 bit video mode, it mean that this value must range from 32 to 1023. If you set an higher value, there will be multiple light gradient on the polygons. This is what I have learned from my personal experience. Here is an example of table initialization for a 4 vertex polygon: V3D polyvtx = { { 136<<16, 400<<16, { 136<<16, 80<<16, { 504<<16, 80<<16, { 504<<16, 400<<16, };

2,0, 128<<16, 2,0, 0, 2,128<<16,0, 2,128<<16,128<<16,

990}, 990}, 990}, 990}

This polygon is a rectangle that will be drawn in the middle of the screen. The texture is 128x128 pixel and is mapped completely over the polygon. If the texture was 64x64 it would have been mapped twice, the light level is set to 990 which mean 93% of its maximum ((( 99031)/1024)x100). The z value 2 is an arbitrary value. I set these value ranging from 1 to 4 which each corresponded, in my maze, to a dierent depth. Here the walls vertex are set on the same depth. If I make a side wall, 2 vertex will be in front and the 2 other on the back, so we will have set two dierent Z values just to make sure the textures get mapped correctly in perspective mode (see later). 8.1.2 Drawing 3D polygons

Finally, the color parameter has dierent interpretation according to the type of polygons you are drawing (see later). The color can be used for 2 purpose, set the color of the polygon or set the lighting of a texture. To set the color, simply use makecol routine to do the job. Warning! makecol use the color depth of the screen to work eciently. If you use makecol in global variable initialization, the makecol routines will be called before set color depth is called giving out weird colors. You can chose to save your color separately in RGB value and generate the color with makecol during the game or calculate the value yourself.

Now that you know how to set the coordinates of your polygons, how do you draw them on the screen? There are a few routines that allows you to do the job. There is rst the generic routine polygon3d: void polygon3d (BITMAP *bmp, int type, BITMAP *texture, int vc, V3D *vtx[]); This routines allows to draw a 3D polygon of any number of vertex. The bmp parameter 54

Video Game Programming with allegro is the bitmap where the polygon is drawn, type is used for the polygon drawing type (see below). The texture parameter is the bitmap that will be used as texture on the polygon. vc indicates the number of vertex the polygon must have and vtx is a pointer on the table of 3D vertex. If you draw a 3 or 4 vertex polygon, you can use the more optimized routines triangle and quad. They each come with their oat variant too. Here is their denition : void triangle3d (BITMAP *bmp, int type, BITMAP *tex, V3D *v1, *v2, *v3); void quad3d (BITMAP *bmp, int type, BITMAP *tex, V3D *v1, *v2, *v3, *v4); In these routines, you must pass each vertex in a separate parameter instead of passing a table of vertex. If you already know the number of vertex your polygons will have, I strongly suggest you use these routines. Finally, there is the polygons types. Most polygon types are inuenced by drawing modes seen in the translucency chapter. So you might need to set drawing mode and set trans blender correctly before using 3D polygons. Each polygon routines has a type parameter which specify the type of polygons you want to draw. The type is a constant that must be taken from the list below. Here is the list with a description and a screen shot for each polygon type. Figure 8.2: Flat VS Gcol modes

POLYTYPE ATEX This is the rst type of textured polygon called Aned texture. This polygon types does not consider the Z value to calculate correctly the perspective. The advantage is that the texture is drawn faster. POLYTYPE PTEX This is the perspective correct textured polygon. It use the Z variable to map the texture correctly. It is a bit slower than aned textures. Figure 8.3: Ane VS Perspective texture

POLYTYPE ATEX MASK POLYTYPE PTEX MASK These polygon types consider the transparent pixels in the texture. They are simply not drawn. There is the ane texture and perspective texture version of this polygon. POLYTYPE ATEX LIT POLYTYPE PTEX LIT These polygon types will consider the color value as a light level. It will spread the light on the texture according to the light level of each vertex. POLYTYPE ATEX MASK LIT POLYTYPE PTEX MASK LIT These types combine transparent pixel skipping and texture lighting.

POLYTYPE FLAT This simply draw a polygon using 1 single color for the whole polygon. It use the color of the 1st vertex for the whole polygon. POLYTYPE GCOL This polygon type draw a single color tint over the polygons. Each vertexs color control the color distribution over the polygon. POLYTYPE GRGB This polygon type draw a multicolored polygon. The color variation changes are done with the color of each vertex. 55

3D Polygons Figure 8.4: Non masked VS masked texture

8.1 Pre-calculated 3D Polygons This chapter ends for now. I might add later a 2nd section that explain Z-Buering routines and 3D scene routines. I have not used them yet so I cannot explain them to you. There wont be an example for this chapter, Ill wait to nish it completely before making an example.

Figure 8.5: Lighten VS Masked lighten

POLYTYPE ATEX TRANS POLYTYPE PTEX TRANS These polygon types allow you to draw translucent polygons. The translucency is controlled by set trans blender. POLYTYPE ATEX MASK TRANS POLYTYPE PTEX MASK TRANS These types combine the transparent pixel skipping and translucency together. Figure 8.6: Translucent VS Masked Translucent

So the only thing you need is to pass the right polygon type in parameter and adjust the color value according to the polygon type. So this is all there is to say about pre-calculated polygons. 56


Allegro Conguration

This chapter has been skipped since the conguration routines are rarely used. There is the allegro setup programm which could be interesting to talk about but I still decided to skip this chapter.


Allegro Conguration



Allegro File System

This chapter will focus on how to use the Allegro datale system. I will also talk a bit about the le access routines which are normally used internally by Allegro. Nevertheless, some of these routines can be useful for you.

Figure 10.1: Allegro Datale Organization


Allegro Datales

A datale is a le that regroup many other les. It is an archive like the .TAR le which can also be compressed like .ZIP, .RAR, .ARJ les. Datales are really useful, in fact, they are essential. In a video game, you will have many images, sounds, fonts and music. Each of these will be stored in a separate le. If you dont place them in an archive, youll have to save thousand of les in a subdirectory structure of your game. This will make the user lose some disk space due to the partition cluster system and it will make the les accessible to the user. If you place the les in an archive, youll reduce the number of les to 1 big le, you will be able to protect your data with a password to make sure the user dont rip them o and you can also compress the data to save some disk space. The data will be uncompressed during your game. It also makes your data more organized and make the loading easier since you are only loading 1 le, not thousands of them. 10.1.1 Datale Structure

you will always use pointers on an array of DATAFILE structure. Here is the declaration of the structure. typedef struct DATAFILE { void *dat; //- data pointer int type; //- data type long size; //- nb bytes void *prop; //- Properties } DATAFILE; The type indicate what kind of content is pointed by dat. The list of types available is shown below. The size eld stores the length of the entry in bytes. The property eld is used to store a list of properties you can add to your object in the grabber. It can be useful to identify some entries which will be processed dierently

A datale item is stored as a DATAFILE structure. Unless you are loading objects separately, 59


10.1 Allegro Datales This loading routine will call callback each time a datale entry is loaded. It will allow you to draw a progress bar while loading your le. This can be useful if your datale takes a lot of time to load but It is also cool. Here is a example of call back that I had used in my Wizardry Legacy game: void InitProc_datafile_loading (DATAFILE *f) { static dword progress = 0; static word drawval = 0; static dword eval = 0; short max = ZZZ_END_OF_ARCHIVE; progress++; eval = ( progress * 200 ) / max; if ( eval > drawval ) { drawval = eval; rectfill ( screen,219,399,219+drawval, 415, makecol ( 225, 175, 0 ) ); } }

A datale can be saved with a with encryption and compression. To encrypt your datale, you will have to set a password in the grabber. Then, when you open your datale, you must set the password by using packle password(see later). You can compress you le in global or individual mode. If you compress you le globally, you will have to uncompress the whole le if you want to load 1 object. In individual mode, each entry is compressed separately, so this problem wont occur. If you always intend to load the datale completely, use global compression. 10.1.2 Datale Loading

Before loading a datale, make sure you enable the video mode and the color depth to make sure that the images are loaded correctly. The basic routine to load a datale is: DATAFILE* load datale (const char *filename); Simply pass the name of your datale in parameter, the routine will load the whole datale in memory and return you a pointer on an array of DATAFILE structure. If this routine returns NULL then the datale has not been loaded correctly, do not use any of the data objects. You can remove from memory a loaded datale by calling: void unload datale (DATAFILE *dat); You pass in parameter the datale pointer you had received when loading it. There is also a loading routine with a callback. DATAFILE* load datale callback (const char *filename, void (*callback)(DATAFILE *d));

This routine simply draw a progress bar. I wont go in this routine in detail but a cool feature is done with ZZZ END OF ARCHIVE. In my datale, there is a dummy entry located at the end named ZZZ END OF ARCHIVE. A constant for each datale entry is made (see later) so constant contains the ID of the last item in the datale which is also the number of item in the datale. Now that I know how many entries there are, I can plan drawing my progress bar more easily. If I add new entries, the last entry ID will increment too, so no need to change the code. You can also load a datale object separately. You must use the following procedures to load/unload an object: DATAFILE* load datale object (const char *filename, const char *objectname); void unload datale object (DATAFILE *dat); This will return a pointer on one datale structure. So you will need more pointers if you want to load more entries. 60

Video Game Programming with allegro 10.1.3 Accessing Methods the name of each frame but you can use the base ID + variable formula to calculate the index of the entry. For example, we could write: draw sprite(screen, datf[BMP FRAME0 + frame].dat, x, y); Frame would be a variable ranging from 0 to 3 indicating which frame must be drawn. When load objects individually, you will have to specify the name of the entry with the name of the datale. Then, you use your pointer to access directly the data. There is no index since there is no array. MID intro = load datafile object ("datafile.dat", "MID INTRO"); play midi(MID intro->dat); If you compile under C++, you will have a compilation error when attempting to use a dat pointer with any Allegro routine. The reason why is because you are converting from a void pointer to another type of pointer ( BITMAP, MIDI, etc ). This is why you must use a cast each time you use the dat eld. draw sprite(screen, (BITMAP*) datf[BMP FRAME3].dat, x, y); This can get annoying while coding. This is why, in my game, I have used a macro system that does the job for you. Here is an entry example from my Wizardry Legacy game. #define BMP ennemy000 (BITMAP*) datfennemy [BMP ENNEMY000].dat I create a constant macro that rst cast the datale in a BITMAP type and it use the right datale datfennemy since I have divided my datale in multiple les since saving a datale took me 10 minutes. When the macro is ready, you can use the macro instead of the constant. Take note that when you have a large amount of data, splitting the datale, into at most a dozen of le, can be useful because saving the datale can take a lot of time. If you change 1 entry, you wont have to re-save everything. I generally regroup the sub datale by theme. I also use some naming conventions. As you can see, all the datale entries start with a 3 letter ID like BMP, MID, SMP, FNT, etc. This

What is cool about allegro datale is that the dat eld points on an allegro data format which can be used immediately in any allegro routine. For example, when you add a midi le to your datale, it does not only copy the le in the datale. It decode the midi le completely and save it in the datale as a MIDI object. Once loaded you can simply use directly the object in your code. When you load a datale, you will receive a pointer on an array of DATAFILE. If you want to access an item in the array, you use the array index and the dat pointer like this: DATAFILE *datf = load datafile ("datafile.dat"); draw sprite(screen, datf[5].dat, x, y); In this case, 6th item of the datale will be drawn on the screen. Of course, this item must be an image. Remembering entry numbers can be dicult. Numbers can also change when you add new entries in your datale since they are always stored in alphabetic order. To simplify your life, the grabber utility can generate a header le when it saves your datale. It will create a constant for each entry in your datale like this: 0 MID INTRO 1 MID TITLE BMP FRAME0 2 BMP FRAME1 3 BMP FRAME2 4 BMP FRAME3 5 The number indicate there in the array is located the object. This mean that in the example above, we could instead write the line like this: draw sprite(screen, datf[BMP FRAME3].dat, x, y); If we insert a new object, the constants will also be updated, so the code will use the right index. Note that the constants are simply numbers. Sometimes, in your code, you cannot specify the name of the object. For example, let say you have a sprite with 4 animation frame, you do not know 61

Allegro File System allow to identify easily the content. The datale entries are all in capital letters while the macros use small letter except for the data type prex. This makes it easier to identify your entries and it make sure the macro and constant does not mixup together. You can create a naming convention of your own if you dont like mine . So if you want to use this datale entry with our macro declared in the example above, you will write this: draw sprite(screen, BMP ennemy000, x, y); It makes it much more beautiful and simple to use. The only drawback is that you will have to make the macros by hand. Use copy paste or use a text editor where you can create input macros (rhide can do this) to do the job more easily.

10.2 File and Compression Routines midi) and then you grab the real les content. The les will be loaded in memory and saved in the datale. In gure 10.2, the left column contains the list of all the entries in the datale. On the right, you see the content of the entry. Images and fonts will be shown on the screen, while sound and music can be played by selecting it. You can see all the information of the entry above the content display area. There is a small window on the top right section where you can enable the compression type. On the top, you have the name of the datale, the path and name where the header le will be generated when you save the le. You can also set the password for the encryption, leaving it blank will leave your datale unencrypted. The usage is simple and there is no complex functions. The grabber oer you the possibility to grab parts of an image into an entry. This is useful if you have dierent tiles in an image. You can load the source image in memory and grab the areas manually or you can start a grabbing process with the function Grab from Grid. This will split your source image in tiles and generate the appropriate number of entries required. Figure 10.3: Grabbing parts of a source image


The Grabber Utility

Now that you know how to load and use datales, it would be fun to know how to build them. The best way to build a datale is through the grabber utility. There is also the dat.exe command line utility which can do the same job but is a less user friendly environment. Another tool called exedat.exe allow to append the datale to your program .exe. It fusion your game and data into one le. I have not tested this tool yet. Anyways, here is a screen shot of the grabber. Figure 10.2: The grabber utility

For more details on how to use the grabber, look at the Allegro documentation. I dont want to make a tutorial on how to use the grabber.


File and Compression Routines

The idea of the grabber is that you rst create object of the right type (like bitmap, font or

These routines are not used really often. The advantage of Allegro le routines is that they transcend the operating system. So when you want 62

Video Game Programming with allegro to do some le operation without considering the OS your are running on, it can be useful. Some routines requires attribute ags. There is a list of ags dened based on the DOS/Window le system. When running on Linux, the rights of the le will be converted to these attributes. You should always use these ags for attributes. Since the constants are bit elds, you must use the OR operator to combine ags together. The ags are: FA RDONLY FA SYSTEM FA DIREC FA HIDDEN FA LABEL FA ARCH the entries which match the wildcard, in the lename, and the specied attributes. int for each le (const char *name, int attrib, void (*callback)(const char *filename, int attrib, int param), int param); This routines use a callback system. For each le that match the rules passed in parameter, the callback will be called. The callback will receive the name of the le, the attributes of the le and the param parameter when for each le has been called. param is your parameter, it can allow you to change the behavior of your callback. You do whatever you want with it. If you want to show the content of a directory to the user, the callback will generally copy the le names into a list that will be shown later to the user. If you dont want to use the call back system, you can use another set of routines to do the job manually. int al ndrst (const char *pattern, struct al ffblk *info, int attrib); int al ndnext (struct al ffblk *info); void al ndclose (struct al ffblk *info); I wont explain them in detail, look at the allegro documentation if you need them. The idea is that you select the rst le and then loop to nd each next le. 10.2.2 Filename Strings


Useful Procedures

The most important le routine you might need to use is le exists. This routines allow you to test if a le exist, if it does you can open the le. You MUST use this routines to test if a le exist. I remember using the old method: testing pointer returned by fopen for NULL. It worked pretty well on DOS but it windows it did not worked and the tried to read a le which did not exist. Of course, the it crashed horribly. So this is why you must use le exists especially if you want to make your program portable. The routine requires you to pass the attributes of the le you want to nd. If you wish, there is a shortcut version named exists which will look for any le which are not hidden, system or directory. int le exists (const char *filename, int attrib, int *aret); int exists (const char *filename); Here are a few other routines which are self explainable. They allow you to get some information on les or remove them from the disk. long le size (const char *filename); time t le time (const char *filename); int delete le (const char *filename); Another common thing to do on les is the browsing of a directory. The for each le routines allow to look in a directory by returning all 63

Allegro comes with a set of routines to manage character strings for lenames. I never used these routines, but they can always get handy when you need them. void get executable name (char *buf, int size); This is simple, it is a function that get the le name of your game program. It is more portable than reading argument 0 passed to the main. The following routines are used to x lename and path according to dierent operating system. It can change the case, the slashes, etc.

Allegro File System char* x lename case (char *path); char* x lename slashes (char *path); char* x lename path (char *dest, const char *path, int size); The following routines allow to replace/add a lename or an extension to a path or a lename. char* replace lename (char *dest, const char *path, const char *filename, int size); char* replace extension (char *dest, const char *filename, const char *ext, int size); char* append lename (char *dest, const char *path, const char *filename, int size); These routines allow you to extract only the lename or the extension portion of a path or a lename. char* get lename (const char *path); char* get extension (const char *filename); Like I said, your not going to use them everyday, but it is fun to know that they are available when you need them. 10.2.3 Packed les

10.2 File and Compression Routines must be compressed. The ! parameter set the uncompressed mode but it add the special magic le header(see below). There is also a series of constants which regroup mode letters so that you dont have to bother with them. F WRITE F READ F WRITE PACKED F READ PACKED F WRITE NOPACK Now there is the magic le names. These le names allows you to read a datale entry like if it was a le without using the load datale object routine. It is also useful for reading datale appended to your executable. The command below must be the lename passed to pack fopen. datafile.dat#BMP IMAGE001 This will open the datale entry like if it was a regular le. # This will mean that the datale to open is the one added to your executable le. #BMP IMAGE001 This mean that it must open an entry from the datale appended to your executable. When your le is opened, you can perform all other know read/write operations. To do so, allegro redenes all the common le routines for their PACKFILE. Here is the list, they all work like the standard le routine. int pack fclose (PACKFILE *f); int pack fseek (PACKFILE *f, int offset); int pack feof (PACKFILE *f); int pack ferror (PACKFILE *f); int pack getc (PACKFILE *f); int pack putc (int c, PACKFILE *f); int pack igetw (PACKFILE *f); long pack igetl (PACKFILE *f); int pack iputw (int w, PACKFILE *f); long pack iputl (long l, PACKFILE *f); int pack mgetw (PACKFILE *f); long pack mgetl (PACKFILE *f); int pack mputw (int w, PACKFILE *f); long pack mputl (long l, PACKFILE *f); long pack fread (void *p, long n, 64

Allegro has his own compression and encryption system for his les. It use the LZSS algorithm for its compression. The compression algorithm focus on the speed of the compression, not on the size. This is why packed les can also be re-compressed with a Zip or Rar utility. The datales use this system to compress and encrypt its les but you can also compress and encrypt your own les. This is implemented through a series of pack routines. Let start le opening routine: PACKFILE* pack fopen (const char *filename, const char *mode); Look similar and works almost the same than a normal fopen routine. Still there is a few new ag available for the mode parameter. The p parameter indicates that the le

Video Game Programming with allegro PACKFILE *f); long pack fwrite (const void *p, long n, PACKFILE *f); char* pack fgets (char *p, int max, PACKFILE *f); int pack fputs (const char *p, PACKFILE *f); Finally, if you want some encryption in your les, you must set a global password that will be used by all packle and datale routines. You simply pass in parameter the password you want to the following routine. void packle password (const char *password); If you open a packle or datale with the wrong password load datale or pack fopen will return a NULL pointer like if the le did not exist. Of course, dont read/write on a NULL pointer. So this is all there was to learn about les. Was it interesting! One thing for sure is that I strongly suggest you to use the datales since they are convenient to use and because some data type, like fonts, can only be loaded from datales.


Allegro File System

10.2 File and Compression Routines


Part III Video Game Logic and Algorithms



Advanced User Input

This is a chapter


Advanced User Input



Advanced Video and Graphics

This is a chapter


Advanced Video and Graphics



Special Eects

This is a chapter


Special Eects




This is a chapter






This is a chapter





Game Objects

This is a chapter


Game Objects



Collision Detection

This is a chapter


Collision Detection



The Main Game Loop

This is a chapter


The Main Game Loop




This is a chapter





Fake movies and Sprite Theaters

This is a chapter


Fake movies and Sprite Theaters


Part IV Video Game Design and Engines



Articial Intelligence

This is a chapter


Articial Intelligence



Data Structure

This is a chapter


Data Structure



Popular Game Engines

This is a chapter


Popular Game Engines



Game Conception and Design

This is a chapter


Game Conception and Design



Exercice : Gradius Duel

this is an appendix


Exercice : Gradius Duel



How its Made

this is an appendix


How its Made


List of Tables


Video Buer Memory Size . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 20





List of Figures

1 2.1 2.2 2.3 2.4 2.5 2.6 3.1 3.2 3.3 3.4 3.5 3.6 4.1 4.2 4.3 4.4 4.5 4.6 5.1 5.2 5.3 5.4 105

Video Game Abstract . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . viii keyboard System . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 9

Scan Code and Ascii . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 10 Last Key System . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 11 mouse b bit eld . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 12

mouse pos variable . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 12 Joystick variable structure . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 14 Video Buer . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 17 RGB values . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 19 True Color video buer . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 19 Video Buer in Palette mode . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 20 Color Palette Entry . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 21 8 Bit color depth Emulation . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 21 A sound Wave . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 23 Frequency Variations . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 23 Sampled Sound Wave . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 24 Various Sampling Frequency . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 24 Music Partition . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 25 synthesizer Cell Operations . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 25

Arc and Circle . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 34 Spline . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 34 Ellipse . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 34 Textout functions relative X position . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 36

LIST OF FIGURES 6.1 6.2 6.3 6.4 6.5 6.6 6.7 6.8 7.1 7.2 7.3 7.4 7.5 7.6 7.7 7.8 7.9 8.1 8.2 8.3 8.4 8.5 8.6


Clipping area of a bitmap . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 41 Blitting a part of a bitmap to another bitmap . . . . . . . . . . . . . . . . . . . . . . . . 41 Image with transparent contour . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 42 Draw Sprite Transparent Drawing . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 42 Draw Sprite Transparency Close up . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 42 Sprite ipping routines . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 43 Sprite stretching . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 43

Sprite rotation and Scaling . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 43 Two Circle in XOR mode . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 47 textured Polygon . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 48 Translucent Water . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 48 No more water . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 48 Opaque VS Clear . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 49 Foots in water . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 49 Behind the waterfall . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 49 Grid and Stripes . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 50 Various Color Blending . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 50 Vertex Order . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 54 Flat VS Gcol modes . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 55 Ane VS Perspective texture . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 55 Non masked VS masked texture . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 56 Lighten VS Masked lighten . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 56 Translucent VS Masked Translucent . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 56

10.1 Allegro Datale Organization . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 59 10.2 The grabber utility . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 62 10.3 Grabbing parts of a source image . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 62


List of Code Listings

1 2 3 4 5 6 7

Quick Start Hello World Program True Color Video Mode Usage . . . Palette Video Mode Usage . . . . . Playing Music and Sound . . . . . Drawing an Happy Face . . . . . . Dizzy Megaman . . . . . . . . . . . Translucent Color Palette . . . . .

. . . . . . .

. . . . . . .

. . . . . . .

. . . . . . .

. . . . . . .

. . . . . . .

. . . . . . .

. . . . . . .

. . . . . . .

. . . . . . .

. . . . . . .

. . . . . . .

. . . . . . .

. . . . . . .

. . . . . . .

. . . . . . .

. . . . . . .

. . . . . . .

. . . . . . .

. . . . . . .

. . . . . . .

. . . . . . .

. . . . . . .

. . . . . . .

. . . . . . .

. . . . . . .

. . . . . . .

. . . . . . .

. . . . . . .

. . . . . . .

8 22 22 29 38 45 51






Allegro Game Development Community Network, http://www.allegro.cc/. The Allegro Video game Library, http://www.talula.demon.co.uk/allegro. Mingw32 Compiler, http://www.mingw.org. Amon, Miran.Allegro Font Editor, http://www.geocities.com/miran014. Armageddon Games.Zelda Classic, www.zeldaclassic.com. Bloodshed Software.Mingw32 Dev-Cpp Development Environment, http://www.bloodshed.net/ dev/. Connell, Jamie O.FM MIDI Synth Driver, http://www.midiox.com/?http://www.midiox.com/ jsoft.htm. Delirium Software.Allegro Font Library, http://nekros.freeshell.org/delirium/alfont.php. Delorie, DJ.DJGPP Compiler, http://www.delorie.com/djgpp/. Fodor, Marius.Super Jukebox, http://superjukebox.zophar.net. Foot, George.Allegro Vivace Tutorial, http://www.glost.eclipse.co.uk/gfoot/vivace/vivace. txt. Foot, George et al..Allegro GL, http://allegrogl.sourceforge.net/. Hargreaves, Shawn.Free BE/AF, http://www.talula.demon.co.uk/freebe/. Hoehne, Robert.DJGPP Interactive Development Environment, http://www.rhide.com. LaMothe, Andree et al..Tricks of the game programming gurus, Indianapolis: Sams Publishing, 1994, 746 pages. Pietrocupo, Eric.Video Game Programming with allegro, ariel.bdeb.qc.ca/~ericp/allegro. Pietrocupo, Eric.The Wizardry Legacy Project, ariel.bdeb.qc.ca/~ericp/wizardry. Sandmann, Charles W.CWSDPMI driver, http://clio.rice.edu/cwsdpmi/. Sci-Tech Software.Display Doctor, http://www.scitechsoft.com/.


Allegro Routines Index

putpixel, 33 putpixel16, 33 putpixel24, 33 acquire bitmap, 40 acquire screen, 40 adjust sample, 26 al ndclose, 63 al ndrst, 63 al ndnext, 63 allegro exit, 6 allegro init, 6 append lename, 64 arc, 34 blit, 41 calc spline, 35 calibrate joystick, 13 circle, 34 circlell, 34 clear bitmap, 41 clear keybuf, 11 clear to color, 6, 41 create bitmap, 40 create sub bitmap, 40 create system bitmap, 40 create video bitmap, 40 delete le, 63 destroy bitmap, 40 destroy midi, 27 destroy sample, 26 detect digi driver, 26 detect midi driver, 26 do arc, 35 do circle, 35 do ellipse, 35 do line, 35 draw lit sprite, 49

draw sprite, 42 draw sprite h ip, 43 draw sprite v ip, 43 draw sprite vh ip, 43 draw trans sprite, 49 drawing mode, 47, 49, 55 ellipse, 34 ellipsell, 34 END OF FUNCTION, 11 END OF MAIN, 6, 11 exists, 63 le exists, 63 le size, 63 le time, 63 x, vi x lename case, 64 x lename path, 64 x lename slashes, 64 oodll, 35 for each le, 63 ftox, 43 generate 332 palette, 21 get color, 21 get executable name, 63 get extension, 64 get lename, 64 get mouse mickeys, 12, 13 get palette, 21 getpixel, 33 hline, 34 i, 40 install install install install install joystick, 13 keyboard, 6, 9 mouse, 12 sound, 26 timer, 26 110

Video Game Programming with allegro is linear bitmap, 40 is memory bitmap, 40 is planar bitmap, 40 is screen bitmap, 40 is sub bitmap, 40 is system bitmap, 40 is video bitmap, 40 itox, 34, 43, 53 keypressed, 10 line, 33 load bitmap, 41 load datale, 60, 65 load datale callback, 60 load datale object, 60, 64 load joystick data, 14 load midi, 27 load voc, 26 load wav, 26 LOCK FUNCTION, 11 LOCK VARIABLE, 11 makecol, 6, 19, 33, 36, 54 masked blit, 42 masked stretch blit, 42 midi pause, 27 midi resume, 27 num joysticks, 13 pack pack pack pack pack pack pack pack pack pack pack pack pack pack pack pack pack pack pack 111 fclose, 64 feof, 64 ferror, 64 fgets, 65 fopen, 64, 65 fputs, 65 fread, 64 fseek, 64 fwrite, 65 getc, 64 igetl, 64 igetw, 64 iputl, 64 iputw, 64 mgetl, 64 mgetw, 64 mputl, 64 mputw, 64 putc, 64 save bitmap, 41 save bmp, 21 save joystick data, 14 scare mouse, 12 SCREEN H, 18 SCREEN W, 18 scroll screen, 18 set add blender, 50 set alpha blender, 49 set burn blender, 50 set clip, 40 set color, 21 set color blender, 50 set color depth, 6, 19, 54 set dierence blender, 50 set dissolve blender, 50 set dodge blender, 50 set gfx mode, 6, 18, 19 set hue blender, 50 set invert blender, 50 packle password, 60, 65 pivot scaled sprite, 43 pivot scaled sprite v ip, 43 pivot sprite, 43 pivot sprite v ip, 43 play midi, 27 play sample, 26 poll joystick, 14 poll keyboard, 10 poll mouse, 12 polygon, 34 polygon3d, 53, 54 polygon3d f, 53 position mouse, 12 putpixel, 33 quad3d, 55 readkey, 6, 9, 10 rect, 21, 34 rectll, 34 release bitmap, 40 release screen, 40 replace extension, 64 replace lename, 64 rotate scaled sprite, 43 rotate scaled sprite v ip, 43 rotate sprite, 43 rotate sprite v ip, 43

ALLEGRO ROUTINES INDEX set luminance blender, 50 set mouse range, 13 set mouse speed, 13 set mouse sprite, 13 set mouse sprite focus, 13 set multiply blender, 50 set palette, 21 set saturation blender, 50 set screen blender, 50 set trans blender, 49, 55, 56 set volume, 26 show mouse, 12 simulate keypress, 10 solid mode, 47 spline, 34, 35 stop midi, 27 stop sample, 26 stretch blit, 42, 43 stretch sprite, 43 text height, 36 text length, 36 text mode, 36 textout, 36 textout centre, 6, 36 textout justify, 36 textout right, 36 textprintf, 36 textprintf centre, 36 textprintf justify, 36 textprintf right, 36 triangle, 34 triangle3d, 55 unload datale, 60 unload datale object, 60 unscare mouse, 12 vline, 34 vsync, 21 xor mode, 47



Allegro Constants Index







3D Polygon, 53 Color, 53 Drawing, 54 Lighting, 53 Pre-calculated, 53 Texture, 53 Type, 54 Vertex, 53 Ascii, 9 Audio, 26 Initialization, 26 Bitmap Allocation, 39 Blitting, 41 Clearing, 41 Clipping area, 40 Loading and Saving, 40 Locking, 40 Sprite, 42 Flipping, 42 Rotation, 42 Scaling, 42 Transparency, 42 Structure, 39 Test routines, 40 Transparency, 41 Type, 39 Color blender, 48, 50 32 bit video mode, 49 Compiler Dev-cpp, 4, 6 DJGPP, 3 Mingw 32, 4 Rhide, 3, 5 Visual C++, 4 Compiling, 5 115

Datale, 59 Encryption, 65 Generated header, 61 Grabber, 62 Loading, 60 Magic le, 64 Object Access, 61 Constant macro, 61 Index constant, 61 Loading, 60, 61 Type, 60 Structure, 59 Drawing mode, 47 Pattern, 47 solid, 47 Translucent, 48 xor, 47 Drawing primitives, 33 Do drawing Functions, 35 Filled Polygons, 34 Lines, 33 Points, 33 Polygons, 34 File, 62 Attributes, 62 Directory browsing, 63 Exist, 63 Information, 63 String, 63 Extract, 64 Fixes, 63 Replace, 64 Hello world, 5, 6 Image palette, 21 Installation, 3 Interrupt Handler, 10

INDEX Joystick, 13 Calibration, 13 Conguration save/load, 13 Data Structure, 14 Reading, 14 Usb redirection, 13 Keyboard, 9 Driver, 9 Interrupt handler, 10 Last key, 10 Polling, 9 Reading, 9 Mouse, 11 Conguration, 13 Moving, 12 Reading, 12 Show/Hide, 11 Music, 24 .MOD .IT .S3M Format, 27 Audio Stream, 27 Compressed WAV, 27 General MIDI, 25 Instrument, 24, 27 Loading, 27 MIDI, 24 MP3, 27 Playing, 27 Synthesizer, 25 Instrument redenition, 25 Operating system DOS, 3, 5 Linux, 4, 6 Windows, 4, 6 PackFile, 64 Encryption, 65 Opening, 64 Scan Codes, 9 Sound, 23 Amplitude, 23 Frequency, 23 Sample Loading, 26 Playing, 26 Sampling, 24 Bit rate, 24 Frequency, 24 Memory Requirement, 24 Wave, 23 Sound card, 23, 26 Text Output, 35 Background, 36 Draw mode, 36 Font, 35, 37 Font Size, 36 Printing, 36 Translucency, 48, 54 Fake, 49 Transparency, 41, 42 Video, 17 Color depth, 18 Color palette, 20 RGB, 20 Driver, 17 Direct X, 4 Free BE/AF, 3, 17 Vesa, 3 Hardware, 17 Acceleration, 17 Memory, 19 Mode, 17 8 bit emulation, 21 Palette, 20 True color, 18 Monitor, 17 Resolution, 17, 19 Vertical synchronization, 17 Video driver Vesa, 17