Source code of Windows XP (NT5)
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

1036 lines
24 KiB

  1. #include <stdlib.h>
  2. #include <stdio.h>
  3. #include <math.h>
  4. #include <string.h>
  5. #include <time.h>
  6. #include <assert.h>
  7. #include <windows.h>
  8. #include <gl\gl.h>
  9. #include <gl\glu.h>
  10. #include <gl\glaux.h>
  11. #define PI ((float)3.14159265358979323846)
  12. #define WIDTH 512
  13. #define HEIGHT 512
  14. #define TESS_MIN 5
  15. #define TESS_MAX 100
  16. int tessLevel = TESS_MAX / 2; // corresponds to # of rings/sections in object
  17. int tessInc = 5;
  18. typedef struct
  19. {
  20. float fX, fY, fZ;
  21. float fNx, fNy, fNz;
  22. DWORD dwColor;
  23. } VERTEX;
  24. typedef struct
  25. {
  26. int iV1;
  27. int iV2;
  28. int iV3;
  29. } TRIANGLE;
  30. enum {
  31. OBJECT_TYPE_SPHERE = 0,
  32. OBJECT_TYPE_TORUS,
  33. OBJECT_TYPE_CYLINDER
  34. };
  35. class OBJECT {
  36. public:
  37. OBJECT( int rings, int sections );
  38. ~OBJECT( );
  39. int VertexCount() { return nVerts; }
  40. int TriangleCount() { return nTris; }
  41. VERTEX *VertexData() { return pVertData; }
  42. TRIANGLE *TriangleData() { return pTriData; }
  43. int NumRings() { return nRings; }
  44. int NumSections() { return nSections; }
  45. protected:
  46. int iType; // object type
  47. int nVerts, nTris;
  48. int nRings, nSections;
  49. VERTEX *pVertData;
  50. TRIANGLE *pTriData;
  51. };
  52. class SPHERE : public OBJECT {
  53. public:
  54. SPHERE( int rings, int sections );
  55. private:
  56. void GenerateData( float fRadius );
  57. int CalcNVertices();
  58. int CalcNTriangles();
  59. };
  60. enum {
  61. DRAW_METHOD_VERTEX_ARRAY = 0,
  62. DRAW_METHOD_DREE,
  63. DRAW_METHOD_TRIANGLES,
  64. DRAW_METHOD_TRISTRIPS,
  65. NUM_DRAW_METHODS
  66. };
  67. // Draw method names
  68. char *pszListType[NUM_DRAW_METHODS] =
  69. {
  70. "Vertex Array", "DrawRangeElements", "Direct Triangles", "Direct Strips"
  71. };
  72. class DRAW_CONTROLLER {
  73. public:
  74. DRAW_CONTROLLER::DRAW_CONTROLLER();
  75. DRAW_CONTROLLER::~DRAW_CONTROLLER();
  76. void InitGL();
  77. void CycleDrawMethod();
  78. void ToggleDisplayListDraw() {bDisplayList = !bDisplayList; }
  79. void ToggleLighting() {bLighting = !bLighting; SetLighting(); }
  80. void Draw();
  81. OBJECT *GetDrawObject() {return pObject;}
  82. void SetDrawObject( OBJECT *pObj, int objectType );
  83. char *GetDrawMethodName();
  84. private:
  85. int iDrawMethod;
  86. BOOL bDisplayList;
  87. BOOL bLighting;
  88. BOOL bDREE; // if DrawRangeElements extension available or not
  89. BOOL bDREE_Disabled; // DREE can be temporarily disabled if not
  90. // practical to use (e.g. high tesselation)
  91. int nDREE_MaxVertices;
  92. int nDREE_MaxIndices;
  93. PFNGLDRAWRANGEELEMENTSWINPROC pfnDrawRangeElementsWIN;
  94. OBJECT *pObject; // Draw object
  95. int iObjectType;
  96. GLint dlList[NUM_DRAW_METHODS];
  97. char **pszDrawMethodNames;
  98. char szNameBuf[80];
  99. void SetLighting();
  100. void NewList();
  101. void DeleteLists();
  102. void DeleteList(int iList);
  103. void DrawObject();
  104. // Draw methods
  105. void DrawVertexArray ();
  106. void DrawRangeElements();
  107. void DrawTriangles();
  108. void DrawStrips();
  109. void Vertex(int iVert);
  110. void CheckDREE_Existence();
  111. BOOL CheckDREE_Usable();
  112. };
  113. class SCENE {
  114. public:
  115. SCENE();
  116. ~SCENE();
  117. void Draw();
  118. void NewObject( int tessLevel );
  119. DRAW_CONTROLLER drawController;
  120. private:
  121. GLfloat fXr, fYr, fZr;
  122. GLfloat fDXr, fDYr, fDZr;
  123. };
  124. enum {
  125. TIMER_METHOD_SINGLE = 0, // single-shot timer
  126. TIMER_METHOD_AVERAGE, // average time for past n results
  127. };
  128. #define MAX_RESULTS 10
  129. class TIMER {
  130. public:
  131. TIMER( int timerMethodArg );
  132. void Start() { dwMillis = GetTickCount(); }
  133. BOOL Stop( int numItems, float *fRate );
  134. void Reset();
  135. private:
  136. int timerMethod;
  137. int nItems;
  138. int nTotalItems; // total # triangles accumulated
  139. DWORD dwMillis;
  140. DWORD dwTotalMillis;
  141. DWORD updateInterval; // interval between timer updates
  142. // These variables are for result averaging
  143. float fResults[MAX_RESULTS];
  144. int nResults; // current # of results
  145. int nMaxResults; // max # of results for averaging
  146. int iOldestResult; // index of oldest result
  147. float fSummedResults; // current sum of results
  148. };
  149. // Global objects
  150. SCENE *scene;
  151. SPHERE *sphere;
  152. TIMER timer( TIMER_METHOD_AVERAGE );
  153. #define RGB_COLOR(red, green, blue) \
  154. (((DWORD)(BYTE)(red) << 0) | \
  155. ((DWORD)(BYTE)(green) << 8) | \
  156. ((DWORD)(BYTE)(blue) << 16))
  157. #define FRANDOM(x) (((float)rand() / RAND_MAX) * (x))
  158. #define DROT 10.0f
  159. BOOL fSingle = FALSE;
  160. /****** OBJECT *******************************************************/
  161. OBJECT::OBJECT( int rings, int sections )
  162. : nRings( rings ), nSections( sections )
  163. {
  164. pTriData = NULL;
  165. pVertData = NULL;
  166. }
  167. OBJECT::~OBJECT()
  168. {
  169. // These ptrs alloc'd in inheriting classes...
  170. if( pVertData )
  171. free( pVertData );
  172. if( pTriData )
  173. free( pTriData );
  174. }
  175. /****** SPHERE *******************************************************/
  176. SPHERE::SPHERE(
  177. int rings, int sections )
  178. : OBJECT( rings, sections )
  179. {
  180. iType = OBJECT_TYPE_SPHERE;
  181. nVerts = CalcNVertices();
  182. nTris = CalcNTriangles();
  183. // Allocate memory for the sphere data (freed by the base OBJECT class)
  184. // Vertex data
  185. pVertData = (VERTEX *) malloc( nVerts * sizeof(VERTEX) );
  186. assert( pVertData != NULL );
  187. // Triangle indices
  188. pTriData = (TRIANGLE *) malloc( nTris * sizeof(TRIANGLE) );
  189. assert( pTriData != NULL );
  190. GenerateData(1.0f);
  191. }
  192. int
  193. SPHERE::CalcNVertices()
  194. {
  195. return (((nRings)+1)*(nSections)+2);
  196. }
  197. int
  198. SPHERE::CalcNTriangles()
  199. {
  200. return (((nRings)+1)*(nSections)*2);
  201. }
  202. void
  203. SPHERE::GenerateData( float fRadius )
  204. {
  205. float fTheta, fPhi; /* Angles used to sweep around sphere */
  206. float fDTheta, fDPhi; /* Angle between each section and ring */
  207. float fX, fY, fZ, fV, fRSinTheta; /* Temporary variables */
  208. int i, j, n, m; /* counters */
  209. VERTEX *pvtx = pVertData;
  210. TRIANGLE *ptri = pTriData;
  211. /*
  212. * Generate vertices at the top and bottom points.
  213. */
  214. pvtx[0].fX = 0.0f;
  215. pvtx[0].fY = fRadius;
  216. pvtx[0].fZ = 0.0f;
  217. pvtx[0].fNx = 0.0f;
  218. pvtx[0].fNy = 1.0f;
  219. pvtx[0].fNz = 0.0f;
  220. pvtx[0].dwColor = RGB_COLOR(0, 0, 255);
  221. pvtx[nVerts - 1].fX = 0.0f;
  222. pvtx[nVerts - 1].fY = -fRadius;
  223. pvtx[nVerts - 1].fZ = 0.0f;
  224. pvtx[nVerts - 1].fNx = 0.0f;
  225. pvtx[nVerts - 1].fNy = -1.0f;
  226. pvtx[nVerts - 1].fNz = 0.0f;
  227. pvtx[nVerts - 1].dwColor = RGB_COLOR(0, 255, 0);
  228. /*
  229. * Generate vertex points for rings
  230. */
  231. fDTheta = PI / (float) (nRings + 2);
  232. fDPhi = 2.0f * PI / (float) nSections;
  233. n = 1; /* vertex being generated, begins at 1 to skip top point */
  234. fTheta = fDTheta;
  235. for (i = 0; i <= nRings; i++)
  236. {
  237. fY = (float)(fRadius * cos(fTheta)); /* y is the same for each ring */
  238. fV = fTheta / PI; /* v is the same for each ring */
  239. fRSinTheta = (float)(fRadius * sin(fTheta));
  240. fPhi = 0.0f;
  241. for (j = 0; j < nSections; j++)
  242. {
  243. fX = (float)(fRSinTheta * sin(fPhi));
  244. fZ = (float)(fRSinTheta * cos(fPhi));
  245. pvtx[n].fX = fX;
  246. pvtx[n].fZ = fZ;
  247. pvtx[n].fY = fY;
  248. pvtx[n].fNx = fX / fRadius;
  249. pvtx[n].fNy = fY / fRadius;
  250. pvtx[n].fNz = fZ / fRadius;
  251. if (n & 1)
  252. {
  253. pvtx[n].dwColor = RGB_COLOR(0, 0, 255);
  254. }
  255. else
  256. {
  257. pvtx[n].dwColor = RGB_COLOR(0, 255, 0);
  258. }
  259. fPhi += fDPhi;
  260. n++;
  261. }
  262. fTheta += fDTheta;
  263. }
  264. /*
  265. * Generate triangles for top and bottom caps.
  266. */
  267. for (i = 0; i < nSections; i++)
  268. {
  269. ptri[i].iV1 = 0;
  270. ptri[i].iV2 = i + 1;
  271. ptri[i].iV3 = 1 + ((i + 1) % nSections);
  272. ptri[nTris - nSections + i].iV1 = nVerts - 1;
  273. ptri[nTris - nSections + i].iV2 = nVerts - 2 - i;
  274. ptri[nTris - nSections + i].iV3 = nVerts - 2 - ((1 + i) % nSections);
  275. }
  276. /*
  277. * Generate triangles for the rings
  278. */
  279. m = 1; /* first vertex in current ring, begins at 1 to skip top point*/
  280. n = nSections; /* triangle being generated, skip the top cap */
  281. for (i = 0; i < nRings; i++)
  282. {
  283. for (j = 0; j < nSections; j++)
  284. {
  285. ptri[n].iV1 = m + j;
  286. ptri[n].iV2 = m + nSections + j;
  287. ptri[n].iV3 = m + nSections + ((j + 1) % nSections);
  288. ptri[n + 1].iV1 = ptri[n].iV1;
  289. ptri[n + 1].iV2 = ptri[n].iV3;
  290. ptri[n + 1].iV3 = m + ((j + 1) % nSections);
  291. n += 2;
  292. }
  293. m += nSections;
  294. }
  295. }
  296. /****** DRAW_CONTROLLER *********************************************/
  297. DRAW_CONTROLLER::DRAW_CONTROLLER( )
  298. {
  299. iDrawMethod = 0;
  300. bDisplayList = FALSE;
  301. bLighting = TRUE;
  302. // check out if DREE exists
  303. CheckDREE_Existence();
  304. pszDrawMethodNames = pszListType;
  305. // Set display list indices to 0 (so they will be filled later)
  306. for( int i = 0; i < NUM_DRAW_METHODS; i++ )
  307. dlList[i] = 0;
  308. // Init GL state
  309. InitGL();
  310. }
  311. DRAW_CONTROLLER::~DRAW_CONTROLLER( )
  312. {
  313. DeleteLists();
  314. }
  315. void
  316. DRAW_CONTROLLER::DeleteLists()
  317. {
  318. for( int i = 0; i < NUM_DRAW_METHODS; i ++ )
  319. DeleteList( i );
  320. }
  321. void
  322. DRAW_CONTROLLER::DeleteList( int iList )
  323. {
  324. if( dlList[iList] ) {
  325. glDeleteLists( dlList[iList], 1 );
  326. dlList[iList] = 0;
  327. }
  328. }
  329. void
  330. DRAW_CONTROLLER::CheckDREE_Existence()
  331. {
  332. // Check for DrawRangeElements extension
  333. pfnDrawRangeElementsWIN = (PFNGLDRAWRANGEELEMENTSWINPROC)
  334. wglGetProcAddress("glDrawRangeElementsWIN");
  335. if (pfnDrawRangeElementsWIN == NULL) {
  336. bDREE = FALSE;
  337. bDREE_Disabled = TRUE;
  338. return;
  339. }
  340. // Extension exists - find out its limits
  341. bDREE = TRUE;
  342. glGetIntegerv( GL_MAX_ELEMENTS_VERTICES_WIN, &nDREE_MaxVertices );
  343. glGetIntegerv( GL_MAX_ELEMENTS_INDICES_WIN, &nDREE_MaxIndices );
  344. }
  345. BOOL
  346. DRAW_CONTROLLER::CheckDREE_Usable( )
  347. {
  348. // Cancel DrawRangeElements if vertex structure makes it impractical :
  349. // - Vertex range too great to fit in call, or
  350. // - Too many indices
  351. // (I add 1 here to account for top or bottom vertices in a batch)
  352. if( ( (2*pObject->NumSections() + 1) > nDREE_MaxVertices ) ||
  353. ( (2*pObject->NumSections()*3) > nDREE_MaxIndices )
  354. )
  355. bDREE_Disabled = TRUE;
  356. else
  357. bDREE_Disabled = FALSE;
  358. return !bDREE_Disabled;
  359. }
  360. char *
  361. DRAW_CONTROLLER::GetDrawMethodName()
  362. {
  363. // Returns name of current drawing method. If in dlist mode, then this is
  364. // prepended to the name.
  365. sprintf(szNameBuf, "%s%s",
  366. bDisplayList ? "Display List " : "",
  367. pszDrawMethodNames[iDrawMethod] );
  368. return szNameBuf;
  369. }
  370. void
  371. DRAW_CONTROLLER::CycleDrawMethod()
  372. {
  373. iDrawMethod++;
  374. if( bDREE_Disabled && (iDrawMethod == DRAW_METHOD_DREE) )
  375. iDrawMethod++;
  376. if( iDrawMethod >= NUM_DRAW_METHODS )
  377. iDrawMethod = 0;
  378. }
  379. void
  380. DRAW_CONTROLLER::NewList( )
  381. {
  382. // Create new list for the current draw method
  383. if( ! dlList[iDrawMethod] ) {
  384. dlList[iDrawMethod] = glGenLists(1);
  385. }
  386. glNewList(dlList[iDrawMethod], GL_COMPILE);
  387. DrawObject();
  388. glEndList();
  389. }
  390. void
  391. DRAW_CONTROLLER::SetDrawObject( OBJECT *pObj, int objectType )
  392. {
  393. iObjectType = objectType;
  394. pObject = pObj;
  395. // Delete all current lists
  396. DeleteLists();
  397. // Check if DREE can be used - and if not go on to next method if
  398. // current method is DREE
  399. if( !CheckDREE_Usable() && (iDrawMethod == DRAW_METHOD_DREE) )
  400. CycleDrawMethod();
  401. }
  402. void
  403. DRAW_CONTROLLER::Draw()
  404. {
  405. // Draws display list or immediate mode
  406. // Display list draw
  407. if( bDisplayList ) {
  408. // Create dlist if necessary
  409. if( !dlList[iDrawMethod] )
  410. NewList();
  411. glCallList( dlList[iDrawMethod] );
  412. return;
  413. }
  414. // Immediate mode draw
  415. DrawObject();
  416. }
  417. void
  418. DRAW_CONTROLLER::DrawObject()
  419. {
  420. // Issues draw commands
  421. switch( iDrawMethod ) {
  422. case DRAW_METHOD_VERTEX_ARRAY :
  423. DrawVertexArray();
  424. break;
  425. case DRAW_METHOD_DREE :
  426. DrawRangeElements();
  427. break;
  428. case DRAW_METHOD_TRIANGLES :
  429. DrawTriangles();
  430. break;
  431. case DRAW_METHOD_TRISTRIPS :
  432. DrawStrips();
  433. break;
  434. }
  435. }
  436. void
  437. DRAW_CONTROLLER::DrawVertexArray()
  438. {
  439. glDrawElements(GL_TRIANGLES,
  440. pObject->TriangleCount()*3,
  441. GL_UNSIGNED_INT,
  442. pObject->TriangleData() );
  443. }
  444. void
  445. DRAW_CONTROLLER::DrawRangeElements()
  446. {
  447. GLint *pTriIndices;
  448. GLint nVerts, nTris;
  449. GLenum type = GL_UNSIGNED_INT;
  450. nVerts = pObject->VertexCount();
  451. nTris = pObject->TriangleCount();
  452. pTriIndices = (int *) pObject->TriangleData();
  453. // Check for trivial case requiring no batching
  454. if( (nVerts <= nDREE_MaxVertices) &&
  455. (nTris*3 <= nDREE_MaxIndices) ) {
  456. pfnDrawRangeElementsWIN(GL_TRIANGLES,
  457. 0,
  458. nVerts-1,
  459. nTris*3,
  460. type,
  461. pTriIndices );
  462. return;
  463. }
  464. // Have to batch : Since the vertex ordering of the sphere is along rings,
  465. // we will batch by groups of rings, according to the vertex index ranges
  466. // allowed by the DrawRangeElements call.
  467. //
  468. // Need some more variables:
  469. GLuint start, end;
  470. GLsizei count;
  471. GLuint nRingsPerBatch, nTrisPerBatch, nElemsPerBatch,
  472. nVerticesPerBatch, elemsLeft;
  473. int sections = pObject->NumSections();
  474. int rings = pObject->NumRings();
  475. nRingsPerBatch = nDREE_MaxVertices / (sections);
  476. nTrisPerBatch = (nRingsPerBatch-1)*sections*2;
  477. nElemsPerBatch = nTrisPerBatch*3;
  478. nVerticesPerBatch = nRingsPerBatch*sections;
  479. elemsLeft = nTris*3;
  480. // Special case first batch with top vertex
  481. start = 0;
  482. end = nVerticesPerBatch - sections;
  483. count = nElemsPerBatch - (sections*3); // top row only has half the tris of
  484. // a 'normal' row
  485. pfnDrawRangeElementsWIN(GL_TRIANGLES,
  486. start,
  487. end,
  488. count,
  489. type,
  490. pTriIndices);
  491. // Batch groups of rings around sphere
  492. pTriIndices += count;
  493. start = (end - sections + 1);
  494. elemsLeft -= count;
  495. while( elemsLeft >= nElemsPerBatch )
  496. {
  497. pfnDrawRangeElementsWIN(GL_TRIANGLES,
  498. start,
  499. start + nVerticesPerBatch - 1,
  500. nElemsPerBatch,
  501. type,
  502. pTriIndices);
  503. start += (nVerticesPerBatch - sections);
  504. pTriIndices += nElemsPerBatch;
  505. elemsLeft -= nElemsPerBatch;
  506. }
  507. // Do last batch, including bottom vertex
  508. if( elemsLeft ) {
  509. pfnDrawRangeElementsWIN(GL_TRIANGLES,
  510. start,
  511. nVerts-1,
  512. elemsLeft,
  513. type,
  514. pTriIndices);
  515. }
  516. }
  517. void
  518. DRAW_CONTROLLER::Vertex(int iVert)
  519. {
  520. VERTEX *pvtx;
  521. pvtx = pObject->VertexData() + iVert;
  522. glColor3ubv((GLubyte *)&pvtx->dwColor);
  523. glNormal3fv(&pvtx->fNx);
  524. glVertex3fv(&pvtx->fX);
  525. }
  526. void
  527. DRAW_CONTROLLER::DrawTriangles()
  528. {
  529. int iVert, *pidx;
  530. glBegin(GL_TRIANGLES);
  531. pidx = (int *) pObject->TriangleData();
  532. for (iVert = 0; iVert < pObject->TriangleCount()*3; iVert++)
  533. {
  534. Vertex(*pidx++);
  535. }
  536. glEnd();
  537. }
  538. void
  539. DRAW_CONTROLLER::DrawStrips()
  540. {
  541. int iIdxBase;
  542. int iRing, iSection;
  543. int sections = pObject->NumSections();
  544. int rings = pObject->NumRings();
  545. // Triangle fans for top and bottom caps
  546. glBegin(GL_TRIANGLE_FAN);
  547. Vertex(0);
  548. iIdxBase = 1;
  549. for (iSection = 0; iSection <= sections; iSection++)
  550. {
  551. Vertex(iIdxBase+(iSection % sections));
  552. }
  553. glEnd();
  554. glBegin(GL_TRIANGLE_FAN);
  555. Vertex(pObject->VertexCount() - 1);
  556. iIdxBase = pObject->VertexCount() - sections - 1;
  557. for (iSection = sections; iSection >= 0 ; iSection--)
  558. {
  559. Vertex(iIdxBase+(iSection % sections));
  560. }
  561. glEnd();
  562. // Triangle strips for each ring
  563. iIdxBase = 1;
  564. for (iRing = 0; iRing < rings; iRing++)
  565. {
  566. glBegin(GL_TRIANGLE_STRIP);
  567. for (iSection = 0; iSection <= sections; iSection++)
  568. {
  569. Vertex(iIdxBase+(iSection % sections));
  570. Vertex(iIdxBase+(iSection % sections)+sections);
  571. }
  572. glEnd();
  573. iIdxBase += sections;
  574. }
  575. }
  576. void
  577. DRAW_CONTROLLER::InitGL(void)
  578. {
  579. float fv4[4];
  580. int iv1[1];
  581. int i;
  582. fv4[0] = 0.05f;
  583. fv4[1] = 0.05f;
  584. fv4[2] = 0.05f;
  585. fv4[3] = 1.0f;
  586. glLightModelfv(GL_LIGHT_MODEL_AMBIENT, fv4);
  587. fv4[0] = 0.0f;
  588. fv4[1] = 1.0f;
  589. fv4[2] = 1.0f;
  590. fv4[3] = 0.0f;
  591. glLightfv(GL_LIGHT0, GL_POSITION, fv4);
  592. fv4[0] = 0.9f;
  593. fv4[1] = 0.9f;
  594. fv4[2] = 0.9f;
  595. fv4[3] = 1.0f;
  596. glLightfv(GL_LIGHT0, GL_DIFFUSE, fv4);
  597. glEnable(GL_LIGHT0);
  598. glEnable(GL_LIGHTING);
  599. fv4[0] = 0.6f;
  600. fv4[1] = 0.6f;
  601. fv4[2] = 0.6f;
  602. fv4[3] = 1.0f;
  603. glMaterialfv(GL_FRONT, GL_SPECULAR, fv4);
  604. iv1[0] = 40;
  605. glMaterialiv(GL_FRONT, GL_SHININESS, iv1);
  606. glEnable(GL_CULL_FACE);
  607. glEnableClientState(GL_VERTEX_ARRAY);
  608. glEnableClientState(GL_NORMAL_ARRAY);
  609. glEnableClientState(GL_COLOR_ARRAY);
  610. glColorMaterial(GL_FRONT, GL_AMBIENT_AND_DIFFUSE);
  611. glEnable(GL_COLOR_MATERIAL);
  612. glMatrixMode(GL_PROJECTION);
  613. glLoadIdentity();
  614. gluPerspective(45, 1, .01, 15);
  615. gluLookAt(0, 0, 10, 0, 0, 0, 0, 1, 0);
  616. glMatrixMode(GL_MODELVIEW);
  617. SetLighting();
  618. }
  619. void
  620. DRAW_CONTROLLER::SetLighting(void)
  621. {
  622. if( bLighting ) {
  623. glEnable( GL_LIGHTING );
  624. } else {
  625. glDisable( GL_LIGHTING );
  626. }
  627. }
  628. /****** SCENE *******************************************************/
  629. SCENE::SCENE()
  630. {
  631. srand(time(NULL));
  632. // Create sphere draw object for the scene
  633. NewObject( tessLevel );
  634. }
  635. void
  636. SCENE::NewObject( int tessLevel )
  637. {
  638. // Only one object allowed for now - delete any previous object
  639. if( sphere )
  640. delete sphere;
  641. // Create new sphere for the scene
  642. sphere = new SPHERE( tessLevel, tessLevel );
  643. assert( sphere != NULL );
  644. // Inform DRAW_CONTROLLER about new object
  645. drawController.SetDrawObject( sphere, OBJECT_TYPE_SPHERE );
  646. // Initialize array pointer data
  647. VERTEX *pVertData = sphere->VertexData();
  648. glVertexPointer(3, GL_FLOAT, sizeof(VERTEX), &pVertData->fX);
  649. glNormalPointer(GL_FLOAT, sizeof(VERTEX), &pVertData->fNx);
  650. glColorPointer(3, GL_UNSIGNED_BYTE, sizeof(VERTEX), &pVertData->dwColor);
  651. // Init scene rotation and motion
  652. fXr = 0.0f;
  653. fYr = 0.0f;
  654. fZr = 0.0f;
  655. fDXr = DROT - FRANDOM(2 * DROT);
  656. fDYr = DROT - FRANDOM(2 * DROT);
  657. fDZr = DROT - FRANDOM(2 * DROT);
  658. }
  659. SCENE::~SCENE()
  660. {
  661. // Delete any scene objects
  662. if( sphere )
  663. delete sphere;
  664. }
  665. void
  666. SCENE::Draw()
  667. {
  668. glClear(GL_COLOR_BUFFER_BIT);
  669. glLoadIdentity();
  670. glRotatef(fXr, 1.0f, 0.0f, 0.0f);
  671. glRotatef(fYr, 0.0f, 1.0f, 0.0f);
  672. glRotatef(fZr, 0.0f, 0.0f, 1.0f);
  673. drawController.Draw();
  674. // next rotation...
  675. fXr += fDXr;
  676. fYr += fDYr;
  677. fZr += fDZr;
  678. }
  679. /****** TIMER *******************************************************/
  680. TIMER::TIMER( int timerMethodArg )
  681. : timerMethod( timerMethodArg )
  682. {
  683. updateInterval = 2000; // in milliseconds
  684. Reset();
  685. }
  686. void
  687. TIMER::Reset()
  688. {
  689. dwTotalMillis = 0;
  690. nTotalItems = 0;
  691. // Parameters for result averaging
  692. nResults = 0;
  693. nMaxResults = MAX_RESULTS; // number of most recent results to average
  694. fSummedResults = 0.0f;
  695. iOldestResult = 0; // index of oldest result
  696. }
  697. BOOL
  698. TIMER::Stop( int numItems, float *fRate )
  699. {
  700. dwMillis = GetTickCount()-dwMillis;
  701. dwTotalMillis += dwMillis;
  702. nTotalItems += numItems;
  703. // If total elapsed time is greater than the update interval, send back
  704. // timing information
  705. if (dwTotalMillis > updateInterval )
  706. {
  707. float fItemsPerSecond;
  708. int iNewResult;
  709. fItemsPerSecond = (float) nTotalItems*1000.0f/dwTotalMillis;
  710. switch( timerMethod ) {
  711. case TIMER_METHOD_AVERAGE :
  712. // Average last n results (they are kept in a circular buffer)
  713. if( nResults < nMaxResults ) {
  714. // Haven't filled the buffer yet
  715. iNewResult = nResults;
  716. nResults++;
  717. } else {
  718. // Full buffer : replace oldest entry with new value
  719. fSummedResults -= fResults[iOldestResult];
  720. iNewResult = iOldestResult;
  721. iOldestResult = (iOldestResult == (nMaxResults - 1)) ?
  722. 0 :
  723. (iOldestResult + 1);
  724. }
  725. // Add new result, maintain sum to simplify calculations
  726. fResults[iNewResult] = fItemsPerSecond;
  727. fSummedResults += fItemsPerSecond;
  728. // average the result
  729. fItemsPerSecond = fSummedResults / (float) nResults;
  730. break;
  731. }
  732. // Set running totals back to 0
  733. dwTotalMillis = 0;
  734. nTotalItems = 0;
  735. *fRate = fItemsPerSecond;
  736. return TRUE;
  737. } else
  738. return FALSE; // no new information yet
  739. }
  740. /********************************************************************/
  741. void Reset()
  742. {
  743. // Called when display changes
  744. // Remove any timing info from title bar, and reset the timer
  745. SetWindowText(auxGetHWND(), scene->drawController.GetDrawMethodName() );
  746. timer.Reset();
  747. }
  748. void NewTessLevel( int tessLevel )
  749. {
  750. static int oldTessLevel = 0; // to avoid unnecessary work
  751. // retesselate scene's object
  752. if( tessLevel == oldTessLevel )
  753. return;
  754. scene->NewObject( tessLevel );
  755. Reset();
  756. oldTessLevel = tessLevel;
  757. }
  758. void Redraw(void)
  759. {
  760. DRAW_CONTROLLER *pDrawControl = &scene->drawController;
  761. float trianglesPerSecond;
  762. timer.Start();
  763. // Draw the scene
  764. scene->Draw();
  765. if (fSingle)
  766. glFlush();
  767. else
  768. auxSwapBuffers();
  769. // Print timing information if Stop returns TRUE
  770. if( timer.Stop( pDrawControl->GetDrawObject()->TriangleCount(),
  771. &trianglesPerSecond ) ) {
  772. char szMsg[80];
  773. sprintf(szMsg, "%s: %.0lf tri/sec",
  774. pDrawControl->GetDrawMethodName(),
  775. trianglesPerSecond );
  776. // Print timing info in title bar
  777. SetWindowText(auxGetHWND(), szMsg);
  778. }
  779. }
  780. void Reshape(GLsizei w, GLsizei h)
  781. {
  782. glViewport(0, 0, w, h);
  783. Reset();
  784. }
  785. void Keyd(void)
  786. {
  787. scene->drawController.ToggleDisplayListDraw();
  788. Reset();
  789. }
  790. void Keyl(void)
  791. {
  792. scene->drawController.ToggleLighting();
  793. Reset();
  794. }
  795. void KeySPACE(void)
  796. {
  797. scene->drawController.CycleDrawMethod();
  798. Reset();
  799. }
  800. void KeyUp(void)
  801. {
  802. // increase tesselation
  803. tessLevel += tessInc;
  804. if( tessLevel > TESS_MAX )
  805. tessLevel = TESS_MAX;
  806. NewTessLevel( tessLevel );
  807. }
  808. void KeyDown(void)
  809. {
  810. // decrease tesselation
  811. tessLevel -= tessInc;
  812. if( tessLevel < TESS_MIN )
  813. tessLevel = TESS_MIN;
  814. NewTessLevel( tessLevel );
  815. }
  816. void __cdecl main(int argc, char **argv)
  817. {
  818. GLenum eMode;
  819. while (--argc > 0)
  820. {
  821. argv++;
  822. if (!strcmp(*argv, "-sb"))
  823. fSingle = TRUE;
  824. }
  825. auxInitPosition(10, 10, WIDTH, HEIGHT);
  826. eMode = AUX_RGB;
  827. if (!fSingle)
  828. {
  829. eMode |= AUX_DOUBLE;
  830. }
  831. auxInitDisplayMode(eMode);
  832. auxInitWindow("Vertex Array/Direct Comparison");
  833. auxReshapeFunc(Reshape);
  834. auxIdleFunc(Redraw);
  835. auxKeyFunc(AUX_l, Keyl);
  836. auxKeyFunc(AUX_d, Keyd);
  837. auxKeyFunc(AUX_SPACE, KeySPACE);
  838. auxKeyFunc(AUX_UP, KeyUp);
  839. auxKeyFunc(AUX_DOWN, KeyDown);
  840. // Create scene, with object(s)
  841. scene = new SCENE;
  842. // Start drawing
  843. auxMainLoop(Redraw);
  844. // Party's over
  845. delete scene;
  846. }