home *** CD-ROM | disk | FTP | other *** search
/ NEXT Generation 27 / NEXT27.iso / pc / demos / emperor / dx3.exe / SDK / SAMPLES / TUNNEL / TUNNEL.C < prev    next >
C/C++ Source or Header  |  1996-08-28  |  25KB  |  718 lines

  1. /*==========================================================================
  2.  *
  3.  *  Copyright (C) 1995, 1996 Microsoft Corporation. All Rights Reserved.
  4.  *
  5.  *  File: tunnel.c
  6.  *
  7.  ***************************************************************************/
  8.  
  9. #include <math.h>
  10. #include <malloc.h>
  11. #include <d3d.h>
  12. #include "d3ddemo.h"
  13.  
  14. /*
  15.  * External funtions which perform much of the math.
  16.  */
  17. extern LPD3DVECTOR D3DVECTORNormalise(LPD3DVECTOR v);
  18. extern LPD3DVECTOR D3DVECTORCrossProduct(LPD3DVECTOR lpd, LPD3DVECTOR lpa,
  19.                                          LPD3DVECTOR lpb);
  20. extern LPD3DMATRIX D3DMATRIXInvert(LPD3DMATRIX d, LPD3DMATRIX a);
  21. extern LPD3DMATRIX D3DMATRIXSetRotation(LPD3DMATRIX lpM, LPD3DVECTOR lpD,
  22.                                         LPD3DVECTOR lpU);
  23. extern void spline(LPD3DVECTOR p, float t, LPD3DVECTOR p1, LPD3DVECTOR p2,
  24.                    LPD3DVECTOR p3, LPD3DVECTOR p4);
  25.  
  26. /*
  27.  * Globals to keep track of execute buffer
  28.  */
  29. static D3DEXECUTEDATA d3dExData;
  30. static LPDIRECT3DEXECUTEBUFFER lpD3DExBuf;
  31. static D3DEXECUTEBUFFERDESC debDesc;
  32.  
  33. /*
  34.  * More globals
  35.  */
  36. LPDIRECT3DMATERIAL lpbmat;
  37. LPDIRECT3DMATERIAL lpmat;   /* Material object */
  38.  
  39. /*
  40.  * Global projection, view, world and identity matricies
  41.  */
  42. D3DMATRIXHANDLE hProj;
  43. D3DMATRIX proj = {
  44.     D3DVAL(2.0), D3DVAL(0.0), D3DVAL(0.0), D3DVAL(0.0),
  45.     D3DVAL(0.0), D3DVAL(2.0), D3DVAL(0.0), D3DVAL(0.0),
  46.     D3DVAL(0.0), D3DVAL(0.0), D3DVAL(1.0), D3DVAL(1.0),
  47.     D3DVAL(0.0), D3DVAL(0.0), D3DVAL(-1.0), D3DVAL(0.0)
  48. };
  49. D3DMATRIXHANDLE hView;
  50. D3DMATRIX view = {
  51.     D3DVAL(1.0), D3DVAL(0.0), D3DVAL(0.0), D3DVAL(0.0),
  52.     D3DVAL(0.0), D3DVAL(1.0), D3DVAL(0.0), D3DVAL(0.0),
  53.     D3DVAL(0.0), D3DVAL(0.0), D3DVAL(1.0), D3DVAL(0.0),
  54.     D3DVAL(0.0), D3DVAL(0.0), D3DVAL(10.0), D3DVAL(1.0)
  55. };
  56. D3DMATRIXHANDLE hWorld;
  57. D3DMATRIX world = {
  58.     D3DVAL(1.0), D3DVAL(0.0), D3DVAL(0.0), D3DVAL(0.0),
  59.     D3DVAL(0.0), D3DVAL(1.0), D3DVAL(0.0), D3DVAL(0.0),
  60.     D3DVAL(0.0), D3DVAL(0.0), D3DVAL(1.0), D3DVAL(0.0),
  61.     D3DVAL(0.0), D3DVAL(0.0), D3DVAL(0.0), D3DVAL(1.0)
  62. };
  63. D3DMATRIX identity = {
  64.     D3DVAL(1.0), D3DVAL(0.0), D3DVAL(0.0), D3DVAL(0.0),
  65.     D3DVAL(0.0), D3DVAL(1.0), D3DVAL(0.0), D3DVAL(0.0),
  66.     D3DVAL(0.0), D3DVAL(0.0), D3DVAL(1.0), D3DVAL(0.0),
  67.     D3DVAL(0.0), D3DVAL(0.0), D3DVAL(0.0), D3DVAL(1.0)
  68. };
  69.  
  70. #define PI 3.14159265359
  71.  
  72. /*
  73.  * These defines describe the section of the tube in the execute buffer at
  74.  * one time. (Note, tube and tunnel are used interchangeably).
  75.  */
  76. #define SEGMENTS 20   /* Number of segments in memory at one time.  Each
  77.                        * segment is made up oftriangles spanning between
  78.                        * two rings.
  79.                        */ 
  80. #define SIDES 8       /* Number of sides on each ring. */
  81. #define TEX_RINGS 5   /* Number of rings to stretch the texture over. */
  82. #define NUM_V (SIDES*(SEGMENTS+1)) // Number of vertices in memory at once
  83. #define NUM_TRI (SIDES*SEGMENTS*2) // Number of triangles in memory
  84. #define TUBE_R 1.0       /* Radius of the tube. */
  85. #define SPLINE_POINTS 50 /* Number of spline points to initially
  86.                           * calculate.  The section in memory represents
  87.                           * only a fraction of this.
  88.                           */
  89. /*
  90.  * Movement and track scalars given in terms of position along the spline
  91.  * curve.
  92.  */
  93. #define SEGMENT_LENGTH 0.05 /* Length of each segment along curve. */
  94. #define SPEED 0.02          /* Amount to increment camera position along
  95.                              * curve for each frame.
  96.                              */
  97. #define DEPTH 0.8           /* How close the camera can get to the end of
  98.                              * track before new segments are added.
  99.                              */
  100. #define PATH_LENGTH (SPLINE_POINTS - 1) /*Total length of the tunnel.*/
  101.  
  102. /*
  103.  * A global structure holding the tube data.
  104.  */
  105. static struct {
  106.     LPD3DVERTEX lpV;        /* Points to the vertices. */
  107.     LPD3DTRIANGLE lpTri;    /* Points to the triangles which make up the
  108.                              * segments.
  109.                              */
  110.     int TriOffset;          /* Offset into the execute buffer were the
  111.                              * triangle list is found.
  112.                              */
  113.     LPD3DVECTOR lpPoints;   /* Points to the points defining the spline
  114.                              * curve.
  115.                              */
  116.     D3DMATERIALHANDLE hMat; /* Handle for the material on the tube. */
  117.     D3DTEXTUREHANDLE hTex;  /* Handle for the texture on the material.*/
  118.     D3DLIGHT light;             /* Structure defining the light. */
  119.     LPDIRECT3DLIGHT lpD3DLight; /* Object pointer for the light. */
  120.     D3DVECTOR cameraP, cameraD, cameraN; /* Vectors defining the camera 
  121.                                           * position, direction and up.
  122.                                           */
  123.     float cameraPos;                     /* Camera position along the 
  124.                                           * spline curve.
  125.                                           */
  126.     D3DVECTOR endP, endD, endN; /* Vectors defining the position, 
  127.                                  * direction and up at the foremost end of
  128.                                  * the section in memory.
  129.                                  */
  130.     float endPos; /* Position along the spline curve of the end. */
  131.     int currentRing, currentSegment; /* Numbers of the ring and tube at 
  132.                                       * the back end of the section.
  133.                                       */
  134. } tube;
  135.  
  136.  
  137. /*
  138.  * Creates a matrix which is equivalent to having the camera at a
  139.  * specified position. This matrix can be used to convert vertices to
  140.  * camera coordinates. lpP    Position of the camera. lpD    Direction of
  141.  * view. lpN    Up vector. lpM    Matrix to update.
  142.  */
  143. void 
  144. PositionCamera(LPD3DVECTOR lpP, LPD3DVECTOR lpD, LPD3DVECTOR lpN, 
  145.                LPD3DMATRIX lpM)
  146. {
  147.     D3DMATRIX tmp;
  148.  
  149.     /*
  150.      * Set the rotation part of the matrix and invert it. Vertices must be
  151.      * inverse rotated to achieve the same result of a corresponding 
  152.      * camera rotation.
  153.      */
  154.     tmp._14 = tmp._24 = tmp._34 = tmp._41 = tmp._42 = tmp._43 = (float)0.0;
  155.     tmp._44 = (float)1.0;
  156.     D3DMATRIXSetRotation(&tmp, lpD, lpN);
  157.     D3DMATRIXInvert(lpM, &tmp);
  158.     /*
  159.      * Multiply the rotation matrix by a translation transform.  The
  160.      * translation matrix must be applied first (left of rotation).
  161.      */
  162.     lpM->_41=-(lpM->_11 * lpP->x + lpM->_21 * lpP->y + lpM->_31 * lpP->z);
  163.     lpM->_42=-(lpM->_12 * lpP->x + lpM->_22 * lpP->y + lpM->_32 * lpP->z);
  164.     lpM->_43=-(lpM->_13 * lpP->x + lpM->_23 * lpP->y + lpM->_33 * lpP->z);
  165. }
  166.  
  167. /*
  168.  * Updates the given position, direction and normal vectors to a given
  169.  * position on the spline curve.  The given up vector is used to determine
  170.  * the new up vector.
  171.  */
  172. void 
  173. MoveToPosition(float position, LPD3DVECTOR lpP, LPD3DVECTOR lpD, 
  174.                LPD3DVECTOR lpN)
  175. {
  176.     LPD3DVECTOR lpSplinePoint[4];
  177.     D3DVECTOR pp, x;
  178.     int i, j;
  179.     float t;
  180.  
  181.     /*
  182.      * Find the four points along the curve which are around the position.
  183.      */
  184.     i = 0;
  185.     t = position;
  186.     while (t > 1.0) {
  187.         i++;
  188.         if (i == SPLINE_POINTS)
  189.             i = 0;
  190.         t -= (float)1.0;
  191.     }
  192.     for (j = 0; j < 4; j++) {
  193.         lpSplinePoint[j] = &tube.lpPoints[i];
  194.         i++;
  195.         if (i == SPLINE_POINTS)
  196.             i = 0;
  197.     }
  198.     /*
  199.      * Get the point at the given position and one just before it.
  200.      */
  201.     spline(lpP, t, lpSplinePoint[0], lpSplinePoint[1], lpSplinePoint[2],
  202.            lpSplinePoint[3]);
  203.     spline(&pp, t - (float)0.01, lpSplinePoint[0], lpSplinePoint[1],
  204.            lpSplinePoint[2], lpSplinePoint[3]);
  205.     /*
  206.      * Calculate the direction.
  207.      */
  208.     lpD->x = lpP->x - pp.x;
  209.     lpD->y = lpP->y - pp.y;
  210.     lpD->z = lpP->z - pp.z;
  211.     D3DVECTORNormalise(lpD);
  212.     /*
  213.      * Find the new normal.  This method will work provided the change in
  214.      * the normal is not very large.
  215.      */
  216.     D3DVECTORNormalise(lpN);
  217.     D3DVECTORCrossProduct(&x, lpN, lpD);
  218.     D3DVECTORCrossProduct(lpN, &x, lpD);
  219.     lpN->x = -lpN->x;
  220.     lpN->y = -lpN->y;
  221.     lpN->z = -lpN->z;
  222.     D3DVECTORNormalise(lpN);
  223. }
  224.  
  225.  
  226. /*
  227.  * Generates a ring of vertices in a plane defined by n and the cross
  228.  * product of n and p.  On exit, joint contains the vertices.  Join must
  229.  * be pre-allocated. Normals are generated pointing in.  Texture
  230.  * coordinates are generated along tu axis and are given along tv.
  231.  */
  232. static void 
  233. MakeRing(LPD3DVECTOR p, LPD3DVECTOR d, LPD3DVECTOR n, float tv,
  234.          LPD3DVERTEX joint)
  235. {
  236.     int spoke;
  237.     float theta, u, v, x, y, z;
  238.     D3DVECTOR nxd;
  239.  
  240.     D3DVECTORCrossProduct(&nxd, n, d);
  241.     for (spoke = 0; spoke < SIDES; spoke++) {
  242.         theta = (float)(2.0 * PI) * spoke / SIDES;
  243.         /*
  244.          * v, u defines a unit vector in the plane define by vectors nxd
  245.          * and n.
  246.          */
  247.         v = (float)sin(theta);
  248.         u = (float)cos(theta);
  249.         /*
  250.          * x, y, z define a unit vector in standard coordiante space
  251.          */
  252.         x = u * nxd.x + v * n->x;
  253.         y = u * nxd.y + v * n->y;
  254.         z = u * nxd.z + v * n->z;
  255.         /*
  256.          * Position, normals and texture coordiantes.
  257.          */
  258.         joint[spoke].x = (float)TUBE_R * x + p->x;
  259.         joint[spoke].y = (float)TUBE_R * y + p->y;
  260.         joint[spoke].z = (float)TUBE_R * z + p->z;
  261.         joint[spoke].nx = -x;
  262.         joint[spoke].ny = -y;
  263.         joint[spoke].nz = -z;
  264.         joint[spoke].tu = (float)1.0 - theta / (float)(2.0 * PI);
  265.         joint[spoke].tv = tv;
  266.  
  267.     }
  268. }
  269.  
  270.  
  271. /*
  272.  * Defines the triangles which form a segment between ring1 and ring2 and
  273.  * stores them at lpTri.  lpTri must be pre-allocated.
  274.  */
  275. void 
  276. MakeSegment(int ring1, int ring2, LPD3DTRIANGLE lpTri)
  277. {
  278.     int side, triangle = 0;
  279.  
  280.     for (side = 0; side < SIDES; side++) {
  281.         /*
  282.          * Each side consists of two triangles.
  283.          */
  284.         lpTri[triangle].v1 = ring1 * SIDES + side;
  285.         lpTri[triangle].v2 = ring2 * SIDES + side;
  286.         lpTri[triangle].v3 = ring2 * SIDES + ((side + 1) % SIDES);
  287.         
  288.         /*
  289.          * for wireframe only need first two edges.
  290.          * Start a two triangle flat fan for each tunnel face.
  291.          */
  292.                 
  293.         lpTri[triangle].wFlags = D3DTRIFLAG_STARTFLAT(1);
  294.         lpTri[triangle].wFlags |= D3DTRIFLAG_EDGEENABLE1 |
  295.                                   D3DTRIFLAG_EDGEENABLE2;
  296.         
  297.         triangle++;
  298.         lpTri[triangle].v2 = ring2 * SIDES + ((side + 1) % SIDES);
  299.         lpTri[triangle].v3 = ring1 * SIDES + ((side + 1) % SIDES);
  300.         lpTri[triangle].v1 = ring1 * SIDES + side;
  301.         
  302.         /*
  303.          * Dont need any edges for wireframe.
  304.          */
  305.         lpTri[triangle].wFlags = D3DTRIFLAG_EVEN;
  306.         
  307.         triangle++;
  308.     }
  309. }
  310.  
  311.  
  312. /*
  313.  * Creates a new segment of the tunnel at the current end position.
  314.  * Creates a new ring and segment.
  315.  */
  316. void 
  317. UpdateTubeInMemory(void)
  318. {
  319.     static int texRing = 0; /* Static counter defining the position of
  320.                              * this ring on the texture.
  321.                              */
  322.     int endRing; /* The ring at the end of the tube in memory. */
  323.     int RingOffset, SegmentOffset; /* Offsets into the vertex and triangle 
  324.                                     * lists for the new data.
  325.                                     */
  326.     /*
  327.      * Replace the back ring with a new ring at the front of the tube
  328.      * in memory.
  329.      */
  330.     memcpy(&tube.lpV[SIDES], &tube.lpV[0], sizeof(tube.lpV[0]) * (NUM_V - SIDES));
  331.     MakeRing(&tube.endP, &tube.endD, &tube.endN, texRing/(float)TEX_RINGS,
  332.              &tube.lpV[0]);
  333.     /*
  334.      * Replace the back segment with a new segment at the front of the
  335.      * tube in memory. Update the current end position of the tube in
  336.      * memory.
  337.      */
  338.     endRing = (tube.currentRing + SEGMENTS) % (SEGMENTS + 1);
  339.     MoveToPosition(tube.endPos, &tube.endP, &tube.endD, &tube.endN);
  340.     /*
  341.      * Update the execute buffer with the new vertices and triangles.
  342.      */
  343.     RingOffset = sizeof(D3DVERTEX) * tube.currentRing * SIDES;
  344.     SegmentOffset = sizeof(D3DTRIANGLE) * tube.currentSegment * SIDES * 2;
  345.     memset(&debDesc, 0, sizeof(D3DEXECUTEBUFFERDESC));
  346.     debDesc.dwSize = sizeof(D3DEXECUTEBUFFERDESC);
  347.     if (lpD3DExBuf->lpVtbl->Lock(lpD3DExBuf, &debDesc) != D3D_OK)
  348.         return;
  349.     memcpy((char *) debDesc.lpData,
  350.            &tube.lpV[0], sizeof(D3DVERTEX) * NUM_V);
  351.     lpD3DExBuf->lpVtbl->Unlock(lpD3DExBuf);
  352.     /*
  353.      * Update the position of the back of the tube in memory and texture
  354.      * counter.
  355.      */
  356.     tube.currentRing = (tube.currentRing + 1) % (SEGMENTS + 1);
  357.     tube.currentSegment = (tube.currentSegment + 1) % SEGMENTS;
  358.     texRing = (texRing + 1) % TEX_RINGS;
  359. }
  360.  
  361.  
  362. /*
  363.  * Move the camera through the tunnel.  Create new segments of the tunnel
  364.  * when the camera gets close to the end of the section in memory.
  365.  */
  366. void 
  367. MoveCamera(LPDIRECT3DDEVICE lpDev, LPDIRECT3DVIEWPORT lpView)
  368. {
  369.     /*
  370.      * Update the position on curve and camera vectors.
  371.      */
  372.     tube.cameraPos += (float)SPEED;
  373.     if (tube.cameraPos > PATH_LENGTH)
  374.         tube.cameraPos -= PATH_LENGTH;
  375.     MoveToPosition(tube.cameraPos, &tube.cameraP, &tube.cameraD,
  376.                    &tube.cameraN);
  377.     /*
  378.      * If the camera is close to the end, add a new segment.
  379.      */
  380.     if (tube.endPos - tube.cameraPos < DEPTH) {
  381.         tube.endPos = tube.endPos + (float)SEGMENT_LENGTH;
  382.         if (tube.endPos > PATH_LENGTH)
  383.             tube.endPos -= PATH_LENGTH;
  384.         UpdateTubeInMemory();
  385.     }
  386. }
  387.  
  388.  
  389. /*
  390.  * Modify the buffer between rendering frames
  391.  */
  392. static void 
  393. TickScene(LPDIRECT3DDEVICE lpDev, LPDIRECT3DVIEWPORT lpView)
  394. {
  395.     MoveCamera(lpDev, lpView);
  396. }
  397.  
  398.  
  399. /*
  400.  * Each frame, renders the scene and calls TickScene to modify the object
  401.  * for the next frame.
  402.  */
  403. BOOL
  404. RenderScene(LPDIRECT3DDEVICE lpDev, LPDIRECT3DVIEWPORT lpView,
  405.             LPD3DRECT lpExtent)
  406. {
  407.     HRESULT ddrval;
  408.  
  409.     /*
  410.      * Move the camera by updating the view matrix and move the light.
  411.      */
  412.     PositionCamera(&tube.cameraP, &tube.cameraD, &tube.cameraN, &view);
  413.     ddrval = lpDev->lpVtbl->SetMatrix(lpDev, hView, &view);
  414.     if (ddrval != D3D_OK)
  415.         return FALSE;
  416.  
  417.     tube.light.dvPosition.x = tube.cameraP.x;
  418.     tube.light.dvPosition.y = tube.cameraP.y;
  419.     tube.light.dvPosition.z = tube.cameraP.z;
  420.     ddrval = tube.lpD3DLight->lpVtbl->SetLight(tube.lpD3DLight, &tube.light);
  421.     if (ddrval != D3D_OK)
  422.         return FALSE;
  423.     /*
  424.      * Execute the instruction buffer and update the view
  425.      */
  426.     ddrval = lpDev->lpVtbl->BeginScene(lpDev);
  427.     if (ddrval != D3D_OK)
  428.         return FALSE;
  429.     ddrval = lpDev->lpVtbl->Execute(lpDev, lpD3DExBuf, lpView, D3DEXECUTE_CLIPPED);
  430.     if (ddrval != D3D_OK)
  431.         return FALSE;
  432.     ddrval = lpDev->lpVtbl->EndScene(lpDev);
  433.     if (ddrval != D3D_OK)
  434.         return FALSE;
  435.     ddrval = lpD3DExBuf->lpVtbl->GetExecuteData(lpD3DExBuf, &d3dExData);
  436.     if (ddrval != D3D_OK)
  437.         return FALSE;
  438.     *lpExtent = d3dExData.dsStatus.drExtent;
  439.     /*
  440.      * Modify for the next time around
  441.      */
  442.     TickScene(lpDev, lpView);
  443.     return TRUE;
  444. }
  445.  
  446. void
  447. OverrideDefaults(Defaults* defaults)
  448. {
  449.     defaults->rs.bZBufferOn = FALSE;
  450.     defaults->rs.bPerspCorrect = TRUE;
  451.     defaults->bClearsOn = FALSE;
  452.     lstrcpy(defaults->Name, "Tunnel D3D Example");
  453. }
  454.  
  455. BOOL
  456. InitScene(void)
  457. {
  458.     float position;             /* Curve position counter. */
  459.     int i;                      /* counter */
  460.  
  461.     /*
  462.      * Reserved memory for vertices, triangles and spline points.
  463.      */
  464.     tube.lpV = (LPD3DVERTEX) malloc(sizeof(D3DVERTEX) * NUM_V);
  465.     tube.lpTri = (LPD3DTRIANGLE) malloc(sizeof(D3DTRIANGLE) * NUM_TRI);
  466.     tube.lpPoints = (LPD3DVECTOR) malloc(sizeof(D3DVECTOR)*SPLINE_POINTS);
  467.     /*
  468.      * Generate spline points
  469.      */
  470.     for (i = 0; i < SPLINE_POINTS; i++) {
  471. #if 1
  472.         tube.lpPoints[i].x = (float)(cos(i * 4.0) * 20.0);
  473.         tube.lpPoints[i].y = (float)(sin(i * 4.0) * 20.0);
  474.         tube.lpPoints[i].z = i * (float)20.0;
  475. #else
  476.         tube.lpPoints[i].x = (float)0.0;
  477.         tube.lpPoints[i].y = (float)0.0;
  478.         tube.lpPoints[i].z = i * (float)20.0;
  479. #endif
  480.     }
  481.     /*
  482.      * Create the initial tube section in memory.
  483.      */
  484.     tube.endN.x = (float)0.0;
  485.     tube.endN.y = (float)1.0;
  486.     tube.endN.z = (float)0.0;
  487.     position = (float)0.0;
  488.     for (i = 0; i < SEGMENTS + 1; i++) {
  489.         MoveToPosition(position, &tube.endP, &tube.endD, &tube.endN);
  490.         position += (float)SEGMENT_LENGTH;
  491.         MakeRing(&tube.endP, &tube.endD, &tube.endN, 
  492.                  (float)(i % TEX_RINGS) / TEX_RINGS,
  493.                  &tube.lpV[(SEGMENTS - i) * SIDES]);
  494.     }
  495.     for (i = 0; i < SEGMENTS; i++)
  496.         MakeSegment(i + 1, i, &tube.lpTri[i * SIDES * 2]);
  497.     /*
  498.      * Move the camera to the begining and set some globals
  499.      */
  500.     tube.cameraN.x = (float)0.0;
  501.     tube.cameraN.y = (float)1.0;
  502.     tube.cameraN.z = (float)0.0;
  503.     MoveToPosition((float)0.0, &tube.cameraP, &tube.cameraD, &tube.cameraN);
  504.     tube.currentRing = 0;
  505.     tube.currentSegment = 0;
  506.     tube.cameraPos = (float)0.0;
  507.     tube.endPos = position;
  508.     return TRUE;
  509. }
  510.  
  511. void
  512. ReleaseScene(void)
  513. {
  514.     if (tube.lpPoints)
  515.         free(tube.lpPoints);
  516.     if (tube.lpTri)
  517.         free(tube.lpTri);
  518.     if (tube.lpV)
  519.         free(tube.lpV);
  520. }
  521.  
  522. void
  523. ReleaseView(LPDIRECT3DVIEWPORT lpView)
  524. {
  525.     if (lpView)
  526.         lpView->lpVtbl->DeleteLight(lpView, tube.lpD3DLight);
  527.     RELEASE(lpD3DExBuf);
  528.     RELEASE(tube.lpD3DLight);
  529.     RELEASE(lpmat);
  530.     RELEASE(lpbmat);
  531. }
  532.  
  533.  
  534. /*
  535.  * Builds the scene and initializes the execute buffer for rendering.
  536.  * Returns 0 on failure.
  537.  */
  538. BOOL
  539. InitView(LPDIRECTDRAW lpDD, LPDIRECT3D lpD3D, LPDIRECT3DDEVICE lpDev, 
  540.            LPDIRECT3DVIEWPORT lpView, int NumTextures, 
  541.            LPD3DTEXTUREHANDLE TextureHandle)
  542. {
  543.     /* Variables for exectue buffer generation */
  544.     LPVOID lpBufStart, lpInsStart, lpPointer;
  545.     LPDIRECT3DEXECUTEBUFFER lpD3DExCmdBuf;
  546.     DWORD size;
  547.  
  548.     /* Background material variables */
  549.     D3DMATERIAL bmat;
  550.     D3DMATERIALHANDLE hbmat;
  551.     D3DMATERIAL mat;
  552.  
  553.     /*
  554.      * Set background to black material
  555.      */
  556.     if (lpD3D->lpVtbl->CreateMaterial(lpD3D, &lpbmat, NULL) != D3D_OK)
  557.         return FALSE;
  558.     memset(&bmat, 0, sizeof(D3DMATERIAL));
  559.     bmat.dwSize = sizeof(D3DMATERIAL);
  560.     bmat.dwRampSize = 1;
  561.     lpbmat->lpVtbl->SetMaterial(lpbmat, &bmat);
  562.     lpbmat->lpVtbl->GetHandle(lpbmat, lpDev, &hbmat);
  563.     lpView->lpVtbl->SetBackground(lpView, hbmat);
  564.     /*
  565.      * Set the view, projection and world matricies in an execute buffer
  566.      */
  567.     MAKE_MATRIX(lpDev, hView, view);
  568.     MAKE_MATRIX(lpDev, hProj, proj);
  569.     MAKE_MATRIX(lpDev, hWorld, world);
  570.     /*
  571.      * Create an execute buffer
  572.      */
  573.     size = 0;
  574.     size += sizeof(D3DINSTRUCTION) * 3;
  575.     size += sizeof(D3DSTATE) * 4;
  576.     memset(&debDesc, 0, sizeof(D3DEXECUTEBUFFERDESC));
  577.     debDesc.dwSize = sizeof(D3DEXECUTEBUFFERDESC);
  578.     debDesc.dwFlags = D3DDEB_BUFSIZE;
  579.     debDesc.dwBufferSize = size;
  580.     if (lpDev->lpVtbl->CreateExecuteBuffer(lpDev, &debDesc, &lpD3DExCmdBuf,
  581.                                            NULL) != D3D_OK)
  582.                                                return FALSE;
  583.     if (lpD3DExCmdBuf->lpVtbl->Lock(lpD3DExCmdBuf, &debDesc) != D3D_OK)
  584.         return FALSE;
  585.     lpBufStart = debDesc.lpData;
  586.     memset(lpBufStart, 0, size);
  587.     lpPointer = lpBufStart;
  588.     /*
  589.      * Fill the execute buffer with instructions
  590.      */
  591.     lpInsStart = lpPointer;
  592.     OP_STATE_TRANSFORM(3, lpPointer);
  593.         STATE_DATA(D3DTRANSFORMSTATE_WORLD, hWorld, lpPointer);
  594.         STATE_DATA(D3DTRANSFORMSTATE_VIEW, hView, lpPointer);
  595.         STATE_DATA(D3DTRANSFORMSTATE_PROJECTION, hProj, lpPointer);
  596.     OP_STATE_LIGHT(1, lpPointer);
  597.         STATE_DATA(D3DLIGHTSTATE_AMBIENT, RGBA_MAKE(40, 40, 40, 40), lpPointer);
  598.     OP_EXIT(lpPointer);
  599.     /*
  600.      * Setup the execute data describing the buffer
  601.      */
  602.     lpD3DExCmdBuf->lpVtbl->Unlock(lpD3DExCmdBuf);
  603.     memset(&d3dExData, 0, sizeof(D3DEXECUTEDATA));
  604.     d3dExData.dwSize = sizeof(D3DEXECUTEDATA);
  605.     d3dExData.dwInstructionOffset = (ULONG) 0;
  606.     d3dExData.dwInstructionLength = (ULONG) ((char *)lpPointer - (char*)lpInsStart);
  607.     lpD3DExCmdBuf->lpVtbl->SetExecuteData(lpD3DExCmdBuf, &d3dExData);
  608.     lpDev->lpVtbl->BeginScene(lpDev);
  609.     lpDev->lpVtbl->Execute(lpDev, lpD3DExCmdBuf, lpView, D3DEXECUTE_UNCLIPPED);
  610.     lpDev->lpVtbl->EndScene(lpDev);
  611.     /*
  612.      * We are done with the command buffer.
  613.      */
  614.     lpD3DExCmdBuf->lpVtbl->Release(lpD3DExCmdBuf);
  615.     /*
  616.      * Setup materials and lights
  617.      */
  618.     tube.hTex = TextureHandle[1];
  619.     if (lpD3D->lpVtbl->CreateMaterial(lpD3D, &lpmat, NULL) != D3D_OK)
  620.         return FALSE;
  621.     memset(&mat, 0, sizeof(D3DMATERIAL));
  622.     mat.dwSize = sizeof(D3DMATERIAL);
  623.     mat.diffuse.r = (D3DVALUE)1.0;
  624.     mat.diffuse.g = (D3DVALUE)1.0;
  625.     mat.diffuse.b = (D3DVALUE)1.0;
  626.     mat.diffuse.a = (D3DVALUE)1.0;
  627.     mat.ambient.r = (D3DVALUE)1.0;
  628.     mat.ambient.g = (D3DVALUE)1.0;
  629.     mat.ambient.b = (D3DVALUE)1.0;
  630.     mat.specular.r = (D3DVALUE)1.0;
  631.     mat.specular.g = (D3DVALUE)1.0;
  632.     mat.specular.b = (D3DVALUE)1.0;
  633.     mat.power = (float)20.0;
  634.     mat.dwRampSize = 16;
  635.     mat.hTexture = tube.hTex;
  636.     lpmat->lpVtbl->SetMaterial(lpmat, &mat);
  637.     lpmat->lpVtbl->GetHandle(lpmat, lpDev, &tube.hMat);
  638.     memset(&tube.light, 0, sizeof(D3DLIGHT));
  639.     tube.light.dwSize = sizeof(D3DLIGHT);
  640.     tube.light.dltType = D3DLIGHT_POINT;
  641.     tube.light.dvPosition.x = tube.cameraP.x;
  642.     tube.light.dvPosition.y = tube.cameraP.y;
  643.     tube.light.dvPosition.z = tube.cameraP.z;
  644.     tube.light.dcvColor.r = D3DVAL(0.9);
  645.     tube.light.dcvColor.g = D3DVAL(0.9);
  646.     tube.light.dcvColor.b = D3DVAL(0.9);
  647.     tube.light.dvAttenuation0 = (float)0.0;
  648.     tube.light.dvAttenuation1 = (float)0.0;
  649.     tube.light.dvAttenuation2 = (float)0.05;
  650.     if (lpD3D->lpVtbl->CreateLight(lpD3D, &tube.lpD3DLight, NULL)!=D3D_OK)
  651.         return FALSE;
  652.     if (tube.lpD3DLight->lpVtbl->SetLight(tube.lpD3DLight, &tube.light)
  653.         !=D3D_OK)
  654.         return FALSE;
  655.     if (lpView->lpVtbl->AddLight(lpView, tube.lpD3DLight) != D3D_OK)
  656.         return FALSE;
  657.  
  658.     /*
  659.      * Create an execute buffer
  660.      */
  661.     size = sizeof(D3DVERTEX) * NUM_V;
  662.     size += sizeof(D3DPROCESSVERTICES);
  663.     size += sizeof(D3DINSTRUCTION) * 6;
  664.     size += sizeof(D3DSTATE) * 4;
  665.     size += sizeof(D3DTRIANGLE) * NUM_TRI;
  666.     memset(&debDesc, 0, sizeof(D3DEXECUTEBUFFERDESC));
  667.     debDesc.dwSize = sizeof(D3DEXECUTEBUFFERDESC);
  668.     debDesc.dwFlags = D3DDEB_BUFSIZE;
  669.     debDesc.dwBufferSize = size;
  670.     if (lpDev->lpVtbl->CreateExecuteBuffer(lpDev, &debDesc, &lpD3DExBuf,
  671.                                            NULL) != D3D_OK)
  672.         return FALSE;
  673.     /*
  674.      * lock it so it can be filled
  675.      */
  676.     if (lpD3DExBuf->lpVtbl->Lock(lpD3DExBuf, &debDesc) != D3D_OK)
  677.         return FALSE;
  678.     lpBufStart = debDesc.lpData;
  679.     memset(lpBufStart, 0, size);
  680.     lpPointer = lpBufStart;
  681.     VERTEX_DATA(tube.lpV, NUM_V, lpPointer);
  682.     /*
  683.      * Save the location of the first instruction and add instructions to
  684.      * execute buffer.
  685.      */
  686.     lpInsStart = lpPointer;
  687.     OP_STATE_LIGHT(1, lpPointer);
  688.         STATE_DATA(D3DLIGHTSTATE_MATERIAL, tube.hMat, lpPointer);
  689.     OP_PROCESS_VERTICES(1, lpPointer);
  690.         PROCESSVERTICES_DATA(D3DPROCESSVERTICES_TRANSFORMLIGHT, 0, NUM_V, lpPointer);
  691.     OP_STATE_RENDER(3, lpPointer);
  692.         STATE_DATA(D3DRENDERSTATE_TEXTUREHANDLE, tube.hTex, lpPointer);
  693.         STATE_DATA(D3DRENDERSTATE_WRAPU, TRUE, lpPointer);
  694.         STATE_DATA(D3DRENDERSTATE_WRAPV, TRUE, lpPointer);
  695.     /*
  696.      * Make sure that the triangle data (not OP) will be QWORD aligned
  697.      */
  698.     if (QWORD_ALIGNED(lpPointer)) {
  699.         OP_NOP(lpPointer);
  700.     }
  701.     OP_TRIANGLE_LIST(NUM_TRI, lpPointer);
  702.         tube.TriOffset = (char *)lpPointer - (char *)lpBufStart;
  703.         TRIANGLE_LIST_DATA(tube.lpTri, NUM_TRI, lpPointer);
  704.     OP_EXIT(lpPointer);
  705.     /*
  706.      * Setup the execute data describing the buffer
  707.      */
  708.     lpD3DExBuf->lpVtbl->Unlock(lpD3DExBuf);
  709.     memset(&d3dExData, 0, sizeof(D3DEXECUTEDATA));
  710.     d3dExData.dwSize = sizeof(D3DEXECUTEDATA);
  711.     d3dExData.dwVertexCount = NUM_V;
  712.     d3dExData.dwInstructionOffset = (ULONG) ((char *)lpInsStart - (char *)lpBufStart);
  713.     d3dExData.dwInstructionLength = (ULONG) ((char *)lpPointer - (char *)lpInsStart);
  714.     lpD3DExBuf->lpVtbl->SetExecuteData(lpD3DExBuf, &d3dExData);
  715.  
  716.     return TRUE;
  717. }
  718.