Team Fortress 2 Source Code as on 22/4/2020
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.

1427 lines
33 KiB

  1. //========= Copyright Valve Corporation, All rights reserved. ============//
  2. //
  3. // Purpose:
  4. //
  5. // $NoKeywords: $
  6. //
  7. //=============================================================================//
  8. #include "glos.h"
  9. #include <gl/gl.h>
  10. #if _MSC_VER < 1600
  11. #include <gl/glaux.h>
  12. #endif
  13. #include <gl/glu.h>
  14. #include <stdarg.h>
  15. #include <string.h>
  16. #include <stdio.h>
  17. #include <math.h>
  18. #include "cmdlib.h"
  19. #include "mathlib/mathlib.h"
  20. #include "cmodel.h"
  21. #include "tier1/strtools.h"
  22. #include "physdll.h"
  23. #include "phyfile.h"
  24. #include "vphysics_interface.h"
  25. #include "tier0/icommandline.h"
  26. #include "tier0/vprof.h"
  27. HDC camdc;
  28. HGLRC baseRC;
  29. HWND camerawindow;
  30. HANDLE main_instance;
  31. /* YWB: 3/13/98
  32. You run the program like normal with any file. If you want to read portals for the
  33. file type, you type: glview -portal filename.gl0 (or whatever). glview will then
  34. try to read in the .prt file filename.prt.
  35. The portals are shown as white lines superimposed over your image. You can toggle the
  36. view between showing portals or not by hitting the '2' key. The '1' key toggles
  37. world polygons.
  38. The 'b' key toggles blending modes.
  39. If you don't want to depth buffer the portals, hit 'p'.
  40. The command line parsing is inelegant but functional.
  41. I sped up the KB movement and turn speed, too.
  42. */
  43. // Vars added by YWB
  44. Vector g_Center; // Center of all read points, so camera is in a sensible place
  45. int g_nTotalPoints = 0; // Total points read, for calculating center
  46. int g_UseBlending = 0; // Toggle to use blending mode or not
  47. BOOL g_bReadPortals = 0; // Did we read in a portal file?
  48. BOOL g_bNoDepthPortals = 0; // Do we zbuffer the lines of the portals?
  49. int g_nPortalHighlight = -1; // The leaf we're viewing
  50. int g_nLeafHighlight = -1; // The leaf we're viewing
  51. BOOL g_bShowList1 = 1; // Show regular polygons?
  52. BOOL g_bShowList2 = 1; // Show portals?
  53. BOOL g_bShowLines = 0; // Show outlines of faces
  54. BOOL g_Active = TRUE;
  55. BOOL g_Update = TRUE;
  56. BOOL g_bDisp = FALSE;
  57. IPhysicsCollision *physcollision = NULL;
  58. // -----------
  59. static int g_Keys[256];
  60. void AppKeyDown( int key );
  61. void AppKeyUp( int key );
  62. BOOL ReadDisplacementFile( const char *filename );
  63. void DrawDisplacementData( void );
  64. #define BENCHMARK_PHY 0
  65. /*
  66. =================
  67. Error
  68. For abnormal program terminations
  69. =================
  70. */
  71. void Error (char *error, ...)
  72. {
  73. va_list argptr;
  74. char text[1024];
  75. va_start (argptr,error);
  76. vsprintf (text, error,argptr);
  77. va_end (argptr);
  78. MessageBox(NULL, text, "Error", 0 /* MB_OK */ );
  79. exit (1);
  80. }
  81. float origin[3] = {32, 32, 48};
  82. float angles[3];
  83. float forward[3], right[3], vup[3], vpn[3], vright[3];
  84. float width = 1024;
  85. float height = 768;
  86. float g_flMovementSpeed = 320.f; // Units / second (run speed of HL)
  87. #define SPEED_TURN 90 // Degrees / second
  88. #define VK_COMMA 188
  89. #define VK_PERIOD 190
  90. void KeyDown (int key)
  91. {
  92. switch (key)
  93. {
  94. case VK_ESCAPE:
  95. g_Active = FALSE;
  96. break;
  97. case VK_F1:
  98. glEnable (GL_CULL_FACE);
  99. glCullFace (GL_FRONT);
  100. break;
  101. case 'B':
  102. g_UseBlending ^= 1;
  103. if (g_UseBlending)
  104. glEnable(GL_BLEND);// YWB TESTING
  105. else
  106. glDisable(GL_BLEND);
  107. break;
  108. case '1':
  109. g_bShowList1 ^= 1;
  110. break;
  111. case '2':
  112. g_bShowList2 ^= 1;
  113. break;
  114. case 'P':
  115. g_bNoDepthPortals ^= 1;
  116. break;
  117. case 'L':
  118. g_bShowLines ^= 1;
  119. break;
  120. }
  121. g_Update = TRUE;
  122. }
  123. static BOOL g_Capture = FALSE;
  124. #define MOUSE_SENSITIVITY 0.2f
  125. #define MOUSE_SENSITIVITY_X (MOUSE_SENSITIVITY*1)
  126. #define MOUSE_SENSITIVITY_Y (MOUSE_SENSITIVITY*1)
  127. void Cam_MouseMoved( void )
  128. {
  129. if ( g_Capture )
  130. {
  131. RECT rect;
  132. int centerx, centery;
  133. float deltax, deltay;
  134. POINT cursorPoint;
  135. GetWindowRect( camerawindow, &rect );
  136. if ( rect.top < 0)
  137. rect.top = 0;
  138. if ( rect.left < 0)
  139. rect.left = 0;
  140. centerx = ( rect.left + rect.right ) / 2;
  141. centery = ( rect.top + rect.bottom ) / 2;
  142. GetCursorPos( &cursorPoint );
  143. SetCursorPos( centerx, centery );
  144. deltax = (cursorPoint.x - centerx) * MOUSE_SENSITIVITY_X;
  145. deltay = (cursorPoint.y - centery) * MOUSE_SENSITIVITY_Y;
  146. angles[1] -= deltax;
  147. angles[0] -= deltay;
  148. g_Update = TRUE;
  149. }
  150. }
  151. int Test_Key( int key )
  152. {
  153. int r = (g_Keys[ key ] != 0);
  154. g_Keys[ key ] &= 0x01; // clear out debounce bit
  155. if (r)
  156. g_Update = TRUE;
  157. return r;
  158. }
  159. // UNDONE: Probably should change the controls to match the game - but I don't know who relies on them
  160. // as of now.
  161. void Cam_Update( float frametime )
  162. {
  163. if ( Test_Key( 'W' ) )
  164. {
  165. VectorMA (origin, g_flMovementSpeed*frametime, vpn, origin);
  166. }
  167. if ( Test_Key( 'S' ) )
  168. {
  169. VectorMA (origin, -g_flMovementSpeed*frametime, vpn, origin);
  170. }
  171. if ( Test_Key( 'A' ) )
  172. {
  173. VectorMA (origin, -g_flMovementSpeed*frametime, vright, origin);
  174. }
  175. if ( Test_Key( 'D' ) )
  176. {
  177. VectorMA (origin, g_flMovementSpeed*frametime, vright, origin);
  178. }
  179. if ( Test_Key( VK_UP ) )
  180. {
  181. VectorMA (origin, g_flMovementSpeed*frametime, forward, origin);
  182. }
  183. if ( Test_Key( VK_DOWN ) )
  184. {
  185. VectorMA (origin, -g_flMovementSpeed*frametime, forward, origin);
  186. }
  187. if ( Test_Key( VK_LEFT ) )
  188. {
  189. angles[1] += SPEED_TURN * frametime;
  190. }
  191. if ( Test_Key( VK_RIGHT ) )
  192. {
  193. angles[1] -= SPEED_TURN * frametime;
  194. }
  195. if ( Test_Key( 'F' ) )
  196. {
  197. origin[2] += g_flMovementSpeed*frametime;
  198. }
  199. if ( Test_Key( 'C' ) )
  200. {
  201. origin[2] -= g_flMovementSpeed*frametime;
  202. }
  203. if ( Test_Key( VK_INSERT ) )
  204. {
  205. angles[0] += SPEED_TURN * frametime;
  206. if (angles[0] > 85)
  207. angles[0] = 85;
  208. }
  209. if ( Test_Key( VK_DELETE ) )
  210. {
  211. angles[0] -= SPEED_TURN * frametime;
  212. if (angles[0] < -85)
  213. angles[0] = -85;
  214. }
  215. Cam_MouseMoved();
  216. }
  217. void Cam_BuildMatrix (void)
  218. {
  219. float xa, ya;
  220. float matrix[4][4];
  221. int i;
  222. xa = angles[0]/180*M_PI;
  223. ya = angles[1]/180*M_PI;
  224. // the movement matrix is kept 2d ?? do we want this?
  225. forward[0] = cos(ya);
  226. forward[1] = sin(ya);
  227. right[0] = forward[1];
  228. right[1] = -forward[0];
  229. glGetFloatv (GL_PROJECTION_MATRIX, &matrix[0][0]);
  230. for (i=0 ; i<3 ; i++)
  231. {
  232. vright[i] = matrix[i][0];
  233. vup[i] = matrix[i][1];
  234. vpn[i] = matrix[i][2];
  235. }
  236. VectorNormalize (vright);
  237. VectorNormalize (vup);
  238. VectorNormalize (vpn);
  239. }
  240. void Draw (void)
  241. {
  242. float screenaspect;
  243. float yfov;
  244. //glClearColor (0.5, 0.5, 0.5, 0);
  245. glClearColor(0.0, 0.0, 0.0, 0); // Black Clearing YWB
  246. glClear (GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
  247. //
  248. // set up viewpoint
  249. //
  250. glMatrixMode(GL_PROJECTION);
  251. glLoadIdentity ();
  252. screenaspect = (float)width/height;
  253. yfov = 2*atan((float)height/width)*180/M_PI;
  254. gluPerspective (yfov, screenaspect, 6, 20000);
  255. glRotatef (-90, 1, 0, 0); // put Z going up
  256. glRotatef (90, 0, 0, 1); // put Z going up
  257. glRotatef (angles[0], 0, 1, 0);
  258. glRotatef (-angles[1], 0, 0, 1);
  259. glTranslatef (-origin[0], -origin[1], -origin[2]);
  260. Cam_BuildMatrix ();
  261. //
  262. // set drawing parms
  263. //
  264. glShadeModel (GL_SMOOTH);
  265. glPolygonMode (GL_FRONT_AND_BACK, GL_FILL);
  266. glFrontFace(GL_CW); // YWB Carmack goes backward
  267. glCullFace(GL_BACK); // Cull backfaces (qcsg used to spit out two sides, doesn't for -glview now)
  268. glEnable(GL_CULL_FACE); // Enable face culling, just in case...
  269. glDisable(GL_TEXTURE_2D);
  270. // Blending function if enabled..
  271. glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
  272. if (g_UseBlending)
  273. {
  274. glEnable(GL_BLEND);// YWB TESTING
  275. glDisable(GL_DEPTH_TEST);
  276. glDisable(GL_CULL_FACE); // Enable face culling, just in case...
  277. }
  278. else
  279. {
  280. glDisable(GL_BLEND);
  281. glEnable(GL_DEPTH_TEST);
  282. }
  283. glDepthFunc (GL_LEQUAL);
  284. if( g_bDisp )
  285. {
  286. DrawDisplacementData();
  287. }
  288. else
  289. {
  290. //
  291. // draw the list
  292. //
  293. if (g_bShowList1)
  294. glCallList (1);
  295. if (g_bReadPortals)
  296. {
  297. if (g_bNoDepthPortals)
  298. glDisable(GL_DEPTH_TEST);
  299. glDisable(GL_CULL_FACE); // Disable face culling
  300. if (g_bShowList2)
  301. glCallList(2);
  302. };
  303. if (g_bShowLines)
  304. glCallList(3);
  305. }
  306. }
  307. void ReadPolyFileType(const char *name, int nList, BOOL drawLines)
  308. {
  309. FILE *f;
  310. int i, j, numverts;
  311. float v[8];
  312. int c;
  313. int r;
  314. float divisor;
  315. f = fopen (name, "rt");
  316. if (!f)
  317. Error ("Couldn't open %s", name);
  318. if (g_bReadPortals)
  319. divisor = 2.0f;
  320. else
  321. divisor = 1.0f;
  322. c = 0;
  323. glNewList (nList, GL_COMPILE);
  324. for (i = 0; i < 3; i++) // Find the center point so we can put the viewer there by default
  325. g_Center[i] = 0.0f;
  326. if (drawLines) // Slight hilite
  327. glLineWidth(1.5);
  328. while (1)
  329. {
  330. r = fscanf( f, "%i\n", &numverts);
  331. if (!r || r == EOF)
  332. break;
  333. if ( c > 65534*8)
  334. break;
  335. if (drawLines || numverts == 2)
  336. glBegin(GL_LINE_LOOP);
  337. else
  338. glBegin (GL_POLYGON);
  339. for (i=0 ; i<numverts ; i++)
  340. {
  341. r = fscanf( f, "%f %f %f %f %f %f\n", &v[0], &v[1],
  342. &v[2], &v[3], &v[4], &v[5]);
  343. /*
  344. if (!(fabs( v[0] ) < 32768.0&& fabs( v[1] ) < 32768.0 && fabs( v[2] ) < 32768.0 ) )
  345. Error( "Out of range data\n");
  346. */
  347. /*
  348. if (v[3] <= 0.1 && v[4] <= 0.1 && v[5] <= 0.1 )
  349. continue;
  350. */
  351. if (drawLines) // YELLOW OUTLINES
  352. glColor4f(1.0, 1.0, 0.0, 0.5);
  353. else
  354. {
  355. if (g_bReadPortals) // Gray scale it, leave portals blue
  356. {
  357. if (fabs(fabs(v[5]) - 1.0f) < 0.01) // Is this a detail brush (color 0,0,1 blue)
  358. {
  359. glColor4f (v[3],v[4],v[5],0.5);
  360. }
  361. else // Normal brush, gray scale it...
  362. {
  363. v[3] += v[4] + v[5];
  364. v[3]/= 3.0f;
  365. glColor4f (v[3]/divisor, v[3]/divisor, v[3]/divisor, 0.6);
  366. }
  367. }
  368. else
  369. {
  370. v[3] = pow( v[3], (float)(1.0 / 2.2) );
  371. v[4] = pow( v[4], (float)(1.0 / 2.2) );
  372. v[5] = pow( v[5], (float)(1.0 / 2.2) );
  373. glColor4f (v[3]/divisor, v[4]/divisor, v[5]/divisor, 0.6); // divisor is one, bright colors
  374. };
  375. };
  376. glVertex3f (v[0], v[1], v[2]);
  377. for (j = 0; j < 3; j++)
  378. {
  379. g_Center[j] += v[j];
  380. }
  381. g_nTotalPoints++;
  382. }
  383. glEnd ();
  384. c++;
  385. }
  386. if (f)
  387. fclose(f);
  388. glEndList ();
  389. if (g_nTotalPoints > 0) // Avoid division by zero
  390. {
  391. for (i = 0; i < 3; i++)
  392. {
  393. g_Center[i] = g_Center[i]/(float)g_nTotalPoints; // Calculate center...
  394. origin[i] = g_Center[i];
  395. }
  396. }
  397. }
  398. #if BENCHMARK_PHY
  399. #define NUM_COLLISION_TESTS 2500
  400. #include "gametrace.h"
  401. #include "fmtstr.h"
  402. struct testlist_t
  403. {
  404. Vector start;
  405. Vector end;
  406. Vector normal;
  407. bool hit;
  408. };
  409. const float baselineTotal = 120.16f;
  410. const float baselineRay = 28.25f;
  411. const float baselineBox = 91.91f;
  412. #define IMPROVEMENT_FACTOR(x,baseline) (baseline/(x))
  413. #define IMPROVEMENT_PERCENT(x,baseline) (((baseline-(x)) / baseline) * 100.0f)
  414. testlist_t g_Traces[NUM_COLLISION_TESTS];
  415. void Benchmark_PHY( const CPhysCollide *pCollide )
  416. {
  417. int i;
  418. Msg( "Testing collision system\n" );
  419. Vector start = vec3_origin;
  420. static Vector *targets = NULL;
  421. static bool first = true;
  422. static float test[2] = {1,1};
  423. if ( first )
  424. {
  425. float radius = 0;
  426. float theta = 0;
  427. float phi = 0;
  428. for ( int i = 0; i < NUM_COLLISION_TESTS; i++ )
  429. {
  430. radius += NUM_COLLISION_TESTS * 123.123f;
  431. radius = fabs(fmod(radius, 128));
  432. theta += NUM_COLLISION_TESTS * 0.76f;
  433. theta = fabs(fmod(theta, DEG2RAD(360)));
  434. phi += NUM_COLLISION_TESTS * 0.16666666f;
  435. phi = fabs(fmod(phi, DEG2RAD(180)));
  436. float st, ct, sp, cp;
  437. SinCos( theta, &st, &ct );
  438. SinCos( phi, &sp, &cp );
  439. st = sin(theta);
  440. ct = cos(theta);
  441. sp = sin(phi);
  442. cp = cos(phi);
  443. g_Traces[i].start.x = radius * ct * sp;
  444. g_Traces[i].start.y = radius * st * sp;
  445. g_Traces[i].start.z = radius * cp;
  446. }
  447. first = false;
  448. }
  449. float duration = 0;
  450. Vector size[2];
  451. size[0].Init(0,0,0);
  452. size[1].Init(16,16,16);
  453. unsigned int dots = 0;
  454. #if VPROF_LEVEL > 0
  455. g_VProfCurrentProfile.Reset();
  456. g_VProfCurrentProfile.ResetPeaks();
  457. g_VProfCurrentProfile.Start();
  458. #endif
  459. unsigned int hitCount = 0;
  460. double startTime = Plat_FloatTime();
  461. trace_t tr;
  462. for ( i = 0; i < NUM_COLLISION_TESTS; i++ )
  463. {
  464. physcollision->TraceBox( g_Traces[i].start, start, -size[0], size[0], pCollide, vec3_origin, vec3_angle, &tr );
  465. if ( tr.DidHit() )
  466. {
  467. g_Traces[i].end = tr.endpos;
  468. g_Traces[i].normal = tr.plane.normal;
  469. g_Traces[i].hit = true;
  470. hitCount++;
  471. }
  472. else
  473. {
  474. g_Traces[i].hit = false;
  475. }
  476. }
  477. for ( i = 0; i < NUM_COLLISION_TESTS; i++ )
  478. {
  479. physcollision->TraceBox( g_Traces[i].start, start, -size[1], size[1], pCollide, vec3_origin, vec3_angle, &tr );
  480. }
  481. duration = Plat_FloatTime() - startTime;
  482. {
  483. unsigned int msSupp = physcollision->ReadStat( 100 );
  484. unsigned int msGJK = physcollision->ReadStat( 101 );
  485. unsigned int msMesh = physcollision->ReadStat( 102 );
  486. CFmtStr str("%d ms total %d ms gjk %d mesh solve\n", msSupp, msGJK, msMesh );
  487. OutputDebugStr( str.Access() );
  488. }
  489. #if VPROF_LEVEL > 0
  490. g_VProfCurrentProfile.MarkFrame();
  491. g_VProfCurrentProfile.Stop();
  492. g_VProfCurrentProfile.Reset();
  493. g_VProfCurrentProfile.ResetPeaks();
  494. g_VProfCurrentProfile.Start();
  495. #endif
  496. hitCount = 0;
  497. startTime = Plat_FloatTime();
  498. for ( i = 0; i < NUM_COLLISION_TESTS; i++ )
  499. {
  500. physcollision->TraceBox( g_Traces[i].start, start, -size[0], size[0], pCollide, vec3_origin, vec3_angle, &tr );
  501. if ( tr.DidHit() )
  502. {
  503. g_Traces[i].end = tr.endpos;
  504. g_Traces[i].normal = tr.plane.normal;
  505. g_Traces[i].hit = true;
  506. hitCount++;
  507. }
  508. else
  509. {
  510. g_Traces[i].hit = false;
  511. }
  512. #if VPROF_LEVEL > 0
  513. g_VProfCurrentProfile.MarkFrame();
  514. #endif
  515. }
  516. double midTime = Plat_FloatTime();
  517. for ( i = 0; i < NUM_COLLISION_TESTS; i++ )
  518. {
  519. physcollision->TraceBox( g_Traces[i].start, start, -size[1], size[1], pCollide, vec3_origin, vec3_angle, &tr );
  520. #if VPROF_LEVEL > 0
  521. g_VProfCurrentProfile.MarkFrame();
  522. #endif
  523. }
  524. double endTime = Plat_FloatTime();
  525. duration = endTime - startTime;
  526. {
  527. CFmtStr str("%d collisions in %.2f ms [%.2f X] %d hits\n", NUM_COLLISION_TESTS, duration*1000, IMPROVEMENT_FACTOR(duration*1000.0f, baselineTotal), hitCount );
  528. OutputDebugStr( str.Access() );
  529. }
  530. {
  531. float rayTime = (midTime - startTime) * 1000.0f;
  532. float boxTime = (endTime - midTime)*1000.0f;
  533. CFmtStr str("%.2f ms rays [%.2f X] %.2f ms boxes [%.2f X]\n", rayTime, IMPROVEMENT_FACTOR(rayTime, baselineRay), boxTime, IMPROVEMENT_FACTOR(boxTime, baselineBox));
  534. OutputDebugStr( str.Access() );
  535. }
  536. {
  537. unsigned int msSupp = physcollision->ReadStat( 100 );
  538. unsigned int msGJK = physcollision->ReadStat( 101 );
  539. unsigned int msMesh = physcollision->ReadStat( 102 );
  540. CFmtStr str("%d ms total %d ms gjk %d mesh solve\n", msSupp, msGJK, msMesh );
  541. OutputDebugStr( str.Access() );
  542. }
  543. #if VPROF_LEVEL > 0
  544. g_VProfCurrentProfile.Stop();
  545. g_VProfCurrentProfile.OutputReport( VPRT_FULL & ~VPRT_HIERARCHY, NULL );
  546. #endif
  547. // draw the traces in yellow
  548. glColor3f( 1.0f, 1.0f, 0.0f );
  549. glBegin( GL_LINES );
  550. for ( int i = 0; i < NUM_COLLISION_TESTS; i++ )
  551. {
  552. if ( !g_Traces[i].hit )
  553. continue;
  554. glVertex3fv( g_Traces[i].end.Base() );
  555. Vector tmp = g_Traces[i].end + g_Traces[i].normal * 10.0f;
  556. glVertex3fv( tmp.Base() );
  557. }
  558. glEnd();
  559. }
  560. #endif
  561. struct phyviewparams_t
  562. {
  563. Vector mins;
  564. Vector maxs;
  565. Vector offset;
  566. QAngle angles;
  567. int outputType;
  568. void Defaults()
  569. {
  570. ClearBounds(mins, maxs);
  571. offset.Init();
  572. outputType = GL_POLYGON;
  573. angles.Init();
  574. }
  575. };
  576. void AddVCollideToList( phyheader_t &header, vcollide_t &collide, phyviewparams_t &params )
  577. {
  578. matrix3x4_t xform;
  579. AngleMatrix( params.angles, params.offset, xform );
  580. ClearBounds( params.mins, params.maxs );
  581. for ( int i = 0; i < header.solidCount; i++ )
  582. {
  583. ICollisionQuery *pQuery = physcollision->CreateQueryModel( collide.solids[i] );
  584. for ( int j = 0; j < pQuery->ConvexCount(); j++ )
  585. {
  586. for ( int k = 0; k < pQuery->TriangleCount(j); k++ )
  587. {
  588. Vector verts[3];
  589. pQuery->GetTriangleVerts( j, k, verts );
  590. Vector v0,v1,v2;
  591. VectorTransform( verts[0], xform, v0 );
  592. VectorTransform( verts[1], xform, v1 );
  593. VectorTransform( verts[2], xform, v2 );
  594. AddPointToBounds( v0, params.mins, params.maxs );
  595. AddPointToBounds( v1, params.mins, params.maxs );
  596. AddPointToBounds( v2, params.mins, params.maxs );
  597. glBegin(params.outputType);
  598. glColor3ub( 255, 0, 0 );
  599. glVertex3fv( v0.Base() );
  600. glColor3ub( 0, 255, 0 );
  601. glVertex3fv( v1.Base() );
  602. glColor3ub( 0, 0, 255 );
  603. glVertex3fv( v2.Base() );
  604. glEnd();
  605. }
  606. }
  607. physcollision->DestroyQueryModel( pQuery );
  608. }
  609. }
  610. void GL_DrawLine( const Vector &start, const Vector &dir, float length, int r, int g, int b )
  611. {
  612. Vector end = start + (dir*length);
  613. glBegin( GL_LINES );
  614. glColor3ub(r,g,b);
  615. glVertex3fv( start.Base() );
  616. glVertex3fv( end.Base() );
  617. glEnd();
  618. }
  619. void GL_DrawBox( Vector origin, float size, int r, int g, int b )
  620. {
  621. Vector mins = origin - Vector(size,size,size);
  622. Vector maxs = origin + Vector(size,size,size);
  623. const float *v[2] = {mins.Base(), maxs.Base()};
  624. Vector start, end;
  625. {
  626. for ( int i = 0; i < 3; i++ )
  627. {
  628. int a0 = i;
  629. int a1 = (i+1)%3;
  630. int a2 = (i+2)%3;
  631. for ( int j = 0; j < 2; j++ )
  632. {
  633. for ( int k = 0; k < 2; k++ )
  634. {
  635. start[a0] = v[0][a0];
  636. end[a0] = v[1][a0];
  637. start[a1] = v[j][a1];
  638. end[a1] = v[j][a1];
  639. start[a2] = v[k][a2];
  640. end[a2] = v[k][a2];
  641. GL_DrawLine( start, end-start, 1, r, g, b );
  642. }
  643. }
  644. }
  645. }
  646. for ( int axis = 0; axis < 3; axis++ )
  647. {
  648. int a0 = axis;
  649. int a1 = (axis+1)%3;
  650. int a2 = (axis+2)%3;
  651. start[a0] = v[0][a0];
  652. end[a0] = v[1][a0];
  653. start[a1] = 0.5f *(v[0][a1]+v[1][a1]);
  654. end[a1] = 0.5f *(v[0][a1]+v[1][a1]);
  655. start[a2] = 0.5f *(v[0][a2]+v[1][a2]);
  656. end[a2] = 0.5f *(v[0][a2]+v[1][a2]);
  657. GL_DrawLine( start, end-start, 1, r, g, b );
  658. }
  659. }
  660. void ReadPHYFile(const char *name, phyviewparams_t &params )
  661. {
  662. FILE *fp = fopen (name, "rb");
  663. if (!fp)
  664. Error ("Couldn't open %s", name);
  665. phyheader_t header;
  666. fread( &header, sizeof(header), 1, fp );
  667. if ( header.size != sizeof(header) || header.solidCount <= 0 )
  668. return;
  669. int pos = ftell( fp );
  670. fseek( fp, 0, SEEK_END );
  671. int fileSize = ftell(fp) - pos;
  672. fseek( fp, pos, SEEK_SET );
  673. char *buf = (char *)_alloca( fileSize );
  674. fread( buf, fileSize, 1, fp );
  675. fclose( fp );
  676. vcollide_t collide;
  677. physcollision->VCollideLoad( &collide, header.solidCount, (const char *)buf, fileSize );
  678. #if 0
  679. Vector start0( -3859.1199, -2050.8674, 64.031250 );
  680. Vector end0(-3859.2246, -2051.2817, 64.031250 );
  681. Vector modelPosition(-3840,-2068.0000, 82.889099);
  682. QAngle modelAngles(0,90,0);
  683. {
  684. Ray_t ray;
  685. ray.Init( start0, end0, Vector(-16,-16,0), Vector(16,16,72));
  686. trace_t tr;
  687. physcollision->TraceBox( ray, collide.solids[0], modelPosition, modelAngles, &tr );
  688. Assert(!tr.startsolid);
  689. if ( tr.DidHit() )
  690. {
  691. Ray_t ray2;
  692. ray2.Init( tr.endpos, tr.endpos, Vector(-16,-16,0), Vector(16,16,72));
  693. trace_t tr2;
  694. physcollision->TraceBox( ray2, collide.solids[0], modelPosition, modelAngles, &tr2 );
  695. Assert(!tr2.startsolid);
  696. }
  697. }
  698. #endif
  699. #if BENCHMARK_PHY
  700. Benchmark_PHY( collide.solids[0] );
  701. #endif
  702. AddVCollideToList( header, collide, params );
  703. }
  704. void ReadPolyFile (const char *name)
  705. {
  706. char ext[4];
  707. Q_ExtractFileExtension( name, ext, 4 );
  708. bool isPHY = !Q_stricmp( ext, "phy" );
  709. if ( isPHY )
  710. {
  711. CreateInterfaceFn physicsFactory = GetPhysicsFactory();
  712. physcollision = (IPhysicsCollision *)physicsFactory( VPHYSICS_COLLISION_INTERFACE_VERSION, NULL );
  713. if ( physcollision )
  714. {
  715. phyviewparams_t params;
  716. params.Defaults();
  717. glNewList (1, GL_COMPILE);
  718. ReadPHYFile( name, params );
  719. Vector tmp = (params.mins + params.maxs) * 0.5;
  720. tmp.CopyToArray(origin);
  721. glEndList ();
  722. }
  723. }
  724. else
  725. {
  726. // Read in polys...
  727. ReadPolyFileType(name, 1, false);
  728. // Make list 3 just the lines... so we can draw outlines
  729. ReadPolyFileType(name, 3, true);
  730. }
  731. }
  732. void ReadPortalFile (char *name)
  733. {
  734. FILE *f;
  735. int i, numverts;
  736. float v[8];
  737. int c;
  738. int r;
  739. // For Portal type reading...
  740. char szDummy[80];
  741. int nNumLeafs;
  742. int nNumPortals;
  743. int nLeafIndex[2];
  744. f = fopen (name, "r");
  745. if (!f)
  746. Error ("Couldn't open %s", name);
  747. c = 0;
  748. glNewList (2, GL_COMPILE);
  749. // Read in header
  750. fscanf(f, "%79s\n", szDummy);
  751. fscanf(f, "%i\n", &nNumLeafs);
  752. fscanf(f, "%i\n", &nNumPortals);
  753. glLineWidth(1.5);
  754. while (1)
  755. {
  756. r = fscanf(f, "%i %i %i ", &numverts, &nLeafIndex[0], &nLeafIndex[1]);
  757. if (!r || r == EOF)
  758. break;
  759. glBegin(GL_LINE_LOOP);
  760. for (i=0 ; i<numverts ; i++)
  761. {
  762. r = fscanf (f, "(%f %f %f )\n", &v[0], &v[1],
  763. &v[2]);
  764. if (!r || (r != 3) || r == EOF)
  765. break;
  766. if ( c == g_nPortalHighlight || nLeafIndex[0] == g_nLeafHighlight || nLeafIndex[1] == g_nLeafHighlight )
  767. {
  768. glColor4f (1.0, 0.0, 0.0, 1.0);
  769. }
  770. else
  771. {
  772. glColor4f (1.0f, 1.0f, 1.0f, 1.0f); // WHITE portals
  773. }
  774. glVertex3f (v[0], v[1], v[2]);
  775. }
  776. glEnd ();
  777. c++;
  778. }
  779. if (f)
  780. fclose(f);
  781. glEndList ();
  782. }
  783. #define MAX_DISP_COUNT 4096
  784. static Vector dispPoints[MAX_DISP_COUNT];
  785. static Vector dispNormals[MAX_DISP_COUNT];
  786. static int dispPointCount = 0;
  787. //-----------------------------------------------------------------------------
  788. //-----------------------------------------------------------------------------
  789. BOOL ReadDisplacementFile( const char *filename )
  790. {
  791. FILE *pFile;
  792. int fileCount;
  793. //
  794. // open the file
  795. //
  796. pFile = fopen( filename, "r" );
  797. if( !pFile )
  798. Error( "Couldn't open %s", filename );
  799. //
  800. // read data in file
  801. //
  802. while( 1 )
  803. {
  804. // overflow test
  805. if( dispPointCount >= MAX_DISP_COUNT )
  806. break;
  807. fileCount = fscanf( pFile, "%f %f %f %f %f %f",
  808. &dispPoints[dispPointCount][0], &dispPoints[dispPointCount][1], &dispPoints[dispPointCount][2],
  809. &dispNormals[dispPointCount][0], &dispNormals[dispPointCount][1], &dispNormals[dispPointCount][2] );
  810. dispPointCount++;
  811. // end of file check
  812. if( !fileCount || ( fileCount == EOF ) )
  813. break;
  814. }
  815. fclose( pFile );
  816. return TRUE;
  817. }
  818. //-----------------------------------------------------------------------------
  819. //-----------------------------------------------------------------------------
  820. void DrawDisplacementData( void )
  821. {
  822. int i, j;
  823. int width, halfCount;
  824. GLUquadricObj *pObject = gluNewQuadric();
  825. glEnable( GL_DEPTH_TEST );
  826. for( i = 0; i < dispPointCount; i++ )
  827. {
  828. // draw a sphere where the point is (in red)
  829. glColor3f( 1.0f, 0.0f, 0.0f );
  830. glPushMatrix();
  831. glTranslatef( dispPoints[i][0], dispPoints[i][1], dispPoints[i][2] );
  832. gluSphere( pObject, 5, 5, 5 );
  833. glPopMatrix();
  834. // draw the normal (in yellow)
  835. glColor3f( 1.0f, 1.0f, 0.0f );
  836. glBegin( GL_LINES );
  837. glVertex3f( dispPoints[i][0], dispPoints[i][1], dispPoints[i][2] );
  838. glVertex3f( dispPoints[i][0] + ( dispNormals[i][0] * 50.0f ), dispPoints[i][1] + ( dispNormals[i][1] * 50.0f ), dispPoints[i][2] + ( dispNormals[i][2] * 50.0f ) );
  839. glEnd();
  840. }
  841. halfCount = dispPointCount / 2;
  842. width = sqrt( (float)halfCount );
  843. glDisable( GL_CULL_FACE );
  844. glColor3f( 0.0f, 0.0f, 1.0f );
  845. for( i = 0; i < width - 1; i++ )
  846. {
  847. for( j = 0; j < width - 1; j++ )
  848. {
  849. glBegin( GL_POLYGON );
  850. glVertex3f( dispPoints[i*width+j][0], dispPoints[i*width+j][1], dispPoints[i*width+j][2] );
  851. glVertex3f( dispPoints[(i+1)*width+j][0], dispPoints[(i+1)*width+j][1], dispPoints[(i+1)*width+j][2] );
  852. glVertex3f( dispPoints[(i+1)*width+(j+1)][0], dispPoints[(i+1)*width+(j+1)][1], dispPoints[(i+1)*width+(j+1)][2] );
  853. glVertex3f( dispPoints[i*width+(j+1)][0], dispPoints[i*width+(j+1)][1], dispPoints[i*width+(j+1)][2] );
  854. glEnd();
  855. }
  856. }
  857. #if 0
  858. for( i = 0; i < width - 1; i++ )
  859. {
  860. for( j = 0; j < width - 1; j++ )
  861. {
  862. glBegin( GL_POLYGON );
  863. glVertex3f( dispPoints[halfCount+(i*width+j)][0], dispPoints[halfCount+(i*width+j)][1], dispPoints[halfCount+(i*width+j)][2] );
  864. glVertex3f( dispPoints[halfCount+((i+1)*width+j)][0], dispPoints[halfCount+(i+1)*width+j][1], dispPoints[halfCount+((i+1)*width+j)][2] );
  865. glVertex3f( dispPoints[halfCount+((i+1)*width+(j+1))][0], dispPoints[halfCount+(i+1)*width+(j+1)][1], dispPoints[halfCount+((i+1)*width+(j+1))][2] );
  866. glVertex3f( dispPoints[halfCount+(i*width+(j+1))][0], dispPoints[halfCount+(i*width+(j+1))][1], dispPoints[halfCount+(i*width+(j+1))][2] );
  867. glEnd();
  868. }
  869. }
  870. #endif
  871. glColor3f( 0.0f, 1.0f, 0.0f );
  872. for( i = 0; i < width - 1; i++ )
  873. {
  874. for( j = 0; j < width - 1; j++ )
  875. {
  876. glBegin( GL_POLYGON );
  877. glVertex3f( dispPoints[i*width+j][0] + ( dispNormals[i*width+j][0] * 150.0f ),
  878. dispPoints[i*width+j][1] + ( dispNormals[i*width+j][1] * 150.0f ),
  879. dispPoints[i*width+j][2] + ( dispNormals[i*width+j][2] * 150.0f ) );
  880. glVertex3f( dispPoints[(i+1)*width+j][0] + ( dispNormals[(i+1)*width+j][0] * 150.0f ),
  881. dispPoints[(i+1)*width+j][1] + ( dispNormals[(i+1)*width+j][1] * 150.0f ),
  882. dispPoints[(i+1)*width+j][2] + ( dispNormals[(i+1)*width+j][2] * 150.0f ) );
  883. glVertex3f( dispPoints[(i+1)*width+(j+1)][0] + ( dispNormals[(i+1)*width+(j+1)][0] * 150.0f ),
  884. dispPoints[(i+1)*width+(j+1)][1] + ( dispNormals[(i+1)*width+(j+1)][1] * 150.0f ),
  885. dispPoints[(i+1)*width+(j+1)][2] + ( dispNormals[(i+1)*width+(j+1)][2] * 150.0f ) );
  886. glVertex3f( dispPoints[i*width+(j+1)][0] + ( dispNormals[i*width+(j+1)][0] * 150.0f ),
  887. dispPoints[i*width+(j+1)][1] + ( dispNormals[i*width+(j+1)][1] * 150.0f ),
  888. dispPoints[i*width+(j+1)][2] + ( dispNormals[i*width+(j+1)][2] * 150.0f ) );
  889. glEnd();
  890. }
  891. }
  892. glDisable( GL_DEPTH_TEST );
  893. glColor3f( 0.0f, 0.0f, 1.0f );
  894. for( i = 0; i < width - 1; i++ )
  895. {
  896. for( j = 0; j < width - 1; j++ )
  897. {
  898. glBegin( GL_LINE_LOOP );
  899. glVertex3f( dispPoints[i*width+j][0] + ( dispNormals[i*width+j][0] * 150.0f ),
  900. dispPoints[i*width+j][1] + ( dispNormals[i*width+j][1] * 150.0f ),
  901. dispPoints[i*width+j][2] + ( dispNormals[i*width+j][2] * 150.0f ) );
  902. glVertex3f( dispPoints[(i+1)*width+j][0] + ( dispNormals[(i+1)*width+j][0] * 150.0f ),
  903. dispPoints[(i+1)*width+j][1] + ( dispNormals[(i+1)*width+j][1] * 150.0f ),
  904. dispPoints[(i+1)*width+j][2] + ( dispNormals[(i+1)*width+j][2] * 150.0f ) );
  905. glVertex3f( dispPoints[(i+1)*width+(j+1)][0] + ( dispNormals[(i+1)*width+(j+1)][0] * 150.0f ),
  906. dispPoints[(i+1)*width+(j+1)][1] + ( dispNormals[(i+1)*width+(j+1)][1] * 150.0f ),
  907. dispPoints[(i+1)*width+(j+1)][2] + ( dispNormals[(i+1)*width+(j+1)][2] * 150.0f ) );
  908. glVertex3f( dispPoints[i*width+(j+1)][0] + ( dispNormals[i*width+(j+1)][0] * 150.0f ),
  909. dispPoints[i*width+(j+1)][1] + ( dispNormals[i*width+(j+1)][1] * 150.0f ),
  910. dispPoints[i*width+(j+1)][2] + ( dispNormals[i*width+(j+1)][2] * 150.0f ) );
  911. glEnd();
  912. }
  913. }
  914. gluDeleteQuadric( pObject );
  915. }
  916. //=====================================================================
  917. BOOL bSetupPixelFormat(HDC hDC)
  918. {
  919. static PIXELFORMATDESCRIPTOR pfd = {
  920. sizeof(PIXELFORMATDESCRIPTOR), // size of this pfd
  921. 1, // version number
  922. PFD_DRAW_TO_WINDOW | // support window
  923. PFD_SUPPORT_OPENGL | // support OpenGL
  924. PFD_DOUBLEBUFFER, // double buffered
  925. PFD_TYPE_RGBA, // RGBA type
  926. 24, // 24-bit color depth
  927. 0, 0, 0, 0, 0, 0, // color bits ignored
  928. 0, // no alpha buffer
  929. 0, // shift bit ignored
  930. 0, // no accumulation buffer
  931. 0, 0, 0, 0, // accum bits ignored
  932. 32, // 32-bit z-buffer
  933. 0, // no stencil buffer
  934. 0, // no auxiliary buffer
  935. PFD_MAIN_PLANE, // main layer
  936. 0, // reserved
  937. 0, 0, 0 // layer masks ignored
  938. };
  939. int pixelformat = 0;
  940. if ( (pixelformat = ChoosePixelFormat(hDC, &pfd)) == 0 )
  941. Error ("ChoosePixelFormat failed");
  942. if (!SetPixelFormat(hDC, pixelformat, &pfd))
  943. Error ("SetPixelFormat failed");
  944. return TRUE;
  945. }
  946. /*
  947. ============
  948. CameraWndProc
  949. ============
  950. */
  951. LONG WINAPI WCam_WndProc (
  952. HWND hWnd,
  953. UINT uMsg,
  954. WPARAM wParam,
  955. LPARAM lParam)
  956. {
  957. LONG lRet = 1;
  958. RECT rect;
  959. GetClientRect(hWnd, &rect);
  960. switch (uMsg)
  961. {
  962. case WM_CREATE:
  963. {
  964. camdc = GetDC(hWnd);
  965. bSetupPixelFormat(camdc);
  966. baseRC = wglCreateContext( camdc );
  967. if (!baseRC)
  968. Error ("wglCreateContext failed");
  969. if (!wglMakeCurrent( camdc, baseRC ))
  970. Error ("wglMakeCurrent failed");
  971. glCullFace(GL_FRONT);
  972. glEnable(GL_CULL_FACE);
  973. }
  974. break;
  975. case WM_PAINT:
  976. {
  977. PAINTSTRUCT ps;
  978. BeginPaint(hWnd, &ps);
  979. if (!wglMakeCurrent( camdc, baseRC ))
  980. Error ("wglMakeCurrent failed");
  981. Draw ();
  982. SwapBuffers(camdc);
  983. EndPaint(hWnd, &ps);
  984. }
  985. break;
  986. case WM_KEYDOWN:
  987. KeyDown (wParam);
  988. AppKeyDown( wParam );
  989. break;
  990. case WM_KEYUP:
  991. AppKeyUp( wParam );
  992. break;
  993. case WM_MBUTTONDOWN:
  994. case WM_RBUTTONDOWN:
  995. case WM_LBUTTONDOWN:
  996. SetCapture (camerawindow);
  997. ShowCursor( FALSE );
  998. g_Capture = TRUE;
  999. break;
  1000. case WM_MBUTTONUP:
  1001. case WM_RBUTTONUP:
  1002. case WM_LBUTTONUP:
  1003. if (! (wParam & (MK_LBUTTON|MK_RBUTTON|MK_MBUTTON)))
  1004. {
  1005. g_Capture = FALSE;
  1006. ReleaseCapture ();
  1007. ShowCursor( TRUE );
  1008. }
  1009. break;
  1010. case WM_SIZE:
  1011. InvalidateRect(camerawindow, NULL, false);
  1012. break;
  1013. case WM_NCCALCSIZE:// don't let windows copy pixels
  1014. lRet = DefWindowProc (hWnd, uMsg, wParam, lParam);
  1015. return WVR_REDRAW;
  1016. case WM_CLOSE:
  1017. /* call destroy window to cleanup and go away */
  1018. DestroyWindow (hWnd);
  1019. break;
  1020. case WM_DESTROY:
  1021. {
  1022. HGLRC hRC;
  1023. HDC hDC;
  1024. /* release and free the device context and rendering context */
  1025. hRC = wglGetCurrentContext();
  1026. hDC = wglGetCurrentDC();
  1027. wglMakeCurrent(NULL, NULL);
  1028. if (hRC)
  1029. wglDeleteContext(hRC);
  1030. if (hDC)
  1031. ReleaseDC(hWnd, hDC);
  1032. PostQuitMessage (0);
  1033. }
  1034. break;
  1035. default:
  1036. /* pass all unhandled messages to DefWindowProc */
  1037. lRet = DefWindowProc (hWnd, uMsg, wParam, lParam);
  1038. break;
  1039. }
  1040. /* return 1 if handled message, 0 if not */
  1041. return lRet;
  1042. }
  1043. /*
  1044. ==============
  1045. WCam_Register
  1046. ==============
  1047. */
  1048. void WCam_Register (HINSTANCE hInstance)
  1049. {
  1050. WNDCLASS wc;
  1051. /* Register the camera class */
  1052. memset (&wc, 0, sizeof(wc));
  1053. wc.style = 0;
  1054. wc.lpfnWndProc = (WNDPROC)WCam_WndProc;
  1055. wc.cbClsExtra = 0;
  1056. wc.cbWndExtra = 0;
  1057. wc.hInstance = hInstance;
  1058. wc.hIcon = 0;
  1059. wc.hCursor = LoadCursor (NULL,IDC_ARROW);
  1060. wc.hbrBackground = NULL;
  1061. wc.lpszMenuName = 0;
  1062. wc.lpszClassName = "camera";
  1063. if (!RegisterClass (&wc) )
  1064. Error ("WCam_Register: failed");
  1065. }
  1066. void WCam_Create (HINSTANCE hInstance)
  1067. {
  1068. // Center it
  1069. int nScx, nScy;
  1070. int w, h;
  1071. int x, y;
  1072. WCam_Register (hInstance);
  1073. w = ::width;
  1074. h = ::height;
  1075. nScx = GetSystemMetrics(SM_CXSCREEN);
  1076. nScy = GetSystemMetrics(SM_CYSCREEN);
  1077. x = (nScx - w)/2;
  1078. y = (nScy - h)/2;
  1079. camerawindow = CreateWindow ("camera" ,
  1080. "Camera View",
  1081. WS_OVERLAPPED |
  1082. WS_CAPTION |
  1083. WS_SYSMENU |
  1084. WS_THICKFRAME |
  1085. WS_MAXIMIZEBOX |
  1086. WS_CLIPSIBLINGS |
  1087. WS_CLIPCHILDREN,
  1088. x,
  1089. y,
  1090. w,
  1091. h, // size
  1092. NULL, // parent window
  1093. 0, // no menu
  1094. hInstance,
  1095. 0);
  1096. if (!camerawindow)
  1097. Error ("Couldn't create camerawindow");
  1098. ShowWindow (camerawindow, SW_SHOWDEFAULT);
  1099. }
  1100. void AppKeyDown( int key )
  1101. {
  1102. key &= 0xFF;
  1103. g_Keys[key] = 0x03; // add debounce bit
  1104. }
  1105. void AppKeyUp( int key )
  1106. {
  1107. key &= 0xFF;
  1108. g_Keys[key] &= 0x02;
  1109. }
  1110. void AppRender( void )
  1111. {
  1112. static double lastTime = 0;
  1113. double time = timeGetTime() * 0.001f;
  1114. double frametime = time - lastTime;
  1115. // clamp too large frames (like first frame)
  1116. if ( frametime > 0.2 )
  1117. frametime = 0.2;
  1118. lastTime = time;
  1119. if (!wglMakeCurrent( camdc, baseRC ))
  1120. Error ("wglMakeCurrent failed");
  1121. Cam_Update( frametime );
  1122. if (g_Update)
  1123. {
  1124. Draw ();
  1125. SwapBuffers(camdc);
  1126. g_Update = FALSE;
  1127. }
  1128. else
  1129. {
  1130. Sleep( 1.0 );
  1131. }
  1132. }
  1133. SpewRetval_t Sys_SpewFunc( SpewType_t type, const char *pMsg )
  1134. {
  1135. OutputDebugString( pMsg );
  1136. if( type == SPEW_ASSERT )
  1137. return SPEW_DEBUGGER;
  1138. else if( type == SPEW_ERROR )
  1139. return SPEW_ABORT;
  1140. else
  1141. return SPEW_CONTINUE;
  1142. }
  1143. /*
  1144. ==================
  1145. WinMain
  1146. ==================
  1147. */
  1148. int WINAPI WinMain (HINSTANCE hInstance, HINSTANCE hPrevInstance
  1149. ,LPSTR lpCmdLine, int nCmdShow)
  1150. {
  1151. CommandLine()->CreateCmdLine( Plat_GetCommandLine() );
  1152. MathLib_Init( 2.2f, 2.2f, 0.0f, 2.0f );
  1153. MSG msg;
  1154. if (!lpCmdLine || !lpCmdLine[0])
  1155. Error ("No file specified");
  1156. main_instance = hInstance;
  1157. WCam_Create (hInstance);
  1158. // Last argument is the file name
  1159. const char *pFileName = CommandLine()->GetParm( CommandLine()->ParmCount() - 1 );
  1160. CmdLib_InitFileSystem( pFileName );
  1161. if ( CommandLine()->CheckParm( "-portal") )
  1162. {
  1163. g_bReadPortals = 1;
  1164. g_nPortalHighlight = CommandLine()->ParmValue( "-portalhighlight", -1 );
  1165. g_nLeafHighlight = CommandLine()->ParmValue( "-leafhighlight", -1 );
  1166. }
  1167. g_flMovementSpeed = CommandLine()->ParmValue( "-speed", 320 );
  1168. if( CommandLine()->CheckParm( "-disp") )
  1169. {
  1170. ReadDisplacementFile( pFileName );
  1171. g_bDisp = TRUE;
  1172. }
  1173. SpewOutputFunc( Sys_SpewFunc );
  1174. // Any chunk of original left is the filename.
  1175. if (pFileName && pFileName[0] && !g_bDisp )
  1176. {
  1177. ReadPolyFile( pFileName );
  1178. }
  1179. if (g_bReadPortals)
  1180. {
  1181. // Copy file again and this time look for the . from .gl? so we can concatenate .prt
  1182. // and open the portal file.
  1183. char szTempCmd[MAX_PATH];
  1184. strcpy(szTempCmd, pFileName);
  1185. char *pTmp = szTempCmd;
  1186. while (pTmp && *pTmp && *pTmp != '.')
  1187. {
  1188. pTmp++;
  1189. }
  1190. *pTmp = '\0';
  1191. strcat(szTempCmd, ".prt");
  1192. ReadPortalFile(szTempCmd);
  1193. };
  1194. /* main window message loop */
  1195. while (g_Active)
  1196. {
  1197. while (PeekMessage(&msg, NULL, 0, 0, PM_REMOVE))
  1198. {
  1199. TranslateMessage (&msg);
  1200. DispatchMessage (&msg);
  1201. }
  1202. AppRender();
  1203. }
  1204. /* return success of application */
  1205. return TRUE;
  1206. }