home *** CD-ROM | disk | FTP | other *** search
/ Tricks of the Windows Gam…ming Gurus (2nd Edition) / Disc2.iso / msdn_vcb / samples / vc98 / sdk / graphics / directx / boids / boids.cpp next >
Encoding:
C/C++ Source or Header  |  1997-07-15  |  29.2 KB  |  980 lines

  1. /*
  2. **----------------------------------------------------------------------------
  3. **
  4. **  File:       boids.cpp
  5. **  Purpose:    
  6. **  Notes:
  7. **
  8. **    Copyright (C) 1995 - 1997 Microsoft Corporation. All Rights Reserved.
  9. **----------------------------------------------------------------------------
  10. */
  11.  
  12. /*
  13. **----------------------------------------------------------------------------
  14. ** Includes
  15. **----------------------------------------------------------------------------
  16. */
  17.  
  18. #include <math.h>
  19. #include <time.h>
  20.  
  21. #include "D3DScene.h"
  22. #include "Debug.h"
  23. #include "D3DWin.h"
  24. #include "d3dutils.h"
  25. #include "d3dtex.h"
  26. #include "boids.h"
  27.  
  28.  
  29. /*
  30. **----------------------------------------------------------------------------
  31. ** Defines
  32. **----------------------------------------------------------------------------
  33. */
  34.  
  35. #define NUM_BOIDS    13
  36.  
  37. // ground pattern
  38. D3DVECTOR       grid_color(0.0f, 0.3f, 0.5f);
  39. D3DLVERTEX    pattern1[24];
  40. D3DLVERTEX    pattern2[8];
  41. WORD        pat1_indices[25] = { 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 
  42.                                 13, 14, 15, 16, 17, 18, 19, 20, 21, 22, 23, 0 };
  43. WORD        pat2_indices[9] = { 0, 1, 2, 3, 4, 5, 6, 7, 0 };
  44.  
  45. #define MESH_SIZE    8
  46. #define SPHERE_VERTICES    (2+MESH_SIZE*MESH_SIZE*2)
  47. #define SPHERE_INDICES    ((MESH_SIZE*4 + MESH_SIZE*4*(MESH_SIZE-1))*3)
  48.  
  49.     
  50. /*
  51. **----------------------------------------------------------------------------
  52. ** Local Variables
  53. **----------------------------------------------------------------------------
  54. */
  55.  
  56. D3DVERTEX    sphere[SPHERE_VERTICES];
  57. WORD        sphere_indices[SPHERE_INDICES];
  58.  
  59. Flock        flock;
  60.  
  61. D3DVERTEX    boid_vertices[16];
  62. WORD        boid_indices[30];
  63.  
  64. D3DMATRIX    proj, view, world;
  65.  
  66. Light        *lpLight1,
  67.             *lpLight2;
  68.  
  69. Material    *lpBackgroundMat,
  70.             *lpGridMat,
  71.             *lpSphereMat,
  72.             *lpBoidMat;
  73.  
  74. D3DTexture    SphereTex;
  75.  
  76. /*
  77. **----------------------------------------------------------------------------
  78. ** Function definitions
  79. **----------------------------------------------------------------------------
  80. */
  81.  
  82. /*
  83. **----------------------------------------------------------------------------
  84. ** Name:        DrawBoid
  85. ** Purpose:
  86. **----------------------------------------------------------------------------
  87. */
  88.  
  89. HRESULT
  90. Drawboid(LPDIRECT3DDEVICE2 lpDev)
  91. {
  92.     HRESULT hResult;
  93.  
  94.         hResult = lpDev->DrawIndexedPrimitive(D3DPT_TRIANGLELIST, D3DVT_VERTEX, (LPVOID)boid_vertices, 16, boid_indices, 30, D3DDP_WAIT);
  95.  
  96.     return hResult;
  97. } // End DrawBoid
  98.  
  99.  
  100. /*
  101. **----------------------------------------------------------------------------
  102. ** Name:        DrawSphere
  103. ** Purpose:
  104. **----------------------------------------------------------------------------
  105. */
  106.  
  107. HRESULT
  108. DrawSphere(LPDIRECT3DDEVICE2 lpDev)
  109. {
  110.     HRESULT hResult;
  111.  
  112.         hResult = lpDev->DrawIndexedPrimitive(D3DPT_TRIANGLELIST, D3DVT_VERTEX, (LPVOID)sphere, SPHERE_VERTICES, sphere_indices, SPHERE_INDICES, D3DDP_WAIT);
  113.     if (hResult != D3D_OK)
  114.         return hResult;
  115.  
  116.     return D3D_OK;
  117. } // End DrawSphere
  118.  
  119.  
  120. HRESULT
  121. DrawPattern(LPDIRECT3DDEVICE2 lpDev)
  122. {
  123.     HRESULT hResult;
  124.  
  125.     for (int dx= -2; dx<3; dx++) {
  126.         for (int dz= -2; dz<3; dz++) {
  127.             D3DVECTOR    offset(dx*80.0f, 0.0f, dz*80.0f);
  128.  
  129.             world = TranslateMatrix(offset);
  130.             hResult = lpDev->SetTransform(D3DTRANSFORMSTATE_WORLD, &world);
  131.             if (hResult != D3D_OK) {
  132.                 REPORTERR(hResult);
  133.                 return hResult;
  134.             }
  135.                         hResult = lpDev->DrawIndexedPrimitive(D3DPT_LINESTRIP, D3DVT_LVERTEX, (LPVOID)pattern1, 24, pat1_indices, 25, D3DDP_WAIT);
  136.             if (hResult != D3D_OK) {
  137.                 REPORTERR(hResult);
  138.                 return hResult;
  139.             }
  140.                         hResult = lpDev->DrawIndexedPrimitive(D3DPT_LINESTRIP, D3DVT_LVERTEX, (LPVOID)pattern2, 8, pat2_indices, 9, D3DDP_WAIT);
  141.             if (hResult != D3D_OK) {
  142.                 REPORTERR(hResult);
  143.                 return hResult;
  144.             }
  145.         }
  146.     }
  147.  
  148.     return D3D_OK;
  149. }    // end of DrawPattern()
  150.  
  151.  
  152. /*
  153. **----------------------------------------------------------------------------
  154. ** D3DScene Methods
  155. **----------------------------------------------------------------------------
  156. */
  157.  
  158. /*
  159. **----------------------------------------------------------------------------
  160. ** Name:        D3DScene::D3DScene
  161. ** Purpose:        Default Constructor
  162. **----------------------------------------------------------------------------
  163. */
  164.  
  165. D3DScene::D3DScene(void)
  166. {
  167.     lpd3dWindow = NULL;
  168. } // End D3DScene::D3DScene
  169.  
  170.  
  171.   
  172. /*
  173. **----------------------------------------------------------------------------
  174. ** Name:        D3DScene::~D3DScene
  175. ** Purpose:        Default Destructor
  176. **----------------------------------------------------------------------------
  177. */
  178.  
  179. D3DScene::~D3DScene(void)
  180. {
  181.     Fini();
  182.     lpd3dWindow = NULL;
  183. } // End D3DScene::~D3DScene
  184.  
  185.  
  186.  
  187. /*
  188. **----------------------------------------------------------------------------
  189. ** Name:        D3DScene::Init
  190. ** Purpose:        Do all static intialization here
  191. ** Notes:        This means all Scene data that isn't dependent on the
  192. **                D3D interface, viewport, or D3D device in some manner
  193. **----------------------------------------------------------------------------
  194. */
  195.  
  196. HRESULT
  197. D3DScene::Init(LPD3DWindow lpd3dWin)
  198. {
  199.     HRESULT hResult;
  200.     int i, j;
  201.  
  202.     // Check Parameters
  203.     if (! lpd3dWin)    {
  204.         // Need a valid D3D Window object
  205.         hResult = APPERR_INVALIDPARAMS;
  206.         REPORTERR(hResult);
  207.         return hResult;
  208.     }
  209.  
  210.     // Save assocation with D3D Window
  211.     lpd3dWindow = lpd3dWin;
  212.  
  213.     // generate the boid data
  214.  
  215.     // top
  216.     boid_vertices[ 0] = D3DVERTEX(D3DVECTOR(0.0f, 0.0f, 10.0f), Normalize(D3DVECTOR(0.2f, 1.0f, 0.0f)), 0.0f, 0.5f);
  217.     boid_vertices[ 1] = D3DVERTEX(D3DVECTOR(10.0f, 0.0f, -10.0f), Normalize(D3DVECTOR(0.1f, 1.0f, 0.0f)), 0.5f, 1.0f);
  218.     boid_vertices[ 2] = D3DVERTEX(D3DVECTOR(3.0f, 3.0f, -7.0f), Normalize(D3DVECTOR(0.0f, 1.0f, 0.0f)), 0.425f, 0.575f);
  219.     boid_vertices[ 3] = D3DVERTEX(D3DVECTOR(-3.0f, 3.0f, -7.0f), Normalize(D3DVECTOR(-0.1f, 1.0f, 0.0f)), 0.425f, 0.425f);
  220.     boid_vertices[ 4] = D3DVERTEX(D3DVECTOR(-10.0f, 0.0f, -10.0f), Normalize(D3DVECTOR(-0.2f, 1.0f, 0.0f)), 0.5f, 0.0f);
  221.  
  222.     //bottom
  223.     boid_vertices[ 5] = D3DVERTEX(D3DVECTOR(0.0f, 0.0f, 10.0f), Normalize(D3DVECTOR(0.2f, -1.0f, 0.0f)), 1.0f, 0.5f);
  224.     boid_vertices[ 6] = D3DVERTEX(D3DVECTOR(10.0f, 0.0f, -10.0f), Normalize(D3DVECTOR(0.1f, -1.0f, 0.0f)), 0.5f, 1.0f);
  225.     boid_vertices[ 7] = D3DVERTEX(D3DVECTOR(3.0f, -3.0f, -7.0f), Normalize(D3DVECTOR(0.0f, -1.0f, 0.0f)), 0.575f, 0.575f);
  226.     boid_vertices[ 8] = D3DVERTEX(D3DVECTOR(-3.0f, -3.0f, -7.0f), Normalize(D3DVECTOR(-0.1f, -1.0f, 0.0f)), 0.575f, 0.425f);
  227.     boid_vertices[ 9] = D3DVERTEX(D3DVECTOR(-10.0f, 0.0f, -10.0f), Normalize(D3DVECTOR(-0.2f, -1.0f, 0.0f)), 0.5f, 0.0f);
  228.  
  229.     // rear
  230.     boid_vertices[10] = D3DVERTEX(D3DVECTOR(10.0f, 0.0f, -10.0f), Normalize(D3DVECTOR(-0.4f, 0.0f, -1.0f)), 0.5f, 1.0f);
  231.     boid_vertices[11] = D3DVERTEX(D3DVECTOR(3.0f, 3.0f, -7.0f), Normalize(D3DVECTOR(-0.2f, 0.0f, -1.0f)), 0.425f, 0.575f);
  232.     boid_vertices[12] = D3DVERTEX(D3DVECTOR(-3.0f, 3.0f, -7.0f), Normalize(D3DVECTOR(0.2f, 0.0f, -1.0f)), 0.425f, 0.425f);
  233.     boid_vertices[13] = D3DVERTEX(D3DVECTOR(-10.0f, 0.0f, -10.0f), Normalize(D3DVECTOR(0.4f, 0.0f, -1.0f)), 0.5f, 0.0f);
  234.     boid_vertices[14] = D3DVERTEX(D3DVECTOR(-3.0f, -3.0f, -7.0f), Normalize(D3DVECTOR(0.2f, 0.0f, -1.0f)), 0.575f, 0.425f);
  235.     boid_vertices[15] = D3DVERTEX(D3DVECTOR(3.0f, -3.0f, -7.0f), Normalize(D3DVECTOR(-0.2f, 0.0f, -1.0f)), 0.575f, 0.575f);
  236.  
  237.     // top
  238.     boid_indices[ 0] = 0;
  239.     boid_indices[ 1] = 1;
  240.     boid_indices[ 2] = 2;
  241.     boid_indices[ 3] = 0;
  242.     boid_indices[ 4] = 2;
  243.     boid_indices[ 5] = 3;
  244.     boid_indices[ 6] = 0;
  245.     boid_indices[ 7] = 3;
  246.     boid_indices[ 8] = 4;
  247.  
  248.     // bottom
  249.     boid_indices[ 9] = 5;
  250.     boid_indices[10] = 7;
  251.     boid_indices[11] = 6;
  252.     boid_indices[12] = 5;
  253.     boid_indices[13] = 8;
  254.     boid_indices[14] = 7;
  255.     boid_indices[15] = 5;
  256.     boid_indices[16] = 9;
  257.     boid_indices[17] = 8;
  258.  
  259.     // rear
  260.     boid_indices[18] = 10;
  261.     boid_indices[19] = 15;
  262.     boid_indices[20] = 11;
  263.     boid_indices[21] = 11;
  264.     boid_indices[22] = 15;
  265.     boid_indices[23] = 12;
  266.     boid_indices[24] = 12;
  267.     boid_indices[25] = 15;
  268.     boid_indices[26] = 14;
  269.     boid_indices[27] = 12;
  270.     boid_indices[28] = 14;
  271.     boid_indices[29] = 13;
  272.  
  273.     // scale the boid to be unit length
  274.     for (i=0; i<16; i++) {
  275.         boid_vertices[i].x /= 20.0f;
  276.         boid_vertices[i].y /= 20.0f;
  277.         boid_vertices[i].z /= 20.0f;
  278.     }
  279.  
  280.     // seed the random number generator
  281.     srand(time(NULL));
  282.  
  283.     // allocate the flock
  284.     if (!(flock.boids = (Boid *)malloc(NUM_BOIDS * sizeof(Boid)))) {
  285.         return FALSE;
  286.     }
  287.     if (!(flock.dist = (float **)malloc(NUM_BOIDS * sizeof(float *)))) {
  288.         return FALSE;
  289.     }
  290.  
  291.     flock.num_boids = NUM_BOIDS;
  292.     flock.goal = D3DVECTOR(0.0f, 0.0f, 0.0f);
  293.  
  294.     for (i=0; i<flock.num_boids; i++) {
  295.         flock.boids[i].loc = D3DVECTOR(100.0f*(rnd()-rnd()), 10.0f*rnd(), 100.0f*(rnd()-rnd()));
  296.         flock.boids[i].dir = Normalize(D3DVECTOR(rnd()-rnd(), rnd()-rnd(), rnd()-rnd()));
  297.         flock.boids[i].yaw = flock.boids[i].pitch = flock.boids[i].roll = flock.boids[i].dyaw = 0.0f;
  298.         flock.boids[i].speed = 0.1f;
  299.         flock.boids[i].color = D3DVECTOR(rnd(), rnd(), rnd());
  300.         flock.boids[i].color -= D3DVECTOR(Min(flock.boids[i].color));
  301.         flock.boids[i].color /= Max(flock.boids[i].color);
  302.         if (!(flock.dist[i] = (float *)malloc(NUM_BOIDS * sizeof(float)))) {
  303.             return FALSE;
  304.         }
  305.     }
  306.  
  307.     flock.num_obs = 4;
  308.     if (!(flock.obs = (Obstacle *)malloc(flock.num_obs * sizeof(Obstacle)))) {
  309.         return FALSE;
  310.     }
  311.     flock.obs[0].loc = D3DVECTOR(100.0f, 10.0f, 0.0f);
  312.     flock.obs[1].loc = D3DVECTOR(-100.0f, 10.0f, 0.0f);
  313.     flock.obs[2].loc = D3DVECTOR(0.0f, 10.0f, 100.0f);
  314.     flock.obs[3].loc = D3DVECTOR(0.0f, 10.0f, -100.0f);
  315.     flock.obs[0].radius = 3.0f;
  316.     flock.obs[1].radius = 3.0f;
  317.     flock.obs[2].radius = 3.0f;
  318.     flock.obs[3].radius = 3.0f;
  319.  
  320.     D3DCOLOR    diffuse = D3DRGB(grid_color[0], grid_color[1], grid_color[2]),
  321.                 specular = D3DRGB(0.0, 0.0, 0.0);
  322.  
  323.     pattern1[ 0] = D3DLVERTEX(D3DVECTOR(-25.0f, 0.0f, 35.0f), diffuse, specular, 0.0f, 0.0f);
  324.     pattern1[ 1] = D3DLVERTEX(D3DVECTOR(-15.0f, 0.0f, 35.0f), diffuse, specular, 0.0f, 0.0f);
  325.     pattern1[ 2] = D3DLVERTEX(D3DVECTOR(-5.0f, 0.0f, 25.0f), diffuse, specular, 0.0f, 0.0f);
  326.     pattern1[ 3] = D3DLVERTEX(D3DVECTOR(5.0f, 0.0f, 25.0f), diffuse, specular, 0.0f, 0.0f);
  327.     pattern1[ 4] = D3DLVERTEX(D3DVECTOR(15.0f, 0.0f, 35.0f), diffuse, specular, 0.0f, 0.0f);
  328.     pattern1[ 5] = D3DLVERTEX(D3DVECTOR(25.0f, 0.0f, 35.0f), diffuse, specular, 0.0f, 0.0f);
  329.     pattern1[ 6] = D3DLVERTEX(D3DVECTOR(35.0f, 0.0f, 25.0f), diffuse, specular, 0.0f, 0.0f);
  330.     pattern1[ 7] = D3DLVERTEX(D3DVECTOR(35.0f, 0.0f, 15.0f), diffuse, specular, 0.0f, 0.0f);
  331.     pattern1[ 8] = D3DLVERTEX(D3DVECTOR(25.0f, 0.0f, 5.0f), diffuse, specular, 0.0f, 0.0f);
  332.     pattern1[ 9] = D3DLVERTEX(D3DVECTOR(25.0f, 0.0f, -5.0f), diffuse, specular, 0.0f, 0.0f);
  333.     pattern1[10] = D3DLVERTEX(D3DVECTOR(35.0f, 0.0f, -15.0f), diffuse, specular, 0.0f, 0.0f);
  334.     pattern1[11] = D3DLVERTEX(D3DVECTOR(35.0f, 0.0f, -25.0f), diffuse, specular, 0.0f, 0.0f);
  335.     pattern1[12] = D3DLVERTEX(D3DVECTOR(25.0f, 0.0f, -35.0f), diffuse, specular, 0.0f, 0.0f);
  336.     pattern1[13] = D3DLVERTEX(D3DVECTOR(15.0f, 0.0f,-35.0f), diffuse, specular, 0.0f, 0.0f);
  337.     pattern1[14] = D3DLVERTEX(D3DVECTOR(5.0f, 0.0f, -25.0f), diffuse, specular, 0.0f, 0.0f);
  338.     pattern1[15] = D3DLVERTEX(D3DVECTOR(-5.0f, 0.0f, -25.0f), diffuse, specular, 0.0f, 0.0f);
  339.     pattern1[16] = D3DLVERTEX(D3DVECTOR(-15.0f, 0.0f,-35.0f), diffuse, specular, 0.0f, 0.0f);
  340.     pattern1[17] = D3DLVERTEX(D3DVECTOR(-25.0f, 0.0f,-35.0f), diffuse, specular, 0.0f, 0.0f);
  341.     pattern1[18] = D3DLVERTEX(D3DVECTOR(-35.0f, 0.0f, -25.0f), diffuse, specular, 0.0f, 0.0f);
  342.     pattern1[19] = D3DLVERTEX(D3DVECTOR(-35.0f, 0.0f, -15.0f), diffuse, specular, 0.0f, 0.0f);
  343.     pattern1[20] = D3DLVERTEX(D3DVECTOR(-25.0f, 0.0f, -5.0f), diffuse, specular, 0.0f, 0.0f);
  344.     pattern1[21] = D3DLVERTEX(D3DVECTOR(-25.0f, 0.0f, 5.0f), diffuse, specular, 0.0f, 0.0f);
  345.     pattern1[22] = D3DLVERTEX(D3DVECTOR(-35.0f, 0.0f, 15.0f), diffuse, specular, 0.0f, 0.0f);
  346.     pattern1[23] = D3DLVERTEX(D3DVECTOR(-35.0f, 0.0f, 25.0f), diffuse, specular, 0.0f, 0.0f);
  347.  
  348.     pattern2[ 0] = D3DLVERTEX(D3DVECTOR(-5.0f, 0.0f, 15.0f), diffuse, specular, 0.0f, 0.0f);
  349.     pattern2[ 1] = D3DLVERTEX(D3DVECTOR(5.0f, 0.0f, 15.0f), diffuse, specular, 0.0f, 0.0f);
  350.     pattern2[ 2] = D3DLVERTEX(D3DVECTOR(15.0f, 0.0f, 5.0f), diffuse, specular, 0.0f, 0.0f);
  351.     pattern2[ 3] = D3DLVERTEX(D3DVECTOR(15.0f, 0.0f, -5.0f), diffuse, specular, 0.0f, 0.0f);
  352.     pattern2[ 4] = D3DLVERTEX(D3DVECTOR(5.0f, 0.0f, -15.0f), diffuse, specular, 0.0f, 0.0f);
  353.     pattern2[ 5] = D3DLVERTEX(D3DVECTOR(-5.0f, 0.0f, -15.0f), diffuse, specular, 0.0f, 0.0f);
  354.     pattern2[ 6] = D3DLVERTEX(D3DVECTOR(-15.0f, 0.0f, -5.0f), diffuse, specular, 0.0f, 0.0f);
  355.     pattern2[ 7] = D3DLVERTEX(D3DVECTOR(-15.0f, 0.0f, 5.0f), diffuse, specular, 0.0f, 0.0f);
  356.  
  357.     float   dj = pi/(MESH_SIZE+1.0f);
  358.     float    di = pi/MESH_SIZE;
  359.  
  360.     // generate the sphere data, note the random texture coords
  361.  
  362.     // vertices 0 and 1 are the north and south poles
  363.     sphere[0] = D3DVERTEX(D3DVECTOR(0.0f, 1.0f, 0.0f), Normalize(D3DVECTOR(0.0f, 1.0f, 0.0f)), 0.0f, 0.0f);
  364.     sphere[1] = D3DVERTEX(D3DVECTOR(0.0f, -1.0f, 0.0f), Normalize(D3DVECTOR(0.0f, -1.0f, 0.0f)), 1.0f, 1.0f);
  365.  
  366.     for (j=0; j<MESH_SIZE; j++) {
  367.         for (i=0; i<MESH_SIZE*2; i++) {
  368.             D3DVECTOR    p;
  369.             float        u, v;
  370.  
  371.             p.y = (float) cos((j+1) * dj);
  372.             p.x = (float) sin(i * di) * (float) sin((j+1) * dj);
  373.             p.z = (float) cos(i * di) * (float) sin((j+1) * dj);
  374.             u = (float)i/MESH_SIZE;
  375.             if (u>1.0f) 
  376.                 u -= 1.0f;
  377.             u = 1.0f - u;    // flip so texture is not mirrored
  378.             v = (float)j/MESH_SIZE;
  379.             sphere[2+i+j*MESH_SIZE*2] = D3DVERTEX(p, p, u, v);
  380.         }
  381.     }
  382.  
  383.     // now generate the traingle indices
  384.     // strip around north pole first
  385.     for (i=0; i<MESH_SIZE*2; i++) {
  386.         sphere_indices[3*i] = 0;
  387.         sphere_indices[3*i+1] = i+2;
  388.         sphere_indices[3*i+2] = i+3;
  389.         if (i==MESH_SIZE*2-1)
  390.             sphere_indices[3*i+2] = 2;
  391.     }
  392.  
  393.     // now all the middle strips
  394.     int    v;        // vertex offset
  395.     int ind;    // indices offset
  396.     for (j=0; j<MESH_SIZE-1; j++) {
  397.         v = 2+j*MESH_SIZE*2;
  398.         ind = 3*MESH_SIZE*2 + j*6*MESH_SIZE*2;
  399.         for (i=0; i<MESH_SIZE*2; i++) {
  400.             sphere_indices[6*i+ind] = v+i;
  401.             sphere_indices[6*i+2+ind] = v+i+1;
  402.             sphere_indices[6*i+1+ind] = v+i+MESH_SIZE*2;
  403.  
  404.             sphere_indices[6*i+ind+3] = v+i+MESH_SIZE*2;
  405.             sphere_indices[6*i+2+ind+3] = v+i+1;
  406.             sphere_indices[6*i+1+ind+3] = v+i+MESH_SIZE*2+1;
  407.             if (i==MESH_SIZE*2-1) {
  408.                 sphere_indices[6*i+2+ind] = v+i+1-2*MESH_SIZE;
  409.                 sphere_indices[6*i+2+ind+3] = v+i+1-2*MESH_SIZE;
  410.                 sphere_indices[6*i+1+ind+3] = v+i+MESH_SIZE*2+1-2*MESH_SIZE;
  411.             }
  412.         }
  413.     }
  414.  
  415.     // finally strip around south pole
  416.     v = SPHERE_VERTICES-MESH_SIZE*2;
  417.     ind = SPHERE_INDICES-3*MESH_SIZE*2;
  418.     for (i=0; i<MESH_SIZE*2; i++) {
  419.         sphere_indices[3*i+ind] = 1;
  420.         sphere_indices[3*i+1+ind] = v+i+1;
  421.         sphere_indices[3*i+2+ind] = v+i;
  422.         if (i==MESH_SIZE*2-1)
  423.             sphere_indices[3*i+1+ind] = v;
  424.     }
  425.  
  426.     // Success
  427.     return D3D_OK;
  428. } // End D3DScene::Init
  429.  
  430.  
  431.   
  432. /*
  433. **-----------------------------------------------------------------------------
  434. **  Name:       D3DScene::Fini
  435. **  Purpose:    Cleanup scene objects
  436. **-----------------------------------------------------------------------------
  437. */
  438.  
  439. HRESULT D3DScene::Fini(void)
  440. {
  441.     Detach();
  442.     lpd3dWindow = NULL;
  443.  
  444.     // Success
  445.     return D3D_OK;
  446. } // End D3DScene::Fini
  447.  
  448.  
  449.  
  450. /*
  451. **----------------------------------------------------------------------------
  452. ** Name:        D3DScene::Attach
  453. ** Purpose:        Attaching to a new D3DWindow object
  454. ** Notes:        Need to create and attach all Scene objects dependent upon
  455. **                the D3D interface, viewport, and D3D device here.  
  456. **                For Example:  Textures, Materials, Lights, etc.
  457. **----------------------------------------------------------------------------
  458. */
  459.  
  460. HRESULT D3DScene::Attach(void)
  461. {
  462.     HRESULT hResult;
  463.  
  464.     // Check Initialization
  465.     if ((! lpd3dWindow) || (! lpd3dWindow->isValid()))    {
  466.         // Error, not properly initialized
  467.         hResult = APPERR_NOTINITIALIZED;
  468.         REPORTERR(hResult);
  469.         return hResult;
  470.     }
  471.  
  472.     hResult = AttachViewport();
  473.     if (hResult != D3D_OK) {
  474.         return hResult;
  475.     }
  476.  
  477.     // Success
  478.     return D3D_OK;
  479. } // End D3DScene::Attach
  480.  
  481.   
  482.  
  483. /*
  484. **-----------------------------------------------------------------------------
  485. **  Name:       D3DScene::Detach
  486. **  Purpose:    Cleanup all scene objects dependent upon the 
  487. **                D3D Interface, viewport, or D3D device 
  488. **-----------------------------------------------------------------------------
  489. */
  490.  
  491. HRESULT D3DScene::Detach(void)
  492. {
  493.     // Cleanup Viewport
  494.     DetachViewport();
  495.  
  496.     // Success
  497.     return D3D_OK;
  498. } // End D3DScene::Fini
  499.  
  500.  
  501.  
  502.  
  503. /*
  504. **----------------------------------------------------------------------------
  505. ** Name:        D3DScene::Render
  506. ** Purpose:
  507. **----------------------------------------------------------------------------
  508. */
  509.  
  510. HRESULT D3DScene::Render(void)
  511. {
  512.     LPDIRECT3DDEVICE2    lpDev;
  513.     LPDIRECT3DVIEWPORT2 lpView;
  514.     RECT                rSrc;
  515.     LPD3DRECT            lpExtent = NULL;
  516.     int                    i;
  517.     HRESULT                hResult;
  518.     D3DCLIPSTATUS        status;
  519.     D3DRECT                d3dRect;
  520.     D3DVECTOR            offset;
  521.     static D3DVECTOR    from(0.0f, 30.0f, 100.0f);
  522.     static D3DVECTOR    at(0.0f, 0.0f, 50.0f);
  523.     static D3DVECTOR    up(0.0f, 1.0f, 0.0f);
  524.     static float        tic = -200.0f * rnd();
  525.  
  526.     // Check Initialization
  527.     if ((! lpd3dWindow) || (! lpd3dWindow->isValid ()))    {
  528.         // Error, not properly initialized
  529.         hResult = APPERR_NOTINITIALIZED;
  530.         REPORTERR(hResult);
  531.         return hResult;
  532.     }
  533.  
  534.     lpDev    = lpd3dWindow->lpd3dDevice;
  535.     lpView  = lpd3dWindow->lpd3dViewport;
  536.     lpd3dWindow->GetSurfaceRect(rSrc);
  537.  
  538.     // Double Check
  539. #ifdef DEBUG
  540.     if ((! lpDev) || (! lpView))
  541.     {
  542.         // Error, not initialized properly
  543.         hResult = APPERR_NOTINITIALIZED;
  544.         REPORTERR(hResult);
  545.         return hResult;
  546.     }
  547. #endif
  548.     
  549.     
  550.     //
  551.     // Clear both back and z-buffer.
  552.     //
  553.     // NOTE: Its safe to specify the z-buffer clear flag even if we
  554.     // don't have an attached z-buffer. Direct3D will simply discard
  555.     // the flag if no z-buffer is being used.
  556.     //
  557.     // NOTE: For maximum efficiency we only want to clear those
  558.     // regions of the device surface and z-buffer which we actually
  559.     // rendered to in the last frame. This is the purpose of the
  560.     // array of rectangles and count passed to this function. It is
  561.     // possible to query Direct3D for the regions of the device
  562.     // surface that were rendered to by that execute. The application
  563.     // can then accumulate those rectangles and clear only those
  564.     // regions. However this is a very simple sample and so, for
  565.     // simplicity, we will just clear the entire device surface and
  566.     // z-buffer. Probably not something you wan't to do in a real
  567.     // application.
  568.     ///
  569.     d3dRect.lX1 = rSrc.left;
  570.     d3dRect.lX2 = rSrc.right;
  571.     d3dRect.lY1 = rSrc.top;
  572.     d3dRect.lY2 = rSrc.bottom;
  573.     hResult = lpView->Clear(1UL, &d3dRect,
  574.                              D3DCLEAR_TARGET | D3DCLEAR_ZBUFFER);
  575.     if (hResult != D3D_OK) {
  576.         REPORTERR(hResult);
  577.         return hResult;
  578.     }    
  579.  
  580.     
  581.     if (lpExtent) {
  582.         // Calculate exclude region
  583.         status.dwFlags = D3DCLIPSTATUS_EXTENTS2;
  584.         status.dwStatus = 0;
  585.         status.minx = (float)lpExtent->x1;
  586.         status.maxx = (float)lpExtent->x2;
  587.         status.miny = (float)lpExtent->y1;
  588.         status.maxy = (float)lpExtent->y2;
  589.         status.minz = 0.0f;
  590.         status.maxz = 0.0f;
  591.  
  592.         hResult = lpDev->SetClipStatus(&status);
  593.         if (hResult != D3D_OK) {
  594.             REPORTERR(hResult);
  595.             goto lblCLEANUP;
  596.         }
  597.     }
  598.  
  599.     // Begin Scene
  600.     // Note:  This is complicated by the need to
  601.     //          check for lost surfaces and restore
  602.     hResult = lpDev->BeginScene();
  603.     if (hResult != D3D_OK) {
  604.         while (hResult == DDERR_SURFACELOST) {
  605.             // Restore surface
  606.             while (hResult == DDERR_SURFACELOST) {
  607.                 hResult = lpd3dWindow->Restore();
  608.             }
  609.  
  610.             // Try BeginScene again
  611.             hResult = lpDev->BeginScene();
  612.         }
  613.  
  614.         if (hResult != D3D_OK) {
  615.             REPORTERR(hResult);
  616.             return hResult;
  617.         }
  618.     }
  619.  
  620.     // Turn off specular highlights
  621.         hResult = lpDev->SetRenderState(D3DRENDERSTATE_SPECULARENABLE, FALSE);
  622.     if (hResult != D3D_OK) {
  623.         REPORTERR(hResult);
  624.         goto lblCLEANUP;
  625.     }
  626.  
  627.     // Turn on Z-buffering
  628.     hResult = lpDev->SetRenderState(D3DRENDERSTATE_ZENABLE, 1);
  629.     if (hResult != D3D_OK) {
  630.         REPORTERR(hResult);
  631.         goto lblCLEANUP;
  632.     }
  633.  
  634.     // null out the texture handle
  635.     hResult = lpDev->SetRenderState(D3DRENDERSTATE_TEXTUREHANDLE, 0);
  636.     if (hResult != D3D_OK) {
  637.         REPORTERR(hResult);
  638.         goto lblCLEANUP;
  639.     }
  640.  
  641.     // turn on dithering
  642.     hResult = lpDev->SetRenderState(D3DRENDERSTATE_DITHERENABLE, TRUE);
  643.     if (hResult != D3D_OK) {
  644.         REPORTERR(hResult);
  645.         goto lblCLEANUP;
  646.     }
  647.  
  648.     // turn on some ambient light
  649.     hResult = lpDev->SetLightState(D3DLIGHTSTATE_AMBIENT, RGBA_MAKE(10, 10, 10, 10));
  650.     if (hResult != D3D_OK) {
  651.         REPORTERR(hResult);
  652.         goto lblCLEANUP;
  653.     }
  654.  
  655.     // set the view and projection matrices
  656.  
  657.     tic += 0.01f;
  658.  
  659.     view = ViewMatrix(from, at, up);
  660.     proj = ProjectionMatrix(1.0f, 500.0f, pi/4.0f);
  661.  
  662.     hResult = lpDev->SetTransform(D3DTRANSFORMSTATE_VIEW, &view);
  663.     if (hResult != D3D_OK) {
  664.         REPORTERR(hResult);
  665.         goto lblCLEANUP;
  666.     }
  667.  
  668.     hResult = lpDev->SetTransform(D3DTRANSFORMSTATE_PROJECTION, &proj);
  669.     if (hResult != D3D_OK) {
  670.         REPORTERR(hResult);
  671.         goto lblCLEANUP;
  672.     }
  673.  
  674.     // draw ground grid
  675.     lpGridMat->SetAsCurrent(lpDev);
  676.     hResult = DrawPattern(lpDev);
  677.     if (hResult != D3D_OK) {
  678.         REPORTERR(hResult);
  679.         goto lblCLEANUP;
  680.     }
  681.  
  682.  
  683.     UpdateFlock(flock);
  684.  
  685.     at = D3DVECTOR(0.0f);
  686.     // draw the boids
  687.     for (i=0; i<flock.num_boids; i++) {
  688.         D3DVECTOR    step;
  689.  
  690.         // build the world matrix for the boid
  691.         world = MatrixMult(MatrixMult(RotateYMatrix(flock.boids[i].yaw), RotateXMatrix(flock.boids[i].pitch)), RotateZMatrix(flock.boids[i].roll));
  692.  
  693.         // first translate into place, then set orientation, then scale (if needed)
  694.         world = TranslateMatrix(flock.boids[i].loc);
  695.         world = MatrixMult(world, MatrixMult(MatrixMult(RotateYMatrix(flock.boids[i].yaw), 
  696.                             RotateXMatrix(flock.boids[i].pitch)), RotateZMatrix(flock.boids[i].roll)));
  697.  
  698.         // apply the world matrix
  699.         hResult = lpDev->SetTransform(D3DTRANSFORMSTATE_WORLD, &world);
  700.         if (hResult != D3D_OK) {
  701.             REPORTERR(hResult);
  702.             goto lblCLEANUP;
  703.         }
  704.  
  705.         // display the boid
  706.         lpBoidMat->SetDiffuse(flock.boids[i].color);
  707.         lpBoidMat->SetAsCurrent(lpDev);
  708.         hResult = Drawboid(lpDev);
  709.         if (hResult != D3D_OK) {
  710.             REPORTERR(hResult);
  711.             goto lblCLEANUP;
  712.         }
  713.  
  714.         flock.boids[i].dir[0] = world(2, 0);
  715.         flock.boids[i].dir[1] = world(2, 1);
  716.         flock.boids[i].dir[2] = world(2, 2);
  717.  
  718.         flock.boids[i].loc += flock.boids[i].dir * flock.boids[i].speed;
  719.  
  720.         at += flock.boids[i].loc;
  721.     }
  722.     // find the center of the flock and look there for the next frame
  723.     at /= (float)(flock.num_boids);
  724.     from = at + D3DVECTOR(20.0f * (float)sin (tic* 0.223f), 
  725.                            16.0f + 15.0f * (float)sin (tic * 0.33f), 
  726.                            20.0f * (float)cos (tic * 0.31f));
  727.  
  728.     flock.goal = D3DVECTOR(105.0f * (float)sin (tic * 0.1f), 
  729.                             10.0f, 
  730.                             105.0f * (float)cos (tic * 0.1f));
  731.  
  732.  
  733.  
  734.     // Finally, draw obstacles last since they're transparent.
  735.     // Set renderstates to support blending such that the texture
  736.     // color is added over the background color.  Also turn Z-write
  737.     // off so when two spheres line up you can always see them both.
  738.     if (lpDev->SetRenderState(D3DRENDERSTATE_BLENDENABLE, TRUE) != D3D_OK)
  739.         return FALSE;
  740.        if (lpDev->SetRenderState(D3DRENDERSTATE_SRCBLEND, D3DBLEND_SRCCOLOR) != D3D_OK)
  741.         return FALSE;
  742.     if (lpDev->SetRenderState(D3DRENDERSTATE_DESTBLEND, D3DBLEND_ONE) != D3D_OK)
  743.         return FALSE;
  744.     if (lpDev->SetRenderState(D3DRENDERSTATE_ZWRITEENABLE, FALSE) != D3D_OK)
  745.         return FALSE;
  746.     // make sure the texture wraps correctly
  747.     if (lpDev->SetRenderState(D3DRENDERSTATE_WRAPU, TRUE) != D3D_OK)
  748.         return FALSE;
  749.     
  750.     lpSphereMat->SetAsCurrent(lpDev);
  751.     for (i=0; i<flock.num_obs; i++) {
  752.         world = MatrixMult(TranslateMatrix(flock.obs[i].loc), MatrixMult(RotateYMatrix(-tic*pi), ScaleMatrix (flock.obs[i].radius)));
  753.         
  754.         hResult = lpDev->SetTransform(D3DTRANSFORMSTATE_WORLD, &world);
  755.         if (hResult != D3D_OK) {
  756.             REPORTERR(hResult);
  757.             return hResult;
  758.         }
  759.  
  760.         hResult = DrawSphere(lpDev);
  761.         if (hResult != D3D_OK) {
  762.             REPORTERR(hResult);
  763.             goto lblCLEANUP;
  764.         }
  765.     }
  766.  
  767.     // set renderstates back to default
  768.     if (lpDev->SetRenderState(D3DRENDERSTATE_BLENDENABLE, FALSE) != D3D_OK)
  769.         return FALSE;
  770.     if (lpDev->SetRenderState(D3DRENDERSTATE_SRCBLEND, D3DBLEND_ONE) != D3D_OK)
  771.         return FALSE;
  772.     if (lpDev->SetRenderState(D3DRENDERSTATE_DESTBLEND, D3DBLEND_ZERO) != D3D_OK)
  773.         return FALSE;
  774.     if (lpDev->SetRenderState(D3DRENDERSTATE_ZWRITEENABLE, TRUE) != D3D_OK)
  775.         return FALSE;
  776.  
  777.  
  778. lblCLEANUP: 
  779.     // End Scene
  780.     // Note:  This is complicated by the need to restore lost surfaces
  781.     hResult = lpDev->EndScene();
  782.     if (hResult != D3D_OK) {
  783.         while (hResult == DDERR_SURFACELOST) {
  784.             // Restore surface
  785.             while (hResult == DDERR_SURFACELOST) {
  786.                 hResult = lpd3dWindow->Restore();
  787.             }
  788.  
  789.             // Try EndScene again
  790.             hResult = lpDev->EndScene();
  791.         }
  792.  
  793.         if (hResult != D3D_OK) {
  794.             REPORTERR(hResult);
  795.             return hResult;
  796.         }
  797.     }
  798.  
  799.     if (lpExtent) {
  800.         hResult = lpDev->GetClipStatus(&status);
  801.         if (hResult != D3D_OK) {
  802.             REPORTERR(hResult);
  803.             return hResult;
  804.         }
  805.  
  806.         if (status.dwFlags & D3DCLIPSTATUS_EXTENTS2) {
  807.             lpExtent->x1 = (long) floor((double)status.minx);
  808.             lpExtent->x2 = (long) ceil((double)status.maxx);
  809.             lpExtent->y1 = (long) floor((double)status.miny);
  810.             lpExtent->y2 = (long) ceil((double)status.maxy);
  811.         }
  812.     }
  813.         
  814.     return hResult;
  815. } // End D3DScene::Render
  816.  
  817.  
  818.   
  819. /*
  820. **----------------------------------------------------------------------------
  821. ** Name:        D3DScene::Restore
  822. ** Purpose:     Restore any scene specific surfaces that might have been
  823. **                lost on a DDERR_LOSTSURFACE message
  824. **----------------------------------------------------------------------------
  825. */
  826.  
  827. HRESULT D3DScene::Restore(void)
  828. {
  829.     // Nothing to do for now
  830.  
  831.     // Success
  832.     return D3D_OK;
  833. } // End D3DScene::Restore
  834.  
  835.  
  836.   
  837. /*
  838. **----------------------------------------------------------------------------
  839. ** Name:        D3DScene::AttachViewport
  840. ** Purpose:
  841. **----------------------------------------------------------------------------
  842. */
  843.  
  844. HRESULT
  845. D3DScene::AttachViewport(void)
  846. {
  847.     LPDIRECT3D2                lpD3D;
  848.     LPDIRECT3DDEVICE2        lpDev;
  849.     LPDIRECT3DVIEWPORT2       lpView;
  850.  
  851.     // Check Initialization
  852.     if ((! lpd3dWindow) || (! lpd3dWindow->isValid())) {
  853.         // Error,
  854.         REPORTERR(DDERR_GENERIC);
  855.         return DDERR_GENERIC;
  856.     }
  857.  
  858.     lpD3D  = lpd3dWindow->lpD3D;
  859.     lpDev  = lpd3dWindow->lpd3dDevice;
  860.     lpView = lpd3dWindow->lpd3dViewport;
  861.  
  862.     if ((! lpD3D) || (! lpDev) || (! lpView)) {
  863.         REPORTERR(DDERR_GENERIC);
  864.         return DDERR_GENERIC;
  865.     }
  866.  
  867.     // Create and set up the background material
  868.     lpBackgroundMat = new Material(lpD3D, lpDev);
  869.     lpBackgroundMat->SetDiffuse(D3DVECTOR(0.0f, 0.05f, 0.1f));
  870.     lpBackgroundMat->SetAsBackground(lpView);
  871.  
  872.     // Create and set up the grid material, since we're using LVertices we want
  873.     // to make sure that ramp mode can actually get the right colors so we set
  874.     // the emissive value to the color we want and choose a small ramp size
  875.     lpGridMat = new Material(lpD3D, lpDev);
  876.     lpGridMat->SetEmissive(grid_color);
  877.     lpGridMat->SetRampSize(2);
  878.  
  879.     // Create and set up the sphere material
  880.     lpSphereMat = new Material(lpD3D, lpDev);
  881.     lpSphereMat->SetDiffuse(D3DVECTOR(1.0f));
  882.  
  883.     // Create the sphere texture and attatch it to the material
  884.     SphereTex.Load(lpDev, "DX5_logo");
  885.     lpSphereMat->SetTextureHandle(SphereTex.GetHandle());
  886.  
  887.     // Create and set up the boid material
  888.     // note that we'll just change the color for each boid we render
  889.     lpBoidMat = new Material(lpD3D, lpDev);
  890.     lpBoidMat->SetDiffuse(D3DVECTOR(1.0f));
  891.  
  892.     // set up transform matrices
  893.     D3DVECTOR    from(0.0f, 0.0f, -100.0f);
  894.     D3DVECTOR    at(0.0f, 0.0f, 0.0f);
  895.     D3DVECTOR    up(0.0f, 1.0f, 0.0f);
  896.  
  897.     view = ViewMatrix(from, at, up);
  898.     proj = ProjectionMatrix(1.0f, 400.0f, pi/4.0f);
  899.     world = IdentityMatrix();
  900.  
  901.     // create 2 lights
  902.     D3DVECTOR    color(1.0f, 1.0f, 1.0f);
  903.     D3DVECTOR    direction(-0.5f, -1.0f, -0.3f);
  904.  
  905.     lpLight1 = new DirectionalLight(lpD3D, color, Normalize(direction));
  906.     if (lpLight1) {
  907.         lpLight1->AddToViewport(lpView);
  908.     }
  909.  
  910.     lpLight2 = new DirectionalLight(lpD3D, color/2.0f, -Normalize(direction));
  911.     if (lpLight2) {
  912.         lpLight2->AddToViewport(lpView);
  913.     }
  914.  
  915.     // Success
  916.     return D3D_OK;
  917. } // End D3DScene::AttachViewport
  918.  
  919.     
  920.  
  921. /*
  922. **-----------------------------------------------------------------------------
  923. **  Name:       D3DScene::DetachViewport
  924. **  Purpose:    Cleanup Viewport
  925. **-----------------------------------------------------------------------------
  926. */
  927.  
  928. HRESULT D3DScene::DetachViewport(void)
  929. {
  930.     LPDIRECT3DVIEWPORT2 lpViewport = NULL;
  931.  
  932.     if (lpd3dWindow) {
  933.         lpViewport = lpd3dWindow->GetViewport();
  934.     }
  935.  
  936.     // Cleanup lights
  937.     if (lpLight1) {
  938.         if (lpViewport) {
  939.             lpLight1->RemoveFromViewport(lpViewport);
  940.         }
  941.  
  942.         delete lpLight1;
  943.         lpLight1 = NULL;
  944.     }
  945.  
  946.     if (lpLight2) {
  947.         if (lpViewport) {
  948.             lpLight2->RemoveFromViewport(lpViewport);
  949.         }
  950.  
  951.         delete lpLight2;
  952.         lpLight2 = NULL;
  953.     }
  954.  
  955.     // Cleanup Materials
  956.     delete lpBackgroundMat;
  957.     delete lpGridMat;
  958.     delete lpSphereMat;
  959.     delete lpBoidMat;
  960.  
  961.     lpBackgroundMat = NULL;
  962.     lpGridMat = NULL;
  963.     lpSphereMat = NULL;
  964.     lpBoidMat = NULL;
  965.  
  966.     SphereTex.Release();
  967.  
  968.     // Success
  969.     return D3D_OK;
  970. } // End D3DScene::DetachViewport
  971.  
  972.  
  973.   
  974. /*
  975. **----------------------------------------------------------------------------
  976. ** End of File
  977. **----------------------------------------------------------------------------
  978. */
  979.  
  980.