Выбрать главу
Jeff Molofee (NeHe)

* DOWNLOAD Visual C++ Code For This Lesson. 

Lesson 35

I would like to start off by saying that I am very proud of this tutorial. When I first got the idea to code an AVI player in OpenGL thanks to Jonathan de Blok, I had no idea how to open an AVI let alone code an AVI player. I started off by flipping through my collection of programming books. Not one book talked about AVI files. I then read everything there was to read about the AVI format in the MSDN. Lots of useful information in the MSDN, but I needed more information.

After browsing the net for hours searching for AVI examples, I had just two sites bookmarked. I'm not going to say my search engine skills are amazing, but 99.9% of the time I have no problems finding what I'm looking for. I was absolutely shocked when I realized just how few AVI examples there were! Most the examples I found wouldn't compile… A handful of them were way to complex (for me at least), and the rest did the job, but they were coded in VB, Delphi, etc. (not VC++).

The first page I book marked was an article written by Jonathan Nix titled "AVI Files". You can visit it at http://www.gamedev.net/reference/programming/features/avifile/. Huge respect to Jonathan for writing an extremely brilliant document on the AVI format. Although I decided to do things differently, his example code snippets, and clear comments made the learning process alot easier! The second site is titled "The AVI Overview" by John F. McGowan, Ph.D. I could go on and on about how amazing John's page is, but it's easier if you check it out yourself! The URL is http://www.jmcgowan.com/avi.html. His site pretty much covers everything there is to know about the AVI format! Thanks to John for making such a valuable page available to the public.

The last thing I wanted to mention is that NONE of the code has been borrowed, and none of the code has been copied. It was written during a 3 day coding spree, using information from the above mentioned sites and articles. With that said, I feel it is important to note that my code may not be the BEST way to play an AVI file. It may not even be the correct way to play an AVI file, but it does work, and it's easy to use! If you dislike the code, my coding style, or if you feel I'm hurting the programming community by releasing this tut, you have a few options: 1) search the net for alternate resources 2) write your own AVI player OR 3) write a better tutorial! Everyone visiting this site should know by now that I'm an average programmer with average skills (I've stated that on numerous pages throughout the site)! I code for FUN! The goal of this site is to make life easier for the non-elite coder to get started with OpenGL. The tutorials are merely examples on how 'I' managed to accomplish a specific effect… Nothing more, nothing less!

On to the code…

The first thing you will notice is that we include and link to the Video For Windows header / library. Big thanks to Microsoft (I can't believe I just said that!). This library makes opening and playing AVI files a SNAP! For now… All you need to know is that you MUST include the vfw.h header file and you must link to the vfw32.lib library file if you want the code to compile :)

#include <windows.h> // Header File For Windows

#include <gl\gl.h> // Header File For The OpenGL32 Library

#include <gl\glu.h> // Header File For The GLu32 Library

#include <vfw.h> // Header File For Video For Windows

#include "NeHeGL.h" // Header File For NeHeGL

#pragma comment( lib, "opengl32.lib" ) // Search For OpenGL32.lib While Linking

#pragma comment( lib, "glu32.lib" ) // Search For GLu32.lib While Linking

#pragma comment( lib, "vfw32.lib" ) // Search For VFW32.lib While Linking

#ifndef CDS_FULLSCREEN // CDS_FULLSCREEN Is Not Defined By Some

#define CDS_FULLSCREEN 4 // Compilers. By Defining It This Way,

#endif // We Can Avoid Errors

GL_Window* g_window;

Keys* g_keys;

Now we define our variables. angle is used to rotate our objects around based on the amount of time that has passed. We will use angle for all rotations just to keep things simple.

next is an integer variable that will be used to count how much time has passed (in milliseconds). It will be used to keep the framerate at a descent speed. More about this later!

frame is of course the current frame we want to display from the animation. We start off at 0 (first frame). I think it's safe to assume that if we managed to open the video, it HAS to have at least one frame of animation :)

effect is the current effect seen on the screen (object: Cube, Sphere, Cylinder, Nothing). env is a boolean value. If it's true, then environment mapping is enabled, if it's false, the object will NOT be environment mapped. If bg is true, you will see the video playing fullscreen behind the object. If it's false, you will only see the object (there will be no background).

sp, ep and bp are used to make sure the user isn't holding a key down.

// User Defined Variables

float angle; // Used For Rotation

int next; // Used For Animation

int frame=0; // Frame Counter

int effect; // Current Effect

bool sp; // Space Bar Pressed?

bool env=TRUE; // Environment Mapping (Default On)

bool ep; // 'E' Pressed?

bool bg=TRUE; // Background (Default On)

bool bp; // 'B' Pressed?

The psi structure will hold information about our AVI file later in the code. pavi is a pointer to a buffer that receives the new stream handle once the AVI file has been opened. pgf is a pointer to our GetFrame object. bmih will be used later in the code to convert the frame of animation to a format we want (holds the bitmap header info describing what we want). lastframe will hold the number of the last frame in the AVI animation. width and height will hold the dimensions of the AVI stream and finally… pdata is a pointer to the image data returned after we get a frame of animation from the AVI! mpf will be used to calculate how many milliseconds each frame is displayed for. More on this later.

AVISTREAMINFO psi; // Pointer To A Structure Containing Stream Info

PAVISTREAM pavi; // Handle To An Open Stream

PGETFRAME pgf; // Pointer To A GetFrame Object

BITMAPINFOHEADER bmih; // Header Information For DrawDibDraw Decoding

long lastframe; // Last Frame Of The Stream

int width; // Video Width

int height; // Video Height

char *pdata; // Pointer To Texture Data

int mpf; // Will Hold Rough Milliseconds Per Frame

In this tutorial we will create 2 different quadratic shapes (a sphere and a cylinder) using the GLU library. quadratic is a pointer to our quadric object.

hdd is a handle to a DrawDib device context. hdc is handle to a device context.

hBitmap is a handle to a device dependant bitmap (used in the bitmap conversion process later).

data is a pointer that will eventually point to our converted bitmap image data. Will make sense later in the code. Keep reading :)

GLUquadricObj *quadratic; // Storage For Our Quadratic Objects

HDRAWDIB hdd; // Handle For Our Dib

HBITMAP hBitmap; // Handle To A Device Dependant Bitmap

HDC hdc = CreateCompatibleDC(0); // Creates A Compatible Device Context