/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *\ * * * FLEXIBLE.H * * by Melinda Green * * melinda@superliminal.com * * Oct. 1996 * * * * RESTRICTIONS: * * None at all. Use this code for anything you like. Enjoy. * * * * DESCRIPTION: * * The "Flexible" class provides a clean wrapper over some D3D * * immediate mode functionality that allows the programmer to easily * * implement a retained mode object with dynamic vertices. * * The resulting object is very nearly a first-class retained mode * * object but for the fact that the real object needs to be created * * within the driver. The difference then is that the real user-visual * * object is maintained inside the flexible object via deligation. * * The GetVisual method returns a pointer to that object which can be * * placed in any D3DRM scene. * * * * All one needs to do to create a custom flexible object is to * * subclass from it and override the UpdateVertexData method. That * * method is called durring display traversal and is passed an * * array of D3DVERTEX into which it writes the vertex positions and * * normals. All vertices must be loaded on the first call, but * * subsequent calls only need to update any changed vertices. * * * * Logically, the primative contains a list of triangle blocks of * * identical topology. For example, the "fire" object in the original * * "uvis" sample was easily reimplemented as a list of "flame" blocks * * where each block contains 8 vertices and 4 triangles connected the * * same way. They differ from each other only by the positions of their * * vertices. Blocks of blocks can also have different colors. * * * * A Pick method is also provided which can be used to determine which * * block and triangle lies under a given pixel in a view. This alone is * * is a very useful feature even if movable vertices are not needed. * * * * A utility method CalculateFlatNormals is provided which will update * * the normals for you for flat shaded objects as long as the vertices * * are arranged according to these simple rules: * * 1) No two non-parallel triangles within a block may begin with * * the same index. * * 2) parallel triangles should be grouped consecutively. * * * * The first rule is important because D3D takes face normals from * * vertices instead of from the faces themselves. Don't ask me why. * * That means that only one normal can be associated with a vertex. * * For flat shading, it takes the face normal from the first vertex of * * each triangle which is therefore what CalculateFlatNormals computes. * * * * The second rule is not strict, but is a good idea because * * CalculateFlatNormals can trivially skip recalculating the same * * normals over again which it would otherwise do. * * * * For smooth shaded objects you must generate your own normals. This * * is because there is no "correct" way to generate vertex normals from * * face data alone. There are several good methods in the literature, * * but the correct one for you will depend upon your data and * * application. Hopefully, the correct normals will fall out of your * * vertex computation such as happens with parametric surface * * tesselation. * * * * BUGS: * * At least under the DxII final version, using a user-visual object * * as a source of shadow does make a proper shadow, but seems to cause * * the object itself not to render. * * * * In some instances, clipping of these objects cause crashing even * * though clipping is always enabled. * * * * I was going to add a feature allowing the app to set a visibility * * flag for each block, but the OP_BRANCH_FORWARD operation doesn't * * seem to work. Therefore, the Flexible subclasses will have to * * implement that effect themselves if desired. One reasonable way to * * do that is to set the coordinates of the vertices of all blocks * * meant to be invisible to be the same as the first visible vertex, * * or perhaps any point within the visible bounding box of the object. * * That might not be the cleanest solution, but if most blocks are * * visible, the performance penalty should be very slight. * * * \* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */ #ifndef FLEXIBLE_H #define FLEXIBLE_H #include "d3d.h" #include "d3dmacs.h" #include "d3drm.h" class Flexible { public: Flexible (LPDIRECT3DRMDEVICE d, LPDIRECT3DRM lpd3drm, int n_verts, int verts_per_block, int n_blocks, int tris_per_block, const int tri_block[][3], int n_colors, const double colors[][3], int blocks_per_color, int flat_shade); virtual ~ Flexible (); IDirect3DRMUserVisual *GetVisual() { return uvis; } virtual int UpdateVertexData(D3DVERTEX v[]) = 0; BOOL Render(LPDIRECT3DRMVIEWPORT view); int Pick(LPDIRECT3DRMVIEWPORT view, long x, long y, int *blockptr, int *triptr); void ComputeFlatNormals(D3DVERTEX v[], int verts_per_block, int n_blocks, int tris_per_block, const int tri_block[][3]); private: LPDIRECT3DDEVICE m_d3ddev; LPDIRECT3DEXECUTEBUFFER eb; int n_mats, m_state_setup_size, m_block_size, m_color_block_size; LPDIRECT3DMATERIAL *mats; LPDIRECT3DRMUSERVISUAL uvis; }; #endif