AVI Materials

As a courtesy, please do not edit this while this message is displayed.
If this page has not been edited for at least several hours to a few days, please remove this template. This message is intended to help reduce edit conflicts; please remove it between editing sessions to allow others to edit the page.
The person who added this notice will be listed in its edit history should you wish to contact them.
Using Procedural Materials, it is possible to play movies (AVIs, specifically) in the place of materials in a map; using this technique, for example, you could have a movie theatre in your map that was actually displaying a full movie on the screen. While Source already allows you to easily view scripted events elsewhere in the map (using Point_cameras and func_monitors), this technique allows you to display actual movies from your harddrive. This code/mini-tutorial gives you everything you need to fairly easily add AVIMaterial entities to your map. Each entity controls drawing to a certain texture, and allows you to play a movie, pause the movie, change the movie, advance one frame, etc. This code draws heavily from the excellent Procedural_materials tutorial and code kindly provided from Valve (thanks again, Tom and Mike!)
Idea
Procedural_Materials allow you to identify certain materials as procedural meaning that its pixel values are set programmatically, as the level is running; conceptually, you get a 2d array of pixels representing the texture that you then set to be whatever color you want. In our case, we read in the appropriate frame of the movie (which frame is of course dependent on where we are in playback), read its pixels one-by-one, and write them to the texture. Since this is done roughly 60 times a second, we get a nice, smooth movie playback.
How to Install
Unfortunately, there is a fair amount of code to install, and some project settings to change. It's all fairly straight-forward, however, and I believe that if you follow these instructions everything should work correctly.
- Read the tutorial for procedural_materials. Everything in this tutorial builds off of that.
- Download this zip file. It has all the files necessary.
- Copy vf32.lib from C:\Program Files\Microsoft Visual Studio .NET 2003\Vc7\PlatformSDK\Lib (or wherever your VS2003 is installed) to C:\MyMod\src\lib\public (changing the directory to be appropriate for your mod.) Add vf32.lib to the client project in Visual Studio. vfw32.lib is Video for Windows, which has the functions we'll use to read the AVI.
- Copy AVIMaterial.h and AVIMaterial.cpp to C:\MyMod\src\dlls. These files declare and define CAVIMaterial, the server-side entity that controls the movies.
- Copy c_aviMaterial.h, c_aviMaterial.cpp, AVIMaterialProxy.h, AVIMaterialProxy.cpp, AVIMaterialRegen.h, and AVIMaterial.cpp to C:\SecondCity\src\cl_dll. c_aviMaterial declares and defines C_AVIMaterial, the cleverly-named client-side version of CAVIMaterial. AVIMaterialProxy declares and defines CAviMaterialProxy which controls instances of CAviTextureRegen, which does the actual movie drawing.
- Add the entry in SecondCity.fgd to your mod's .fgd. This exposes our AVIMaterial entity to Hammer.
- Copy avi_panel1.vmt, avi_panel1.vtf, avi_panel2.vmt, and avi_panel2.vtf to your mod's materials directory. They go in the root.
- Copy quickone.vmf and quickone.bsp to your mod's maps directory. Again, they go in the root.
- Copy iran.avi and category.avi to the root of your c: drive. (If you don't want to put them there, feel free to put them somewhere else, just make sure to update the AVIMaterial entities in quickone to point at the right location.)
- Open Visual Studio, and add vfw32.lib to the client project. (Right-click on client->Add->Add Existing Item.)
- In Visual Studio, add c_aviMaterial.h, AVIMaterialProxy.h, and AVIMaterialRegen.h to the Header Files folder of your client project.
- In Visual Studio, add c_aviMaterial.cpp, AVIMaterialProxy.cpp, and AVIMaterialRegen.cpp to the Source Files folder of your client project.
- In Visual Studio, add AVIMaterial.h to the Header Files folder of your hl (server) project.
- In Visual Studio, add AVIMaterial.cpp to the Source Files folder of your hl (server) project.
- Compile your project, and run it. In the quickone map, you should see two movies hanging and playing in the middle of the room.
How it works
CAVIMaterial and C_AVIMaterial are a typical client/server entity. Please look at the excellent article on Networking entities for more information. When the map loads, avi_panel1 and avi_panel2 each have a corresponding CAviMaterialProxy instantiated for them. (The line
EXPOSE_INTERFACE( CAviMaterialProxy, IMaterialProxy, "AviRenderer" IMATERIAL_PROXY_INTERFACE_VERSION );
links them to the AviRenderer listed as the proxy in avi_panel1.vmt and avi_panel2.vmt. When Init()ted, each proxy is passed in a pointer to the IMaterial they are in charge of. CAviMaterialProxy also has a static function that searches a static array of CAviMaterialProxy on the basis of their texture names. This is a clunky way of allowing C_AVIMaterials to link up to the appropriate textures (otherwise you couldn't control which movie was getting drawn on which texture.) I'm sure there's a better way to do this, please let me know if you know of one. The CAviMaterialProxy instances are used internally by Source to draw the procedural textures; we mainly use it to passthrough commands to its CAviMaterialRegen, however. Once a C_AVIMaterial is passed its movie filename and texture, it searches the proxies for the right one (meaning the proxy that is drawing to its texture), and records it. It then tells the proxy (which passes it to the regenerator) the movie file to load. From then on, the CAVIMaterial entity can be manipulated using the normal Source I/O system. The code is commented, please see it for implementation details.
How to use it
Currently, the CAVIMaterial entity has the following inputs:
- Play - This will start playing whatever movie is set as the current movie. If the movie has not played before, it will start from the beginning; if the movie is paused, it will resume playing back from where it was paused. If the movie is already playing, it has no effect. If no movie is loaded, nothing will happen.
- Pause - This will pause the currently-playing movie, leaving the last frame visible. If the movie is already paused, nothing will happen. If there is no currently-playing movie, nothing will happen.
- Stop - This will end and clear the currently playing movie.
- AdvanceFrame - This will advance the movie one frame. If no movie is currently loaded, nothing will happen. This input assumes the movie is already paused, but doesn't enforce it.
- SetMovie - This input takes a string which should be the absolute path to an AVI on disk, and sets that AVI to be the currently loaded movie. You should stop playing any active movies before setting a new movie.
The CAVIMaterial entity has the following KeyValues:
- TextureName - This is the name of the material that this CAVIMaterial will draw to. If a material is in more than one place of the map, the movie will be shown on all of them.
- MovieName - This is the absolute path on disk to the AVI that will be initially loaded by the CAviMaterialRegen.
The CAVIMaterial entity has the following spawn flags:
- Play movie immediately - This will start the movie specified in MovieName playing as soon as the map loads.
- Loop movie - This will cause the movie to begin playing again immediately after it is completed.