Adding Textures to the EquationDEMO2 (and all subsequent demos) extends the code described above. Not an awful lot changes - but the code gains the ability to texture the tiles it renders, as opposed to the demonstrative (but painfully retro) wireframe graphics of DEMO1. The biggest addition to the mix in DEMO2 is a new class, CTexture. CTexture encapsulates code required to load a bitmap into memory, hand control of it over to Direct3D's texture management interface, and finally destroy the texture when you are done with it. The code itself is surprisingly simple, all things considered… although the bitmap loading routine can be simplified considerably if you so wish. In fact, the code for LoadTexture can be entirely replaced with the DirectX 7 utility function of the same name! The only reason I've included my own version is that I like to be able to tweak bit depths during loading - something that isn't too relevant for this article. So, I suggest that you either copy my code or use the SDK example! The changes to the code most relevant to this article are contained within the new version of CEngine: GameInit() now includes code to instantiate SampleTexture (a CTexture object). GameMain() is unchanged, except that Demo2Render is called instead of Demo1Render. GameDone() now deletes SampleTexture. The meat of the texturing code is found in Demo2Render. Once variables have been declared, the first new section deals with texture alignment. Direct3D (and OpenGL for that matter) both use floats to indicate texture location relative to a vertex. A value of 0 indicates the beginning of an axis, a value of 1.0 indicates the end of a texture. Thus, the size of a texture is irrelevant at this point. This lets a programmer/artist have pretty fine control over model skinning without needing to worry about precise pixel coordinates. It also makes it nice and easy to apply any texture you want to a quad. I decided that vertex 0 would be the top left, vertex 1 would be the top right, vertex 2 would be bottom left and vertex 3 would be bottom right. Its traditional when talking about textures to use u and v instead of x and y (presumably for the sake of clarity). Within a D3DTLVERTEX, these coordinates are stored as tu and tv. Thus, texture alignment for DEMO2 is setup as follows:
Its worth noting that whatever coordinates you choose, the texture will be warped to fit your polygon. This gives a very quick and easy way of rotating, zooming and panning textures! The next consideration when texturing in Direct3D is the rhw component of D3DTLVERTEX. rhw generally isn't used in a 2D context, since its (to quote the SDK) "often 1 divided by the distance from the origin to the object along the z-axis." We don't have a z axis, so perspective correction isn't going to happen... so we'll just set this to 1.0f:
Finally, since I'm only using one texture, I tell Direct3D to use it to texture all subsequent polygons for the scene:
SetTexture is an interesting command. The 0 represents the texture stage. It is possible (and a good idea, sometimes!) to set several textures to apply to the same render command. With hardware multitexturing, this can be inexpensive in terms of processor performance, and you can create some really neat effects. This is where you would specify bump maps, lightmaps, overlays, etc. With transparency, its even possible to perform multilayer tile rendering this way with only one render call! SetTexture may be your best friend in this respect, but be warned: it is a little slow. You really only want to call it when you have to. Once per tile will work, but if you can find a way to make sure that runs of identical tiles don't require a call to it, then you'll get a frame rate boost. The renderer's inner loop remains unchanged! On the machines I tested the demo on, there wasn't much speed difference between texturing the polygons and just rendering them in wireframe, although this may vary depending upon hardware. For me, probably the best feature of this type of rendering is the texturing engine. Textures are rectangular bitmaps, and don't need to be pre-distorted (with wasted space for color keying). This makes life a lot easier for your artist! Important Note: Texture sizes must be powers of 2 to render properly in Direct3D. Thus, 64x64, 128x32 and 256x16 (etc) are all fine… but 15x15 isn't. This generally isn't a problem, though. Many 3D cards, however, choke on larger textures. Anything above 256x256 probably won't work on a large portion of cards out there (such as everything 3DFX have released when I wrote this article). Larger textures also use up a lot of texture memory, so its probably a good idea to keep textures small - particularly for a tiled engine. |
|||||||||||