Counter Strike : Global Offensive Source Code
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.

640 lines
15 KiB

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