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.

635 lines
15 KiB

  1. //========= Copyright Valve Corporation, All rights reserved. ============//
  2. //
  3. // Purpose:
  4. //
  5. // $NoKeywords: $
  6. //=============================================================================//
  7. #include <stdio.h>
  8. #include "scratchpad3d.h"
  9. #include "tier0/dbg.h"
  10. // memdbgon must be the last include file in a .cpp file!!!
  11. #include "tier0/memdbgon.h"
  12. #ifndef POSIX
  13. // NOTE - linux doesn't need any of this code!
  14. extern "C"
  15. {
  16. extern void __stdcall Sleep( unsigned long ms );
  17. };
  18. class CFileRead
  19. {
  20. public:
  21. CFileRead( IFileSystem* pFileSystem, FileHandle_t fp )
  22. {
  23. m_pFileSystem = pFileSystem;
  24. m_fp = fp;
  25. m_Pos = 0;
  26. }
  27. bool Read( void *pDest, int len )
  28. {
  29. int count = m_pFileSystem->Read( pDest, len, m_fp );
  30. m_Pos += count;
  31. return count == len;
  32. }
  33. IFileSystem* m_pFileSystem;
  34. FileHandle_t m_fp;
  35. int m_Pos;
  36. };
  37. // ------------------------------------------------------------------------ //
  38. // CCommand_Point.
  39. // ------------------------------------------------------------------------ //
  40. void CScratchPad3D::CCommand_Point::Read( CFileRead *pFile )
  41. {
  42. pFile->Read( &m_flPointSize, sizeof(m_flPointSize) );
  43. pFile->Read( &m_Vert, sizeof(m_Vert) );
  44. }
  45. void CScratchPad3D::CCommand_Point::Write( IFileSystem* pFileSystem, FileHandle_t fp )
  46. {
  47. pFileSystem->Write( &m_flPointSize, sizeof(m_flPointSize), fp );
  48. pFileSystem->Write( &m_Vert, sizeof(m_Vert), fp );
  49. }
  50. // ------------------------------------------------------------------------ //
  51. // CCommand_Line.
  52. // ------------------------------------------------------------------------ //
  53. void CScratchPad3D::CCommand_Line::Read( CFileRead *pFile )
  54. {
  55. pFile->Read( m_Verts, sizeof(m_Verts) );
  56. }
  57. void CScratchPad3D::CCommand_Line::Write( IFileSystem* pFileSystem, FileHandle_t fp )
  58. {
  59. pFileSystem->Write( m_Verts, sizeof(m_Verts), fp );
  60. }
  61. // ------------------------------------------------------------------------ //
  62. // CCommand_Polygon.
  63. // ------------------------------------------------------------------------ //
  64. void CScratchPad3D::CCommand_Polygon::Read( CFileRead *pFile )
  65. {
  66. int count;
  67. pFile->Read( &count, sizeof(count) );
  68. m_Verts.RemoveAll();
  69. m_Verts.AddMultipleToTail( count );
  70. if( count )
  71. pFile->Read( &m_Verts[0], sizeof(CSPVert)*count );
  72. }
  73. void CScratchPad3D::CCommand_Polygon::Write( IFileSystem* pFileSystem, FileHandle_t fp )
  74. {
  75. int count = m_Verts.Size();
  76. pFileSystem->Write( &count, sizeof(count), fp );
  77. if( count )
  78. pFileSystem->Write( &m_Verts[0], sizeof(CSPVert)*count, fp );
  79. }
  80. // ------------------------------------------------------------------------ //
  81. // CCommand_Matrix.
  82. // ------------------------------------------------------------------------ //
  83. void CScratchPad3D::CCommand_Matrix::Read( CFileRead *pFile )
  84. {
  85. pFile->Read( &m_mMatrix, sizeof(m_mMatrix) );
  86. }
  87. void CScratchPad3D::CCommand_Matrix::Write( IFileSystem* pFileSystem, FileHandle_t fp )
  88. {
  89. pFileSystem->Write( &m_mMatrix, sizeof(m_mMatrix), fp );
  90. }
  91. // ------------------------------------------------------------------------ //
  92. // CCommand_RenderState.
  93. // ------------------------------------------------------------------------ //
  94. void CScratchPad3D::CCommand_RenderState::Read( CFileRead *pFile )
  95. {
  96. pFile->Read( &m_State, sizeof(m_State) );
  97. pFile->Read( &m_Val, sizeof(m_Val) );
  98. }
  99. void CScratchPad3D::CCommand_RenderState::Write( IFileSystem* pFileSystem, FileHandle_t fp )
  100. {
  101. pFileSystem->Write( &m_State, sizeof(m_State), fp );
  102. pFileSystem->Write( &m_Val, sizeof(m_Val), fp );
  103. }
  104. // ------------------------------------------------------------------------ //
  105. // CCommand_Text.
  106. // ------------------------------------------------------------------------ //
  107. void CScratchPad3D::CCommand_Text::Read( CFileRead *pFile )
  108. {
  109. int strLen;
  110. pFile->Read( &strLen, sizeof( strLen ) );
  111. m_String.SetSize( strLen );
  112. pFile->Read( m_String.Base(), strLen );
  113. pFile->Read( &m_TextParams, sizeof( m_TextParams ) );
  114. }
  115. void CScratchPad3D::CCommand_Text::Write( IFileSystem* pFileSystem, FileHandle_t fp )
  116. {
  117. int strLen = m_String.Count();
  118. pFileSystem->Write( &strLen, sizeof( strLen ), fp );
  119. pFileSystem->Write( m_String.Base(), strLen, fp );
  120. pFileSystem->Write( &m_TextParams, sizeof( m_TextParams ), fp );
  121. }
  122. // ------------------------------------------------------------------------ //
  123. // CScratchPad3D internals.
  124. // ------------------------------------------------------------------------ //
  125. CScratchPad3D::CScratchPad3D( char const *pFilename, IFileSystem* pFileSystem, bool bAutoClear )
  126. {
  127. m_pFileSystem = pFileSystem;
  128. m_pFilename = pFilename;
  129. m_bAutoFlush = true;
  130. if( bAutoClear )
  131. Clear(); // Clear whatever is in the file..
  132. }
  133. void CScratchPad3D::AutoFlush()
  134. {
  135. if( m_bAutoFlush )
  136. Flush();
  137. }
  138. void CScratchPad3D::DrawRectGeneric( int iPlane, int otherDim1, int otherDim2, float planeDist, const Vector2D &vMin, const Vector2D &vMax, const CSPColor &vColor )
  139. {
  140. Vector verts[4];
  141. verts[0][iPlane] = verts[1][iPlane] = verts[2][iPlane] = verts[3][iPlane] = planeDist;
  142. verts[0][otherDim1] = vMin.x;
  143. verts[0][otherDim2] = vMin.y;
  144. verts[1][otherDim1] = vMin.x;
  145. verts[1][otherDim2] = vMax.y;
  146. verts[2][otherDim1] = vMax.x;
  147. verts[2][otherDim2] = vMax.y;
  148. verts[3][otherDim1] = vMax.x;
  149. verts[3][otherDim2] = vMin.y;
  150. DrawPolygon( CSPVertList(verts, 4, vColor) );
  151. }
  152. void CScratchPad3D::DeleteCommands()
  153. {
  154. for( int i=0; i < m_Commands.Size(); i++ )
  155. delete m_Commands[i];
  156. m_Commands.RemoveAll();
  157. }
  158. bool CScratchPad3D::LoadCommandsFromFile( )
  159. {
  160. DeleteCommands();
  161. FileHandle_t fp = m_pFileSystem->Open( m_pFilename, "rb" );
  162. if( !fp )
  163. return false;
  164. long fileEndPos = m_pFileSystem->Size( fp );
  165. CFileRead fileRead( m_pFileSystem, fp );
  166. while( fileRead.m_Pos != fileEndPos )
  167. {
  168. unsigned char iCommand;
  169. fileRead.Read( &iCommand, sizeof(iCommand) );
  170. CBaseCommand *pCmd = NULL;
  171. if( iCommand == COMMAND_POINT )
  172. pCmd = new CCommand_Point;
  173. else if( iCommand == COMMAND_LINE )
  174. pCmd = new CCommand_Line;
  175. else if( iCommand == COMMAND_POLYGON )
  176. pCmd = new CCommand_Polygon;
  177. else if( iCommand == COMMAND_MATRIX )
  178. pCmd = new CCommand_Matrix;
  179. else if( iCommand == COMMAND_RENDERSTATE )
  180. pCmd = new CCommand_RenderState;
  181. else if ( iCommand == COMMAND_TEXT )
  182. pCmd = new CCommand_Text;
  183. if( !pCmd )
  184. {
  185. Assert( !"LoadCommandsFromFile: invalid file" );
  186. m_pFileSystem->Close( fp );
  187. return false;
  188. }
  189. pCmd->Read( &fileRead );
  190. m_Commands.AddToTail( pCmd );
  191. }
  192. m_pFileSystem->Close( fp );
  193. return true;
  194. }
  195. // ------------------------------------------------------------------------ //
  196. // CScratchPad3D's IScratchPad3D implementation.
  197. // ------------------------------------------------------------------------ //
  198. void CScratchPad3D::Release()
  199. {
  200. Flush();
  201. delete this;
  202. }
  203. void CScratchPad3D::SetMapping(
  204. const Vector &vInputMin,
  205. const Vector &vInputMax,
  206. const Vector &vOutputMin,
  207. const Vector &vOutputMax )
  208. {
  209. CCommand_Matrix *cmd = new CCommand_Matrix;
  210. m_Commands.AddToTail( cmd );
  211. Vector vDivisor(1,1,1);
  212. for( int i=0; i < 3; i++ )
  213. vDivisor[i] = fabs(vInputMax[i] - vInputMin[i]) < 0.0001f ? 0.001f : (vInputMax[i] - vInputMin[i]);
  214. Vector vScale = (vOutputMax - vOutputMin) / vDivisor;
  215. Vector vShift = -vInputMin * vScale + vOutputMin;
  216. cmd->m_mMatrix.Init(
  217. vScale.x, 0, 0, vShift.x,
  218. 0, vScale.y, 0, vShift.y,
  219. 0, 0, vScale.z, vShift.z,
  220. 0, 0, 0, 1 );
  221. AutoFlush();
  222. }
  223. bool CScratchPad3D::GetAutoFlush()
  224. {
  225. return m_bAutoFlush;
  226. }
  227. void CScratchPad3D::SetAutoFlush( bool bAutoFlush )
  228. {
  229. m_bAutoFlush = bAutoFlush;
  230. if( m_bAutoFlush )
  231. Flush();
  232. }
  233. void CScratchPad3D::DrawPoint( CSPVert const &v, float flPointSize )
  234. {
  235. CCommand_Point *cmd = new CCommand_Point;
  236. m_Commands.AddToTail( cmd );
  237. cmd->m_Vert = v;
  238. cmd->m_flPointSize = flPointSize;
  239. AutoFlush();
  240. }
  241. void CScratchPad3D::DrawLine( CSPVert const &v1, CSPVert const &v2 )
  242. {
  243. CCommand_Line *cmd = new CCommand_Line;
  244. m_Commands.AddToTail( cmd );
  245. cmd->m_Verts[0] = v1;
  246. cmd->m_Verts[1] = v2;
  247. AutoFlush();
  248. }
  249. void CScratchPad3D::DrawPolygon( CSPVertList const &verts )
  250. {
  251. CCommand_Polygon *cmd = new CCommand_Polygon;
  252. m_Commands.AddToTail( cmd );
  253. cmd->m_Verts.AddVectorToTail( verts.m_Verts );
  254. AutoFlush();
  255. }
  256. void CScratchPad3D::DrawRectYZ( float xPos, const Vector2D &vMin, const Vector2D &vMax, const CSPColor &vColor )
  257. {
  258. DrawRectGeneric( 0, 1, 2, xPos, vMin, vMax, vColor );
  259. }
  260. void CScratchPad3D::DrawRectXZ( float yPos, const Vector2D &vMin, const Vector2D &vMax, const CSPColor &vColor )
  261. {
  262. DrawRectGeneric( 1, 0, 2, yPos, vMin, vMax, vColor );
  263. }
  264. void CScratchPad3D::DrawRectXY( float zPos, const Vector2D &vMin, const Vector2D &vMax, const CSPColor &vColor )
  265. {
  266. DrawRectGeneric( 2, 0, 1, zPos, vMin, vMax, vColor );
  267. }
  268. void CScratchPad3D::SetRenderState( RenderState state, unsigned long val )
  269. {
  270. CCommand_RenderState *cmd = new CCommand_RenderState;
  271. m_Commands.AddToTail( cmd );
  272. cmd->m_State = (unsigned long)state;
  273. cmd->m_Val = val;
  274. }
  275. void CScratchPad3D::DrawWireframeBox( const Vector &vMin, const Vector &vMax, const Vector &vColor )
  276. {
  277. // Bottom 4.
  278. DrawLine(
  279. CSPVert(Vector(vMin.x, vMin.y, vMin.z), vColor),
  280. CSPVert(Vector(vMax.x, vMin.y, vMin.z), vColor) );
  281. DrawLine(
  282. CSPVert(Vector(vMin.x, vMin.y, vMin.z), vColor),
  283. CSPVert(Vector(vMin.x, vMax.y, vMin.z), vColor) );
  284. DrawLine(
  285. CSPVert(Vector(vMax.x, vMin.y, vMin.z), vColor),
  286. CSPVert(Vector(vMax.x, vMax.y, vMin.z), vColor) );
  287. DrawLine(
  288. CSPVert(Vector(vMax.x, vMax.y, vMin.z), vColor),
  289. CSPVert(Vector(vMin.x, vMax.y, vMin.z), vColor) );
  290. // Top 4.
  291. DrawLine(
  292. CSPVert(Vector(vMin.x, vMin.y, vMax.z), vColor),
  293. CSPVert(Vector(vMax.x, vMin.y, vMax.z), vColor) );
  294. DrawLine(
  295. CSPVert(Vector(vMin.x, vMin.y, vMax.z), vColor),
  296. CSPVert(Vector(vMin.x, vMax.y, vMax.z), vColor) );
  297. DrawLine(
  298. CSPVert(Vector(vMax.x, vMin.y, vMax.z), vColor),
  299. CSPVert(Vector(vMax.x, vMax.y, vMax.z), vColor) );
  300. DrawLine(
  301. CSPVert(Vector(vMax.x, vMax.y, vMax.z), vColor),
  302. CSPVert(Vector(vMin.x, vMax.y, vMax.z), vColor) );
  303. // Connecting 4.
  304. DrawLine(
  305. CSPVert(Vector(vMin.x, vMin.y, vMin.z), vColor),
  306. CSPVert(Vector(vMin.x, vMin.y, vMax.z), vColor) );
  307. DrawLine(
  308. CSPVert(Vector(vMin.x, vMax.y, vMin.z), vColor),
  309. CSPVert(Vector(vMin.x, vMax.y, vMax.z), vColor) );
  310. DrawLine(
  311. CSPVert(Vector(vMax.x, vMax.y, vMin.z), vColor),
  312. CSPVert(Vector(vMax.x, vMax.y, vMax.z), vColor) );
  313. DrawLine(
  314. CSPVert(Vector(vMax.x, vMin.y, vMin.z), vColor),
  315. CSPVert(Vector(vMax.x, vMin.y, vMax.z), vColor) );
  316. }
  317. void CScratchPad3D::DrawText( const char *pStr, const CTextParams &params )
  318. {
  319. CCommand_Text *cmd = new CCommand_Text;
  320. m_Commands.AddToTail( cmd );
  321. cmd->m_String.CopyArray( pStr, strlen( pStr ) + 1 );
  322. cmd->m_TextParams = params;
  323. AutoFlush();
  324. }
  325. void CScratchPad3D::Clear()
  326. {
  327. FileHandle_t fp;
  328. while( ( fp = m_pFileSystem->Open(m_pFilename, "wb") ) == NULL )
  329. {
  330. #ifdef _WIN32
  331. Sleep( 5 );
  332. #elif POSIX
  333. usleep( 5 );
  334. #endif
  335. }
  336. m_pFileSystem->Close( fp );
  337. DeleteCommands();
  338. }
  339. void CScratchPad3D::Flush()
  340. {
  341. FileHandle_t fp;
  342. while( ( fp = m_pFileSystem->Open(m_pFilename, "ab+") ) == NULL )
  343. {
  344. #ifdef _WIN32
  345. Sleep( 5 );
  346. #elif POSIX
  347. usleep( 5 );
  348. #endif
  349. }
  350. // Append the new commands to the file.
  351. for( int i=0; i < m_Commands.Size(); i++ )
  352. {
  353. m_pFileSystem->Write( &m_Commands[i]->m_iCommand, sizeof(m_Commands[i]->m_iCommand), fp );
  354. m_Commands[i]->Write( m_pFileSystem, fp );
  355. }
  356. m_pFileSystem->Close( fp );
  357. DeleteCommands();
  358. }
  359. void CScratchPad3D::DrawImageBW(
  360. unsigned char const *pData,
  361. int width,
  362. int height,
  363. int pitchInBytes,
  364. bool bOutlinePixels,
  365. bool bOutlineImage,
  366. Vector *vCorners )
  367. {
  368. SPRGBA *pRGBA = new SPRGBA[width*height];
  369. for( int y=0; y < height; y++ )
  370. {
  371. SPRGBA *pDest = &pRGBA[ y * width ];
  372. unsigned char const *pSrc = &pData[ y * pitchInBytes ];
  373. for( int x=0; x < width; x++ )
  374. {
  375. pDest->r = pDest->g = pDest->b = *pSrc;
  376. ++pSrc;
  377. ++pDest;
  378. }
  379. }
  380. DrawImageRGBA( pRGBA, width, height, width*sizeof(SPRGBA), bOutlinePixels, bOutlineImage, vCorners );
  381. delete [] pRGBA;
  382. }
  383. void CScratchPad3D::DrawPolygonsForPixels(
  384. SPRGBA *pData,
  385. int width,
  386. int height,
  387. int pitchInBytes,
  388. Vector *vCorners )
  389. {
  390. // Scan top-down.
  391. Vector vCurLeft = vCorners[1];
  392. Vector vCurRight = vCorners[2];
  393. Vector vLeftInc = (vCorners[0] - vCorners[1]) / height;
  394. Vector vRightInc = (vCorners[3] - vCorners[2]) / height;
  395. Vector vNextLeft = vCurLeft + vLeftInc;
  396. Vector vNextRight = vCurRight + vRightInc;
  397. Vector vPolyBox[4];
  398. Vector &vTopLeft = vPolyBox[0];
  399. Vector &vTopRight = vPolyBox[1];
  400. Vector &vBottomRight = vPolyBox[2];
  401. Vector &vBottomLeft = vPolyBox[3];
  402. for( int y=0; y < height; y++ )
  403. {
  404. vTopLeft = vCurLeft;
  405. vBottomLeft = vNextLeft;
  406. Vector vTopXInc = (vCurRight - vCurLeft) / width;
  407. Vector vBottomXInc = (vNextRight - vNextLeft) / width;
  408. vTopRight = vTopLeft + vTopXInc;
  409. vBottomRight = vBottomLeft + vBottomXInc;
  410. SPRGBA *pSrc = &pData[ y * (pitchInBytes/sizeof(SPRGBA)) ];
  411. for( int x=0; x < width; x++ )
  412. {
  413. if ( pData )
  414. DrawPolygon( CSPVertList( vPolyBox, 4, Vector(pSrc->r/255.1f, pSrc->g/255.1f, pSrc->b/255.1f) ) );
  415. else
  416. DrawPolygon( CSPVertList( vPolyBox, 4, Vector(1,1,1) ) );
  417. ++pSrc;
  418. vTopLeft += vTopXInc;
  419. vTopRight += vTopXInc;
  420. vBottomLeft += vBottomXInc;
  421. vBottomRight += vBottomXInc;
  422. }
  423. vCurLeft += vLeftInc;
  424. vNextLeft += vLeftInc;
  425. vCurRight += vRightInc;
  426. vNextRight += vRightInc;
  427. }
  428. }
  429. void CScratchPad3D::DrawImageRGBA(
  430. SPRGBA *pData,
  431. int width,
  432. int height,
  433. int pitchInBytes,
  434. bool bOutlinePixels,
  435. bool bOutlineImage,
  436. Vector *vCorners )
  437. {
  438. Assert( pitchInBytes % sizeof(SPRGBA) == 0 );
  439. Vector vDefaultCorners[4];
  440. if ( !vCorners )
  441. {
  442. vCorners = vDefaultCorners;
  443. vDefaultCorners[0].Init( -100, -100 );
  444. vDefaultCorners[1].Init( -100, 100 );
  445. vDefaultCorners[2].Init( 100, 100 );
  446. vDefaultCorners[3].Init( 100, -100 );
  447. }
  448. // Don't auto-flush while drawing all these primitives.
  449. bool bOldAutoFlush = m_bAutoFlush;
  450. m_bAutoFlush = false;
  451. // Draw solids.
  452. SetRenderState( IScratchPad3D::RS_FillMode, IScratchPad3D::FillMode_Solid );
  453. DrawPolygonsForPixels( pData, width, height, pitchInBytes, vCorners );
  454. // Draw wireframe.
  455. if ( bOutlinePixels )
  456. {
  457. SetRenderState( IScratchPad3D::RS_FillMode, IScratchPad3D::FillMode_Wireframe );
  458. DrawPolygonsForPixels( NULL, width, height, pitchInBytes, vCorners );
  459. }
  460. // Draw an outline around the whole image.
  461. if ( bOutlineImage )
  462. {
  463. SetRenderState( IScratchPad3D::RS_FillMode, IScratchPad3D::FillMode_Wireframe );
  464. DrawPolygon( CSPVertList( vCorners, 4 ) );
  465. }
  466. // Restore the old auto-flush state.
  467. m_bAutoFlush = bOldAutoFlush;
  468. AutoFlush();
  469. }
  470. // ------------------------------------------------------------------------ //
  471. // Global functions.
  472. // ------------------------------------------------------------------------ //
  473. IFileSystem* ScratchPad3D_SetupFileSystem()
  474. {
  475. // Get a filesystem interface.
  476. CSysModule *pModule = Sys_LoadModule( "filesystem_stdio" );
  477. if( !pModule )
  478. return NULL;
  479. CreateInterfaceFn fn = Sys_GetFactory( pModule );
  480. IFileSystem *pFileSystem;
  481. if( !fn || (pFileSystem = (IFileSystem *)fn( FILESYSTEM_INTERFACE_VERSION, NULL )) == NULL )
  482. {
  483. Sys_UnloadModule( pModule );
  484. return NULL;
  485. }
  486. return pFileSystem;
  487. }
  488. IScratchPad3D* ScratchPad3D_Create( char const *pFilename )
  489. {
  490. IFileSystem *pFileSystem = ScratchPad3D_SetupFileSystem();
  491. if( !pFileSystem )
  492. return NULL;
  493. CScratchPad3D *pRet = new CScratchPad3D( pFilename, pFileSystem, true );
  494. return pRet;
  495. }
  496. #endif // POSIX