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.

1017 lines
27 KiB

  1. /******************************Module*Header*******************************\
  2. * Module Name: state.cxx
  3. *
  4. * STATE
  5. *
  6. * Copyright (c) 1995 Microsoft Corporation
  7. *
  8. \**************************************************************************/
  9. #include <stdio.h>
  10. #include <string.h>
  11. #include <stdlib.h>
  12. #include <math.h>
  13. #include <sys/types.h>
  14. #include <sys/timeb.h>
  15. #include <time.h>
  16. #include <windows.h>
  17. #include "sspipes.h"
  18. #include "dialog.h"
  19. #include "state.h"
  20. #include "pipe.h"
  21. #include "npipe.h"
  22. #include "fpipe.h"
  23. #include "eval.h"
  24. // default texture resource(s)
  25. #define DEF_TEX_COUNT 1
  26. TEX_RES gTexRes[DEF_TEX_COUNT] = {
  27. { TEX_BMP, IDB_DEFTEX }
  28. };
  29. static void InitTexParams();
  30. /******************************Public*Routine******************************\
  31. * STATE constructor
  32. *
  33. * - global state init
  34. * - translates variables set from the dialog boxes
  35. *
  36. \**************************************************************************/
  37. //mf: since pass bXXX params why not do same with ulSurfStyle, fTesselFact,
  38. // ulTexQual
  39. STATE::STATE( BOOL bFlexMode, BOOL bMultiPipes )
  40. {
  41. // various state values
  42. resetStatus = RESET_STARTUP_BIT;
  43. // Put initial hglrc in drawThreads[0]
  44. // This RC is also used for dlists and texture objects that are shared
  45. // by other RC's
  46. shareRC = wglGetCurrentContext();
  47. drawThreads[0].SetRCDC( shareRC, wglGetCurrentDC() );
  48. bTexture = FALSE;
  49. if( ulSurfStyle == SURFSTYLE_TEX ) {
  50. if( LoadTextureFiles( gTexFile, gnTextures, &gTexRes[0] ) )
  51. bTexture = TRUE;
  52. }
  53. else if( ulSurfStyle == SURFSTYLE_WIREFRAME ) {
  54. glPolygonMode( GL_FRONT_AND_BACK, GL_LINE );
  55. }
  56. // Initialize GL state for the initial RC (sets texture state, so
  57. // (must come after LoadTextureFiles())
  58. GLInit();
  59. // set 'reference' radius value
  60. radius = 1.0f;
  61. // convert tesselation from fTesselFact(0.0-2.0) to tessLevel(0-MAX_TESS)
  62. int tessLevel = (int) (fTesselFact * (MAX_TESS+1) / 2.0001f);
  63. nSlices = (tessLevel+2) * 4;
  64. // Allocate basic NODE_ARRAY
  65. // NODE_ARRAY size is determined in Reshape (based on window size)
  66. nodes = new NODE_ARRAY;
  67. // Set drawing mode, and initialize accordingly. For now, either all normal
  68. // or all flex pipes are drawn, but they could be combined later.
  69. // Can assume here that if there's any possibility that normal pipes
  70. // will be drawn, NORMAL_STATE will be initialized so that dlists are
  71. // built
  72. // Again, since have either NORMAL or FLEX, set maxPipesPerFrame,
  73. // maxDrawThreads
  74. if( bMultiPipes )
  75. maxDrawThreads = MAX_DRAW_THREADS;
  76. else
  77. maxDrawThreads = 1;
  78. nDrawThreads = 0; // no active threads yet
  79. nPipesDrawn = 0;
  80. // maxPipesPerFrame is set in Reset()
  81. if( bFlexMode ) {
  82. drawMode = DRAW_FLEX;
  83. pFState = new FLEX_STATE( this );
  84. pNState = NULL;
  85. } else {
  86. drawMode = DRAW_NORMAL;
  87. pNState = new NORMAL_STATE( this );
  88. pFState = NULL;
  89. }
  90. // initialize materials
  91. if( bTexture )
  92. ss_InitTexMaterials();
  93. else
  94. ss_InitTeaMaterials();
  95. // default draw scheme
  96. drawScheme = FRAME_SCHEME_RANDOM;
  97. }
  98. /******************************Public*Routine******************************\
  99. * STATE destructor
  100. *
  101. \**************************************************************************/
  102. STATE::~STATE( )
  103. {
  104. if( pNState )
  105. delete pNState;
  106. if( pFState )
  107. delete pFState;
  108. if( nodes )
  109. delete nodes;
  110. if( bTexture ) {
  111. for( int i = 0; i < nTextures; i ++ ) {
  112. ss_DeleteTexture( &texture[i] );
  113. }
  114. }
  115. // Delete any RC's - should be done by ~THREAD, but since common lib
  116. // deletes shareRC, have to do it here
  117. DRAW_THREAD *pdt = &drawThreads[0];
  118. for( int i = 0; i < MAX_DRAW_THREADS; i ++, pdt++ ) {
  119. if( pdt->hglrc && (pdt->hglrc != shareRC) ) {
  120. wglDeleteContext( pdt->hglrc );
  121. }
  122. }
  123. }
  124. /******************************Public*Routine******************************\
  125. * CalcTexRepFactors
  126. *
  127. \**************************************************************************/
  128. void
  129. STATE::CalcTexRepFactors()
  130. {
  131. ISIZE winSize;
  132. POINT2D texFact;
  133. ss_GetScreenSize( &winSize );
  134. // Figure out repetition factor of texture, based on bitmap size and
  135. // screen size.
  136. //
  137. // We arbitrarily decide to repeat textures that are smaller than
  138. // 1/8th of screen width or height.
  139. for( int i = 0; i < nTextures; i++ ) {
  140. texRep[i].x = texRep[i].y = 1;
  141. if( (texFact.x = winSize.width / texture[i].width / 8.0f) >= 1.0f)
  142. texRep[i].x = (int) (texFact.x+0.5f);
  143. if( (texFact.y = winSize.height / texture[i].height / 8.0f) >= 1.0f)
  144. texRep[i].y = (int) (texFact.y+0.5f);
  145. }
  146. // ! If display list based normal pipes, texture repetition is embedded
  147. // in the dlists and can't be changed. So use the smallest rep factors.
  148. // mf: Should change this so smaller textures are replicated close to
  149. // the largest texture, then same rep factor will work well for all
  150. if( pNState ) {
  151. //put smallest rep factors in texRep[0]; (mf:this is ok for now, as
  152. // flex pipes and normal pipes don't coexist)
  153. for( i = 1; i < nTextures; i++ ) {
  154. if( texRep[i].x < texRep[0].x )
  155. texRep[0].x = texRep[i].x;
  156. if( texRep[i].y < texRep[0].y )
  157. texRep[0].y = texRep[i].y;
  158. }
  159. }
  160. }
  161. /******************************Public*Routine******************************\
  162. * LoadTextureFiles
  163. *
  164. * - Load user texture files. If texturing on but no user textures, or
  165. * problems loading them, load default texture resource
  166. * mf: later, may want to have > 1 texture resource
  167. *
  168. \**************************************************************************/
  169. BOOL
  170. STATE::LoadTextureFiles( TEXFILE *pTexFile, int nTexFiles, TEX_RES *pTexRes )
  171. {
  172. // Set pixel store state
  173. glPixelStorei(GL_UNPACK_ALIGNMENT, 1);
  174. // Try to load the bmp or rgb file
  175. // i counts successfully loaded textures
  176. for( int i = 0; nTexFiles; nTexFiles-- ) {
  177. if( ss_LoadTextureFile( &pTexFile[i], &texture[i] ) ) {
  178. // If texture object extension, set tex params here for each object
  179. if( ss_TextureObjectsEnabled() )
  180. InitTexParams();
  181. i++; // count another valid texture
  182. }
  183. }
  184. // set number of valid textures in state
  185. nTextures = i;
  186. if( nTextures == 0 ) {
  187. // No user textures, or none loaded successfully
  188. // Load default resource texture(s)
  189. nTextures = DEF_TEX_COUNT;
  190. for( i = 0; i < nTextures; i++, pTexRes++ ) {
  191. if( !ss_LoadTextureResource( pTexRes, &texture[i] ) ) {
  192. // shouldn't happen
  193. return FALSE;
  194. }
  195. }
  196. }
  197. CalcTexRepFactors();
  198. return TRUE;
  199. }
  200. /******************************Public*Routine******************************\
  201. * GLInit
  202. *
  203. * - Sets up GL state
  204. * - Called once for every context (rc)
  205. *
  206. \**************************************************************************/
  207. void
  208. STATE::GLInit()
  209. {
  210. static float ambient[] = {0.1f, 0.1f, 0.1f, 1.0f};
  211. static float diffuse[] = {1.0f, 1.0f, 1.0f, 1.0f};
  212. static float position[] = {90.0f, 90.0f, 150.0f, 0.0f};
  213. static float lmodel_ambient[] = {1.0f, 1.0f, 1.0f, 1.0f};
  214. static float lmodel_ambientTex[] = {0.6f, 0.6f, 0.6f, 0.0f};
  215. static float back_mat_diffuse[] = {0.0f, 0.0f, 1.0f};
  216. glClearColor(0.0f, 0.0f, 0.0f, 0.0f);
  217. glFrontFace(GL_CCW);
  218. glDepthFunc(GL_LEQUAL);
  219. glEnable(GL_DEPTH_TEST);
  220. glEnable( GL_AUTO_NORMAL ); // needed for GL_MAP2_VERTEX (tea)
  221. if( bTexture )
  222. glLightModelfv(GL_LIGHT_MODEL_AMBIENT, lmodel_ambientTex);
  223. else
  224. glLightModelfv(GL_LIGHT_MODEL_AMBIENT, lmodel_ambient);
  225. glLightfv(GL_LIGHT0, GL_AMBIENT, ambient);
  226. glLightfv(GL_LIGHT0, GL_DIFFUSE, diffuse);
  227. glLightfv(GL_LIGHT0, GL_POSITION, position);
  228. glEnable(GL_LIGHT0);
  229. glEnable(GL_LIGHTING);
  230. #if 1
  231. glCullFace(GL_BACK);
  232. glEnable(GL_CULL_FACE);
  233. #else
  234. // debug
  235. // back material for debugging
  236. glMaterialfv(GL_BACK, GL_DIFFUSE, back_mat_diffuse);
  237. glLightModeli(GL_LIGHT_MODEL_TWO_SIDE, GL_TRUE );
  238. #endif
  239. // Set texture modes
  240. if( bTexture ) {
  241. glEnable(GL_TEXTURE_2D);
  242. glTexEnvi(GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_MODULATE);
  243. InitTexParams();
  244. }
  245. }
  246. /**************************************************************************\
  247. * InitTexParams
  248. *
  249. * Set texture parameters, globally, or per object if texture object extension
  250. *
  251. \**************************************************************************/
  252. static void
  253. InitTexParams()
  254. {
  255. glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_REPEAT);
  256. glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_REPEAT);
  257. switch( ulTexQuality ) {
  258. case TEXQUAL_HIGH:
  259. glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
  260. glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
  261. break;
  262. case TEXQUAL_DEFAULT:
  263. default:
  264. glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST);
  265. glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST);
  266. break;
  267. }
  268. }
  269. /**************************************************************************\
  270. * Repaint
  271. *
  272. * This is called when a WM_PAINT msg has been sent to the window. The paint
  273. * will overwrite the frame buffer, screwing up the scene if pipes is in single
  274. * buffer mode. We set resetStatus accordingly to clear things up on next
  275. * draw.
  276. *
  277. \**************************************************************************/
  278. void
  279. STATE::Repaint( LPRECT pRect, void *data)
  280. {
  281. resetStatus |= RESET_REPAINT_BIT;
  282. }
  283. /**************************************************************************\
  284. * Reshape
  285. * - called on resize, expose
  286. * - always called on app startup
  287. * - set new window size for VIEW object, and set resetStatus for validation
  288. * at draw time
  289. *
  290. \**************************************************************************/
  291. void
  292. STATE::Reshape(int width, int height, void *data)
  293. {
  294. if( view.SetWinSize( width, height ) )
  295. resetStatus |= RESET_RESIZE_BIT;
  296. }
  297. /**************************************************************************\
  298. * ResetView
  299. *
  300. * Called on FrameReset resulting from change in viewing paramters (e.g. from
  301. * a Resize event).
  302. \**************************************************************************/
  303. void
  304. STATE::ResetView()
  305. {
  306. IPOINT3D numNodes;
  307. // Have VIEW calculate the node array size based on view params
  308. view.CalcNodeArraySize( &numNodes );
  309. // Resize the node array
  310. nodes->Resize( &numNodes );
  311. // Set GL viewing parameters for each active RC
  312. DRAW_THREAD *pThread = drawThreads;
  313. for( int i = 0; i < MAX_DRAW_THREADS; i ++, pThread++ ) {
  314. if( pThread->HasRC() ) {
  315. pThread->MakeRCCurrent();
  316. view.SetGLView();
  317. }
  318. }
  319. }
  320. /**************************************************************************\
  321. * FrameReset
  322. *
  323. * Start a new frame of pipes
  324. *
  325. * The resetStatus parameter indicates what triggered the Reset.
  326. *
  327. \**************************************************************************/
  328. static int PickRandomTexture( int i, int nTextures );
  329. void
  330. STATE::FrameReset()
  331. {
  332. int i;
  333. float xRot, zRot;
  334. PIPE *pNewPipe;
  335. #ifdef DO_TIMING
  336. Timer( TIMER_STOP );
  337. #endif
  338. SS_DBGINFO( "Pipes STATE::FrameReset:\n" );
  339. // Kill off any active pipes ! (so they can shut down ok)
  340. DRAW_THREAD *pThread = drawThreads;
  341. for( i = 0; i < nDrawThreads; i ++, pThread++ ) {
  342. pThread->KillPipe();
  343. }
  344. nDrawThreads = 0;
  345. // Clear the screen
  346. Clear();
  347. // Check for window resize status
  348. if( resetStatus & RESET_RESIZE_BIT ) {
  349. ResetView();
  350. }
  351. // Reset the node states to empty
  352. nodes->Reset();
  353. // Call any pipe-specific state resets, and get any recommended
  354. // pipesPerFrame counts
  355. if( pNState ) {
  356. pNState->Reset();
  357. }
  358. if( pFState ) {
  359. pFState->Reset();
  360. //mf: maybe should figure out min spherical view dist
  361. xRot = ss_fRand(-5.0f, 5.0f);
  362. zRot = ss_fRand(-5.0f, 5.0f);
  363. }
  364. maxPipesPerFrame = CalcMaxPipesPerFrame();
  365. // Set new number of drawing threads
  366. if( maxDrawThreads > 1 ) {
  367. // Set maximum # of pipes per frame
  368. maxPipesPerFrame = (int) (maxPipesPerFrame * 1.5);
  369. // Set # of draw threads
  370. nDrawThreads = SS_MIN( maxPipesPerFrame, ss_iRand2( 2, maxDrawThreads ) );
  371. // Set chase mode if applicable, every now and then
  372. BOOL bUseChase = pNState || (pFState && pFState->OKToUseChase());
  373. if( bUseChase && (!ss_iRand(5)) ) {
  374. drawScheme = FRAME_SCHEME_CHASE;
  375. }
  376. } else {
  377. nDrawThreads = 1;
  378. }
  379. nPipesDrawn = 0;
  380. // for now, either all NORMAL or all FLEX for each frame
  381. pThread = drawThreads;
  382. for( i = 0; i < nDrawThreads; i ++, pThread++ ) {
  383. // Create hglrc if necessary, and init it
  384. if( !pThread->HasRC() ) {
  385. HDC hdc = wglGetCurrentDC();
  386. pThread->SetRCDC( wglCreateContext( hdc ), hdc );
  387. // also need to init each RC
  388. pThread->MakeRCCurrent();
  389. #if 0
  390. //mf: should get this working
  391. wglCopyContext( drawThreads[0].GetRC(), pThread->GetRC(), 0xffff );
  392. #endif
  393. // Do GL Init for this new RC
  394. GLInit();
  395. // Set viewing params
  396. view.SetGLView();
  397. // Give this rc access to any dlists
  398. wglShareLists( shareRC, pThread->GetRC() );
  399. }
  400. else
  401. pThread->MakeRCCurrent();
  402. // Set up the modeling view
  403. glLoadIdentity();
  404. glTranslatef(0.0f, 0.0f, view.zTrans);
  405. // Rotate Scene
  406. glRotatef( view.yRot, 0.0f, 1.0f, 0.0f );
  407. // create approppriate pipe for this thread slot
  408. switch( drawMode ) {
  409. case DRAW_NORMAL:
  410. pNewPipe = (PIPE *) new NORMAL_PIPE(this);
  411. break;
  412. case DRAW_FLEX:
  413. // There are several kinds of FLEX pipes - have FLEX_STATE
  414. // decide which one to create
  415. pNewPipe = pFState->NewPipe( this );
  416. // rotate a bit around x and z as well
  417. // mf: ! If combining NORMAL and FLEX, same rotations must be
  418. // applied to both
  419. glRotatef( xRot, 1.0f, 0.0f, 0.0f );
  420. glRotatef( zRot, 0.0f, 0.0f, 1.0f );
  421. break;
  422. }
  423. pThread->SetPipe( pNewPipe );
  424. if( drawScheme == FRAME_SCHEME_CHASE ) {
  425. if( i == 0 ) {
  426. // this will be the lead pipe
  427. pLeadPipe = pNewPipe;
  428. pNewPipe->SetChooseDirectionMethod( CHOOSE_DIR_RANDOM_WEIGHTED );
  429. } else {
  430. pNewPipe->SetChooseDirectionMethod( CHOOSE_DIR_CHASE );
  431. }
  432. }
  433. // If texturing, pick a random texture for this thread
  434. if( bTexture ) {
  435. int index = PickRandomTexture( i, nTextures );
  436. pThread->SetTexture( &texture[index] );
  437. // Flex pipes need to be informed of the texture, so they
  438. // can dynamically calculate various texture params
  439. if( pFState )
  440. ((FLEX_PIPE *) pNewPipe)->SetTexParams( &texture[index],
  441. &texRep[index] );
  442. }
  443. // Launch the pipe (assumed: always more nodes than pipes starting, so
  444. // StartPipe cannot fail)
  445. // ! All pipe setup needs to be done before we call StartPipe, as this
  446. // is where the pipe starts drawing
  447. pThread->StartPipe();
  448. // Kind of klugey, but if in chase mode, I set chooseStartPos here,
  449. // since first startPos used in StartPipe() should be random
  450. if( (i == 0) && (drawScheme == FRAME_SCHEME_CHASE) )
  451. pNewPipe->SetChooseStartPosMethod( CHOOSE_STARTPOS_FURTHEST );
  452. nPipesDrawn++;
  453. }
  454. // Increment scene rotation for normal reset case
  455. if( resetStatus & RESET_NORMAL_BIT )
  456. view.IncrementSceneRotation();
  457. // clear reset status
  458. resetStatus = 0;
  459. #ifdef DO_TIMING
  460. Timer( TIMER_START );
  461. #endif
  462. }
  463. /**************************************************************************\
  464. * CalcMaxPipesPerFrame
  465. *
  466. \**************************************************************************/
  467. int
  468. STATE::CalcMaxPipesPerFrame()
  469. {
  470. int nCount=0, fCount=0;
  471. if( pFState )
  472. fCount = pFState->GetMaxPipesPerFrame();
  473. if( pNState )
  474. nCount = bTexture ? NORMAL_TEX_PIPE_COUNT : NORMAL_PIPE_COUNT;
  475. return SS_MAX( nCount, fCount );
  476. }
  477. /**************************************************************************\
  478. * PickRandomTexture
  479. *
  480. * Pick a random texture index from a list. Remove entry from list as it
  481. * is picked. Once all have been picked, or starting a new frame, reset.
  482. *
  483. * ! Routine not reentrant, should only be called by the main thread
  484. * dispatcher (FrameReset)
  485. \**************************************************************************/
  486. static int
  487. PickRandomTexture( int iThread, int nTextures )
  488. {
  489. if( nTextures == 0 )
  490. return 0;
  491. static int pickSet[MAX_TEXTURES] = {0};
  492. static int nPicked = 0;
  493. int i, index;
  494. if( iThread == 0 )
  495. // new frame - force reset
  496. nPicked = nTextures;
  497. // reset condition
  498. if( ++nPicked > nTextures ) {
  499. for( i = 0; i < nTextures; i ++ ) pickSet[i] = 0;
  500. nPicked = 1; // cuz
  501. }
  502. // Pick a random texture index
  503. index = ss_iRand( nTextures );
  504. while( pickSet[index] ) {
  505. // this index has alread been taken, try the next one
  506. if( ++index >= nTextures )
  507. index = 0;
  508. }
  509. // Hopefully, the above loop will exit :). This means that we have
  510. // found a texIndex that is available
  511. pickSet[index] = 1; // mark as taken
  512. return index;
  513. }
  514. /**************************************************************************\
  515. * Clear
  516. *
  517. * Clear the screen. Depending on resetStatus, use normal clear or
  518. * fancy transitional clear.
  519. \**************************************************************************/
  520. void
  521. STATE::Clear()
  522. {
  523. // clear the screen - any rc will do
  524. glClear(GL_DEPTH_BUFFER_BIT);
  525. if( resetStatus & RESET_RESIZE_BIT ) {
  526. // new window size - recalibrate the transitional clear
  527. // Calibration is set after a window resize, so window is already black
  528. ddClear.CalibrateClear( view.winSize.width, view.winSize.height, 2.0f );
  529. } else if( resetStatus & RESET_NORMAL_BIT )
  530. // do the normal transitional clear
  531. ddClear.Clear( view.winSize.width, view.winSize.height );
  532. else {
  533. // do a fast one-shot clear
  534. glClear( GL_COLOR_BUFFER_BIT );
  535. }
  536. }
  537. /**************************************************************************\
  538. * DrawValidate
  539. *
  540. * Validation done before every Draw
  541. *
  542. * For now, this just involves checking resetStatus
  543. *
  544. \**************************************************************************/
  545. void
  546. STATE::DrawValidate()
  547. {
  548. if( ! resetStatus )
  549. return;
  550. FrameReset();
  551. }
  552. /**************************************************************************\
  553. * Draw
  554. *
  555. * - Top-level pipe drawing routine
  556. * - Each pipe thread keeps drawing new pipes until we reach maximum number
  557. * of pipes per frame - then each thread gets killed as soon as it gets
  558. * stuck. Once number of drawing threads reaches 0, we start a new
  559. * frame
  560. *
  561. \**************************************************************************/
  562. void
  563. STATE::Draw(void *data)
  564. {
  565. int nKilledThreads = 0;
  566. BOOL bChooseNewLead = FALSE;
  567. // Validate the draw state
  568. DrawValidate();
  569. // Check each pipe's status
  570. DRAW_THREAD *pThread = drawThreads;
  571. for( int i = 0; i < nDrawThreads; i++, pThread++ ) {
  572. if( pThread->pPipe->IsStuck() ) {
  573. if( ++nPipesDrawn > maxPipesPerFrame ) {
  574. // Reaching pipe saturation - kill this pipe thread
  575. if( (drawScheme == FRAME_SCHEME_CHASE) &&
  576. (pThread->pPipe == pLeadPipe) )
  577. bChooseNewLead = TRUE;
  578. pThread->KillPipe();
  579. nKilledThreads++;
  580. } else {
  581. // Start up another pipe
  582. if( ! pThread->StartPipe() )
  583. // we won't be able to draw any more pipes this frame
  584. // (probably out of nodes)
  585. maxPipesPerFrame = nPipesDrawn;
  586. }
  587. }
  588. }
  589. // Whenever one or more pipes are killed, compact the thread list
  590. if( nKilledThreads ) {
  591. CompactThreadList();
  592. nDrawThreads -= nKilledThreads;
  593. }
  594. if( nDrawThreads == 0 ) {
  595. // This frame is finished - mark for reset on next Draw
  596. resetStatus |= RESET_NORMAL_BIT;
  597. return;
  598. }
  599. if( bChooseNewLead ) {
  600. // We're in 'chase mode' and need to pick a new lead pipe
  601. ChooseNewLeadPipe();
  602. }
  603. // Draw each pipe
  604. for( i = 0, pThread = drawThreads; i < nDrawThreads; i++, pThread++ ) {
  605. pThread->DrawPipe();
  606. #ifdef DO_TIMING
  607. pipeCount++;
  608. #endif
  609. }
  610. glFlush();
  611. }
  612. /**************************************************************************\
  613. *
  614. * CompactThreadList
  615. *
  616. * - Compact the thread list according to number of pipe threads killed
  617. * - The pipes have been killed, but the RC's in each slot are still valid
  618. * and reusable. So we swap up entries with valid pipes. This means that
  619. * the ordering of the RC's in the thread list will change during the life
  620. * of the program. This should be OK.
  621. *
  622. \**************************************************************************/
  623. #define SWAP_SLOT( a, b ) \
  624. DRAW_THREAD pTemp; \
  625. pTemp = *(a); \
  626. *(a) = *(b); \
  627. *(b) = pTemp;
  628. void
  629. STATE::CompactThreadList()
  630. {
  631. if( nDrawThreads <= 1 )
  632. // If only one active thread, it must be in slot 0 from previous
  633. // compactions - so nothing to do
  634. return;
  635. int iEmpty = 0;
  636. DRAW_THREAD *pThread = drawThreads;
  637. for( int i = 0; i < nDrawThreads; i ++, pThread++ ) {
  638. if( pThread->pPipe ) {
  639. if( iEmpty < i ) {
  640. // swap active pipe thread and empty slot
  641. SWAP_SLOT( &(drawThreads[iEmpty]), pThread );
  642. }
  643. iEmpty++;
  644. }
  645. }
  646. }
  647. /**************************************************************************\
  648. *
  649. * ChooseNewLeadPipe
  650. *
  651. * Choose a new lead pipe for chase mode.
  652. *
  653. \**************************************************************************/
  654. void
  655. STATE::ChooseNewLeadPipe()
  656. {
  657. // Pick one of the active pipes at random to become the new lead
  658. int iLead = ss_iRand( nDrawThreads );
  659. pLeadPipe = drawThreads[iLead].pPipe;
  660. pLeadPipe->SetChooseStartPosMethod( CHOOSE_STARTPOS_FURTHEST );
  661. pLeadPipe->SetChooseDirectionMethod( CHOOSE_DIR_RANDOM_WEIGHTED );
  662. }
  663. /******************************Public*Routine******************************\
  664. * Finish
  665. *
  666. * - Called when GL window being closed
  667. *
  668. \**************************************************************************/
  669. void
  670. STATE::Finish( void *data )
  671. {
  672. delete (STATE *) data;
  673. }
  674. /**************************************************************************\
  675. * DRAW_THREAD constructor
  676. *
  677. \**************************************************************************/
  678. DRAW_THREAD::DRAW_THREAD()
  679. {
  680. hdc = 0;
  681. hglrc = 0;
  682. pPipe = NULL;
  683. htex = (HTEXTURE) -1;
  684. }
  685. /**************************************************************************\
  686. * DRAW_THREAD destructor
  687. *
  688. * Delete any GL contexts
  689. *
  690. * - can't Delete shareRC, as this is done by common lib, so had to move
  691. * this up to ~STATE
  692. *
  693. \**************************************************************************/
  694. DRAW_THREAD::~DRAW_THREAD()
  695. {
  696. #if 0
  697. wglDeleteContext( hglrc );
  698. #endif
  699. }
  700. /**************************************************************************\
  701. * MakeRCCurrent
  702. *
  703. \**************************************************************************/
  704. void
  705. DRAW_THREAD::MakeRCCurrent()
  706. {
  707. if( hglrc != wglGetCurrentContext() )
  708. wglMakeCurrent( hdc, hglrc );
  709. }
  710. /**************************************************************************\
  711. * SetRCDC
  712. *
  713. \**************************************************************************/
  714. void
  715. DRAW_THREAD::SetRCDC( HGLRC rc, HDC Hdc )
  716. {
  717. hglrc = rc;
  718. hdc = Hdc;
  719. }
  720. /**************************************************************************\
  721. * SetPipe
  722. *
  723. \**************************************************************************/
  724. void
  725. DRAW_THREAD::SetPipe( PIPE *pipe )
  726. {
  727. pPipe = pipe;
  728. }
  729. /**************************************************************************\
  730. * HasRC
  731. *
  732. \**************************************************************************/
  733. BOOL
  734. DRAW_THREAD::HasRC()
  735. {
  736. return( hglrc != 0 );
  737. }
  738. /**************************************************************************\
  739. * GetRC
  740. *
  741. \**************************************************************************/
  742. HGLRC
  743. DRAW_THREAD::GetRC()
  744. {
  745. return hglrc;
  746. }
  747. /**************************************************************************\
  748. * SetTexture
  749. *
  750. * - Set a texture for a thread
  751. * - Cache the texture index for performance
  752. \**************************************************************************/
  753. void
  754. DRAW_THREAD::SetTexture( HTEXTURE hnewtex )
  755. {
  756. if( hnewtex != htex )
  757. {
  758. htex = hnewtex;
  759. ss_SetTexture( htex );
  760. }
  761. }
  762. /**************************************************************************\
  763. * DrawPipe
  764. *
  765. * - Draw pipe in thread slot, according to its type
  766. *
  767. \**************************************************************************/
  768. void
  769. DRAW_THREAD::DrawPipe()
  770. {
  771. MakeRCCurrent();
  772. switch( pPipe->type ) {
  773. case TYPE_NORMAL:
  774. ( (NORMAL_PIPE *) pPipe )->Draw();
  775. break;
  776. case TYPE_FLEX_REGULAR:
  777. ( (REGULAR_FLEX_PIPE *) pPipe )->Draw();
  778. break;
  779. case TYPE_FLEX_TURNING:
  780. ( (TURNING_FLEX_PIPE *) pPipe )->Draw();
  781. break;
  782. }
  783. glFlush();
  784. }
  785. /**************************************************************************\
  786. * StartPipe
  787. *
  788. * Starts up pipe of the approppriate type. If can't find an empty node
  789. * for the pipe to start on, returns FALSE;
  790. *
  791. \**************************************************************************/
  792. BOOL
  793. DRAW_THREAD::StartPipe()
  794. {
  795. MakeRCCurrent();
  796. // call pipe-type specific Start function
  797. switch( pPipe->type ) {
  798. case TYPE_NORMAL:
  799. ( (NORMAL_PIPE *) pPipe )->Start();
  800. break;
  801. case TYPE_FLEX_REGULAR:
  802. ( (REGULAR_FLEX_PIPE *) pPipe )->Start();
  803. break;
  804. case TYPE_FLEX_TURNING:
  805. ( (TURNING_FLEX_PIPE *) pPipe )->Start();
  806. break;
  807. }
  808. glFlush();
  809. // check status
  810. if( pPipe->NowhereToRun() )
  811. return FALSE;
  812. else
  813. return TRUE;
  814. }
  815. /**************************************************************************\
  816. * KillPipe
  817. *
  818. \**************************************************************************/
  819. void
  820. DRAW_THREAD::KillPipe()
  821. {
  822. switch( pPipe->type ) {
  823. case TYPE_NORMAL:
  824. delete (NORMAL_PIPE *) pPipe;
  825. break;
  826. case TYPE_FLEX_REGULAR:
  827. delete (REGULAR_FLEX_PIPE *) pPipe;
  828. break;
  829. case TYPE_FLEX_TURNING:
  830. delete (TURNING_FLEX_PIPE *) pPipe;
  831. break;
  832. }
  833. pPipe = NULL;
  834. }