1 2 /* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *\ 3 * * 4 * FLEXIBLE.H * 5 * by Melinda Green * 6 * melinda@superliminal.com * 7 * Oct. 1996 * 8 * * 9 * RESTRICTIONS: * 10 * None at all. Use this code for anything you like. Enjoy. * 11 * * 12 * DESCRIPTION: * 13 * The "Flexible" class provides a clean wrapper over some D3D * 14 * immediate mode functionality that allows the programmer to easily * 15 * implement a retained mode object with dynamic vertices. * 16 * The resulting object is very nearly a first-class retained mode * 17 * object but for the fact that the real object needs to be created * 18 * within the driver. The difference then is that the real user-visual * 19 * object is maintained inside the flexible object via deligation. * 20 * The GetVisual method returns a pointer to that object which can be * 21 * placed in any D3DRM scene. * 22 * * 23 * All one needs to do to create a custom flexible object is to * 24 * subclass from it and override the UpdateVertexData method. That * 25 * method is called durring display traversal and is passed an * 26 * array of D3DVERTEX into which it writes the vertex positions and * 27 * normals. All vertices must be loaded on the first call, but * 28 * subsequent calls only need to update any changed vertices. * 29 * * 30 * Logically, the primative contains a list of triangle blocks of * 31 * identical topology. For example, the "fire" object in the original * 32 * "uvis" sample was easily reimplemented as a list of "flame" blocks * 33 * where each block contains 8 vertices and 4 triangles connected the * 34 * same way. They differ from each other only by the positions of their * 35 * vertices. Blocks of blocks can also have different colors. * 36 * * 37 * A Pick method is also provided which can be used to determine which * 38 * block and triangle lies under a given pixel in a view. This alone is * 39 * is a very useful feature even if movable vertices are not needed. * 40 * * 41 * A utility method CalculateFlatNormals is provided which will update * 42 * the normals for you for flat shaded objects as long as the vertices * 43 * are arranged according to these simple rules: * 44 * 1) No two non-parallel triangles within a block may begin with * 45 * the same index. * 46 * 2) parallel triangles should be grouped consecutively. * 47 * * 48 * The first rule is important because D3D takes face normals from * 49 * vertices instead of from the faces themselves. Don't ask me why. * 50 * That means that only one normal can be associated with a vertex. * 51 * For flat shading, it takes the face normal from the first vertex of * 52 * each triangle which is therefore what CalculateFlatNormals computes. * 53 * * 54 * The second rule is not strict, but is a good idea because * 55 * CalculateFlatNormals can trivially skip recalculating the same * 56 * normals over again which it would otherwise do. * 57 * * 58 * For smooth shaded objects you must generate your own normals. This * 59 * is because there is no "correct" way to generate vertex normals from * 60 * face data alone. There are several good methods in the literature, * 61 * but the correct one for you will depend upon your data and * 62 * application. Hopefully, the correct normals will fall out of your * 63 * vertex computation such as happens with parametric surface * 64 * tesselation. * 65 * * 66 * BUGS: * 67 * At least under the DxII final version, using a user-visual object * 68 * as a source of shadow does make a proper shadow, but seems to cause * 69 * the object itself not to render. * 70 * * 71 * In some instances, clipping of these objects cause crashing even * 72 * though clipping is always enabled. * 73 * * 74 * I was going to add a feature allowing the app to set a visibility * 75 * flag for each block, but the OP_BRANCH_FORWARD operation doesn't * 76 * seem to work. Therefore, the Flexible subclasses will have to * 77 * implement that effect themselves if desired. One reasonable way to * 78 * do that is to set the coordinates of the vertices of all blocks * 79 * meant to be invisible to be the same as the first visible vertex, * 80 * or perhaps any point within the visible bounding box of the object. * 81 * That might not be the cleanest solution, but if most blocks are * 82 * visible, the performance penalty should be very slight. * 83 * * 84 \* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */ 85 86 #ifndef FLEXIBLE_H 87 #define FLEXIBLE_H 88 89 #include "d3d.h" 90 #include "d3dmacs.h" 91 #include "d3drm.h" 92 93 class Flexible 94 { 95 public: 96 Flexible (LPDIRECT3DRMDEVICE d, LPDIRECT3DRM lpd3drm, int n_verts, 97 int verts_per_block, int n_blocks, int tris_per_block, 98 const int tri_block[][3], int n_colors, 99 const double colors[][3], int blocks_per_color, 100 int flat_shade); 101 virtual ~ Flexible (); GetVisual()102 IDirect3DRMUserVisual *GetVisual() 103 { 104 return uvis; 105 } 106 virtual int UpdateVertexData(D3DVERTEX v[]) = 0; 107 BOOL Render(LPDIRECT3DRMVIEWPORT view); 108 int Pick(LPDIRECT3DRMVIEWPORT view, long x, long y, 109 int *blockptr, int *triptr); 110 void ComputeFlatNormals(D3DVERTEX v[], int verts_per_block, 111 int n_blocks, int tris_per_block, 112 const int tri_block[][3]); 113 114 private: 115 LPDIRECT3DDEVICE m_d3ddev; 116 LPDIRECT3DEXECUTEBUFFER eb; 117 int n_mats, m_state_setup_size, m_block_size, m_color_block_size; 118 LPDIRECT3DMATERIAL *mats; 119 LPDIRECT3DRMUSERVISUAL uvis; 120 }; 121 122 #endif 123