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.

582 lines
15 KiB

  1. //========= Copyright Valve Corporation, All rights reserved. ============//
  2. //
  3. // Purpose:
  4. //
  5. // $NoKeywords: $
  6. //=============================================================================//
  7. #include "cbase.h"
  8. // identifier was truncated to '255' characters in the debug information
  9. #pragma warning(disable: 4786)
  10. #include "proxyentity.h"
  11. #include "materialsystem/imaterialvar.h"
  12. #include "materialsystem/itexture.h"
  13. #include "bitmap/tgaloader.h"
  14. #include "view.h"
  15. #include "datacache/idatacache.h"
  16. #include "materialsystem/imaterial.h"
  17. #include "vtf/vtf.h"
  18. // memdbgon must be the last include file in a .cpp file!!!
  19. #include "tier0/memdbgon.h"
  20. class CCamoMaterialProxy;
  21. class CCamoTextureRegen : public ITextureRegenerator
  22. {
  23. public:
  24. CCamoTextureRegen( CCamoMaterialProxy *pProxy ) : m_pProxy(pProxy) {}
  25. virtual void RegenerateTextureBits( ITexture *pTexture, IVTFTexture *pVTFTexture, Rect_t *pSubRect );
  26. virtual void Release() {}
  27. private:
  28. CCamoMaterialProxy *m_pProxy;
  29. };
  30. class CCamoMaterialProxy : public CEntityMaterialProxy
  31. {
  32. public:
  33. CCamoMaterialProxy();
  34. virtual ~CCamoMaterialProxy();
  35. virtual bool Init( IMaterial *pMaterial, KeyValues *pKeyValues );
  36. virtual void OnBind(C_BaseEntity *pC_BaseEntity );
  37. virtual IMaterial *GetMaterial();
  38. // Procedurally generates the camo texture...
  39. void GenerateCamoTexture( ITexture* pTexture, IVTFTexture *pVTFTexture );
  40. protected:
  41. #if 0
  42. virtual void SetInstanceDataSize( int size );
  43. virtual void *FindInstanceData( C_BaseEntity *pEntity );
  44. virtual void *AllocateInstanceData( C_BaseEntity *pEntity );
  45. #endif
  46. private:
  47. void LoadCamoPattern( void );
  48. void GenerateRandomPointsInNormalizedCube( void );
  49. void GetColors( Vector &lighting, Vector &base, int index,
  50. const Vector &boxMin, const Vector &boxExtents,
  51. const Vector &forward, const Vector &right, const Vector &up,
  52. const Vector& entityPosition );
  53. // this needs to go in a base class
  54. private:
  55. #if 0
  56. // stuff that needs to be in a base class.
  57. struct InstanceData_t
  58. {
  59. C_BaseEntity *pEntity;
  60. void *data;
  61. struct InstanceData_s *next;
  62. };
  63. struct CamoInstanceData_t
  64. {
  65. int dummy;
  66. };
  67. #endif
  68. unsigned char *m_pCamoPatternImage;
  69. #if 0
  70. int m_InstanceDataSize;
  71. InstanceData_t *m_InstanceDataListHead;
  72. #endif
  73. IMaterial *m_pMaterial;
  74. IMaterialVar *m_pCamoTextureVar;
  75. IMaterialVar *m_pCamoPatternTextureVar;
  76. Vector *m_pointsInNormalizedBox; // [m_CamoPatternNumColors]
  77. int m_CamoPatternNumColors;
  78. int m_CamoPatternWidth;
  79. int m_CamoPatternHeight;
  80. #if 0
  81. cache_user_t m_camoImageDataCache;
  82. #endif
  83. unsigned char m_CamoPalette[256][3];
  84. // these represent that part of the entitiy's bounding box that we
  85. // want to cast rays through to get colors for the camo
  86. Vector m_SubBoundingBoxMin; // normalized
  87. Vector m_SubBoundingBoxMax; // normalized
  88. CCamoTextureRegen m_TextureRegen;
  89. C_BaseEntity *m_pEnt;
  90. };
  91. void CCamoTextureRegen::RegenerateTextureBits( ITexture *pTexture, IVTFTexture *pVTFTexture, Rect_t *pSubRect )
  92. {
  93. m_pProxy->GenerateCamoTexture( pTexture, pVTFTexture );
  94. }
  95. #pragma warning (disable:4355)
  96. CCamoMaterialProxy::CCamoMaterialProxy() : m_TextureRegen(this)
  97. {
  98. #if 0
  99. m_InstanceDataSize = 0;
  100. #endif
  101. #if 0
  102. memset( &m_camoImageDataCache, 0,sizeof( m_camoImageDataCache ) );
  103. #endif
  104. m_pointsInNormalizedBox = NULL;
  105. #if 0
  106. m_InstanceDataListHead = NULL;
  107. #endif
  108. m_pCamoPatternImage = NULL;
  109. m_pMaterial = NULL;
  110. m_pCamoTextureVar = NULL;
  111. m_pCamoPatternTextureVar = NULL;
  112. m_pointsInNormalizedBox = NULL;
  113. m_pEnt = NULL;
  114. }
  115. #pragma warning (default:4355)
  116. CCamoMaterialProxy::~CCamoMaterialProxy()
  117. {
  118. #if 0
  119. InstanceData_t *curr = m_InstanceDataListHead;
  120. while( curr )
  121. {
  122. InstanceData_t *next;
  123. next = curr->next;
  124. delete curr;
  125. curr = next;
  126. }
  127. m_InstanceDataListHead = NULL;
  128. #endif
  129. // Disconnect the texture regenerator...
  130. if (m_pCamoTextureVar)
  131. {
  132. ITexture *pCamoTexture = m_pCamoTextureVar->GetTextureValue();
  133. if (pCamoTexture)
  134. pCamoTexture->SetTextureRegenerator( NULL );
  135. }
  136. delete m_pCamoPatternImage;
  137. delete m_pointsInNormalizedBox;
  138. }
  139. #if 0
  140. void CCamoMaterialProxy::SetInstanceDataSize( int size )
  141. {
  142. m_InstanceDataSize = size;
  143. }
  144. #endif
  145. #if 0
  146. void *CCamoMaterialProxy::FindInstanceData( C_BaseEntity *pEntity )
  147. {
  148. InstanceData_t *curr = m_InstanceDataListHead;
  149. while( curr )
  150. {
  151. if( pEntity == curr->pEntity )
  152. {
  153. return curr->data;
  154. }
  155. curr = curr->next;
  156. }
  157. return NULL;
  158. }
  159. #endif
  160. #if 0
  161. void *CCamoMaterialProxy::AllocateInstanceData( C_BaseEntity *pEntity )
  162. {
  163. InstanceData_t *newData = new InstanceData_t;
  164. newData->pEntity = pEntity;
  165. newData->next = m_InstanceDataListHead;
  166. m_InstanceDataListHead = newData;
  167. newData->data = new unsigned char[m_InstanceDataSize];
  168. return newData->data;
  169. }
  170. #endif
  171. bool CCamoMaterialProxy::Init( IMaterial *pMaterial, KeyValues *pKeyValues )
  172. {
  173. return false; // hack! Need to make sure that the TGA loader has a valid filesystem before trying
  174. // to load the camo pattern.
  175. #if 0
  176. // set how big our instance data is.
  177. SetInstanceDataSize( sizeof( CamoInstanceData_t ) );
  178. #endif
  179. // remember what material we belong to.
  180. m_pMaterial = pMaterial;
  181. // get pointers to material vars.
  182. bool found;
  183. m_pCamoTextureVar = m_pMaterial->FindVar( "$baseTexture", &found );
  184. if( !found )
  185. {
  186. m_pCamoTextureVar = NULL;
  187. return false;
  188. }
  189. ITexture *pCamoTexture = m_pCamoTextureVar->GetTextureValue();
  190. if (pCamoTexture)
  191. pCamoTexture->SetTextureRegenerator( &m_TextureRegen );
  192. // Need to get the palettized texture to create the procedural texture from
  193. // somewhere.
  194. m_pCamoPatternTextureVar = m_pMaterial->FindVar( "$camoPatternTexture", &found );
  195. if( !found )
  196. {
  197. m_pCamoTextureVar = NULL;
  198. return false;
  199. }
  200. IMaterialVar *subBoundingBoxMinVar, *subBoundingBoxMaxVar;
  201. subBoundingBoxMinVar = m_pMaterial->FindVar( "$camoBoundingBoxMin", &found, false );
  202. if( !found )
  203. {
  204. m_SubBoundingBoxMin = Vector( 0.0f, 0.0f, 0.0f );
  205. }
  206. else
  207. {
  208. subBoundingBoxMinVar->GetVecValue( m_SubBoundingBoxMin.Base(), 3 );
  209. }
  210. subBoundingBoxMaxVar = m_pMaterial->FindVar( "$camoBoundingBoxMax", &found, false );
  211. if( !found )
  212. {
  213. m_SubBoundingBoxMax = Vector( 1.0f, 1.0f, 1.0f );
  214. }
  215. else
  216. {
  217. subBoundingBoxMaxVar->GetVecValue( m_SubBoundingBoxMax.Base(), 3 );
  218. }
  219. LoadCamoPattern();
  220. GenerateRandomPointsInNormalizedCube();
  221. return true;
  222. }
  223. void CCamoMaterialProxy::GetColors( Vector &diffuseColor, Vector &baseColor, int index,
  224. const Vector &boxMin, const Vector &boxExtents,
  225. const Vector &forward, const Vector &right, const Vector &up,
  226. const Vector& entityPosition )
  227. {
  228. Vector position, transformedPosition;
  229. // hack
  230. // m_pointsInNormalizedBox[index] = Vector( 0.5f, 0.5f, 1.0f );
  231. position[0] = m_pointsInNormalizedBox[index][0] * boxExtents[0] + boxMin[0];
  232. position[1] = m_pointsInNormalizedBox[index][1] * boxExtents[1] + boxMin[1];
  233. position[2] = m_pointsInNormalizedBox[index][2] * boxExtents[2] + boxMin[2];
  234. transformedPosition[0] = right[0] * position[0] + forward[0] * position[1] + up[0] * position[2];
  235. transformedPosition[1] = right[1] * position[0] + forward[1] * position[1] + up[1] * position[2];
  236. transformedPosition[2] = right[2] * position[0] + forward[2] * position[1] + up[2] * position[2];
  237. transformedPosition = transformedPosition + entityPosition;
  238. Vector direction = transformedPosition - CurrentViewOrigin();
  239. VectorNormalize( direction );
  240. direction = direction * ( COORD_EXTENT * 1.74f );
  241. Vector endPoint = position + direction;
  242. // baseColor is already in gamma space
  243. // engine->TraceLineMaterialAndLighting( g_vecInstantaneousRenderOrigin, endPoint, diffuseColor, baseColor );
  244. engine->TraceLineMaterialAndLighting( transformedPosition, endPoint, diffuseColor, baseColor );
  245. // hack - optimize! - convert from linear to gamma space - this should be hidden
  246. diffuseColor[0] = pow( diffuseColor[0], 1.0f / 2.2f );
  247. diffuseColor[1] = pow( diffuseColor[1], 1.0f / 2.2f );
  248. diffuseColor[2] = pow( diffuseColor[2], 1.0f / 2.2f );
  249. #if 0
  250. Msg( "%f %f %f\n",
  251. diffuseColor[0],
  252. diffuseColor[1],
  253. diffuseColor[2] );
  254. #endif
  255. #if 0
  256. float max;
  257. max = diffuseColor[0];
  258. if( diffuseColor[1] > max )
  259. {
  260. max = diffuseColor[1];
  261. }
  262. if( diffuseColor[2] > max )
  263. {
  264. max = diffuseColor[2];
  265. }
  266. if( max > 1.0f )
  267. {
  268. max = 1.0f / max;
  269. diffuseColor = diffuseColor * max;
  270. }
  271. #else
  272. if( diffuseColor[0] > 1.0f )
  273. {
  274. diffuseColor[0] = 1.0f;
  275. }
  276. if( diffuseColor[1] > 1.0f )
  277. {
  278. diffuseColor[1] = 1.0f;
  279. }
  280. if( diffuseColor[2] > 1.0f )
  281. {
  282. diffuseColor[2] = 1.0f;
  283. }
  284. #endif
  285. // hack
  286. //baseColor = Vector( 1.0f, 1.0f, 1.0f );
  287. //diffuseColor = Vector( 1.0f, 1.0f, 1.0f );
  288. }
  289. //-----------------------------------------------------------------------------
  290. // Procedurally generates the camo texture...
  291. //-----------------------------------------------------------------------------
  292. void CCamoMaterialProxy::GenerateCamoTexture( ITexture* pTexture, IVTFTexture *pVTFTexture )
  293. {
  294. if (!m_pEnt)
  295. return;
  296. #if 0
  297. CamoInstanceData_t *pInstanceData;
  298. pInstanceData = ( CamoInstanceData_t * )FindInstanceData( pEnt );
  299. if( !pInstanceData )
  300. {
  301. pInstanceData = ( CamoInstanceData_t * )AllocateInstanceData( pEnt );
  302. if( !pInstanceData )
  303. {
  304. return;
  305. }
  306. // init the instance data
  307. }
  308. #endif
  309. Vector entityPosition;
  310. entityPosition = m_pEnt->GetAbsOrigin();
  311. QAngle entityAngles;
  312. entityAngles = m_pEnt->GetAbsAngles();
  313. // Get the bounding box for the entity
  314. Vector mins, maxs;
  315. mins = m_pEnt->WorldAlignMins();
  316. maxs = m_pEnt->WorldAlignMaxs();
  317. Vector traceDirection;
  318. Vector traceEnd;
  319. trace_t traceResult;
  320. Vector forward, right, up;
  321. AngleVectors( entityAngles, &forward, &right, &up );
  322. Vector position, transformedPosition;
  323. Vector maxsMinusMins = maxs - mins;
  324. Vector diffuseColor[256];
  325. Vector baseColor;
  326. unsigned char camoPalette[256][3];
  327. // Calculate the camo palette
  328. //Msg( "start of loop\n" );
  329. int i;
  330. for( i = 0; i < m_CamoPatternNumColors; i++ )
  331. {
  332. GetColors( diffuseColor[i], baseColor, i,
  333. mins, maxsMinusMins, forward, right, up, entityPosition );
  334. #if 1
  335. camoPalette[i][0] = diffuseColor[i][0] * baseColor[0] * 255.0f;
  336. camoPalette[i][1] = diffuseColor[i][1] * baseColor[1] * 255.0f;
  337. camoPalette[i][2] = diffuseColor[i][2] * baseColor[2] * 255.0f;
  338. #endif
  339. #if 0
  340. camoPalette[i][0] = baseColor[0] * 255.0f;
  341. camoPalette[i][1] = baseColor[1] * 255.0f;
  342. camoPalette[i][2] = baseColor[2] * 255.0f;
  343. #endif
  344. #if 0
  345. camoPalette[i][0] = diffuseColor[i][0] * 255.0f;
  346. camoPalette[i][1] = diffuseColor[i][1] * 255.0f;
  347. camoPalette[i][2] = diffuseColor[i][2] * 255.0f;
  348. #endif
  349. }
  350. int width = pVTFTexture->Width();
  351. int height = pVTFTexture->Height();
  352. if( width != m_CamoPatternWidth || height != m_CamoPatternHeight )
  353. {
  354. return;
  355. }
  356. unsigned char *imageData = pVTFTexture->ImageData( 0, 0, 0 );
  357. enum ImageFormat imageFormat = pVTFTexture->Format();
  358. if( imageFormat != IMAGE_FORMAT_RGB888 )
  359. {
  360. return;
  361. }
  362. // optimize
  363. #if 1
  364. int x, y;
  365. for( y = 0; y < height; y++ )
  366. {
  367. for( x = 0; x < width; x++ )
  368. {
  369. int offset = 3 * ( x + y * width );
  370. assert( offset < width * height * 3 );
  371. int paletteID = m_pCamoPatternImage[x + y * width];
  372. assert( paletteID < 256 );
  373. #if 1
  374. imageData[offset + 0] = camoPalette[paletteID][0];
  375. imageData[offset + 1] = camoPalette[paletteID][1];
  376. imageData[offset + 2] = camoPalette[paletteID][2];
  377. #else
  378. imageData[offset] = 255;
  379. imageData[offset + 1] = 0;
  380. imageData[offset + 2] = 0;
  381. #endif
  382. }
  383. }
  384. #endif
  385. }
  386. //-----------------------------------------------------------------------------
  387. // Called when the texture is bound...
  388. //-----------------------------------------------------------------------------
  389. void CCamoMaterialProxy::OnBind( C_BaseEntity *pEntity )
  390. {
  391. if( !m_pCamoTextureVar )
  392. {
  393. return;
  394. }
  395. m_pEnt = pEntity;
  396. ITexture *pCamoTexture = m_pCamoTextureVar->GetTextureValue();
  397. pCamoTexture->Download();
  398. // Mark it so it doesn't get regenerated on task switch
  399. m_pEnt = NULL;
  400. }
  401. void CCamoMaterialProxy::LoadCamoPattern( void )
  402. {
  403. #if 0
  404. // hack - need to figure out a name to attach that isn't too long.
  405. m_pCamoPatternImage =
  406. ( unsigned char * )datacache->FindByName( &m_camoImageDataCache, "camopattern" );
  407. if( m_pCamoPatternImage )
  408. {
  409. // is already in the cache.
  410. return m_pCamoPatternImage;
  411. }
  412. #endif
  413. enum ImageFormat indexImageFormat;
  414. int indexImageSize;
  415. #ifndef _XBOX
  416. float dummyGamma;
  417. if( !TGALoader::GetInfo( m_pCamoPatternTextureVar->GetStringValue(),
  418. &m_CamoPatternWidth, &m_CamoPatternHeight, &indexImageFormat, &dummyGamma ) )
  419. {
  420. //Warning( "Can't get tga info for hl2/materials/models/combine_elite/camo7paletted.tga for camo material\n" );
  421. m_pCamoTextureVar = NULL;
  422. return;
  423. }
  424. #else
  425. // xboxissue - no tga support, why implemented this way
  426. Assert( 0 );
  427. m_pCamoTextureVar = NULL;
  428. return;
  429. #endif
  430. if( indexImageFormat != IMAGE_FORMAT_I8 )
  431. {
  432. // Warning( "Camo material texture hl2/materials/models/combine_elite/camo7paletted.tga must be 8-bit greyscale\n" );
  433. m_pCamoTextureVar = NULL;
  434. return;
  435. }
  436. indexImageSize = ImageLoader::GetMemRequired( m_CamoPatternWidth, m_CamoPatternHeight, 1, indexImageFormat, false );
  437. #if 0
  438. m_pCamoPatternImage = ( unsigned char * )
  439. datacache->Alloc( &m_camoImageDataCache, indexImageSize, "camopattern" );
  440. #endif
  441. m_pCamoPatternImage = ( unsigned char * )new unsigned char[indexImageSize];
  442. if( !m_pCamoPatternImage )
  443. {
  444. m_pCamoTextureVar = NULL;
  445. return;
  446. }
  447. #ifndef _XBOX
  448. if( !TGALoader::Load( m_pCamoPatternImage, m_pCamoPatternTextureVar->GetStringValue(),
  449. m_CamoPatternWidth, m_CamoPatternHeight, IMAGE_FORMAT_I8, dummyGamma, false ) )
  450. {
  451. // Warning( "camo texture hl2/materials/models/combine_elite/camo7paletted.tga must be grey-scale" );
  452. m_pCamoTextureVar = NULL;
  453. return;
  454. }
  455. #else
  456. // xboxissue - no tga support, why is the camo done this way?
  457. Assert( 0 );
  458. #endif
  459. bool colorUsed[256];
  460. int colorRemap[256];
  461. // count the number of colors used in the image.
  462. int i;
  463. for( i = 0; i < 256; i++ )
  464. {
  465. colorUsed[i] = false;
  466. }
  467. for( i = 0; i < indexImageSize; i++ )
  468. {
  469. colorUsed[m_pCamoPatternImage[i]] = true;
  470. }
  471. m_CamoPatternNumColors = 0;
  472. for( i = 0; i < 256; i++ )
  473. {
  474. if( colorUsed[i] )
  475. {
  476. colorRemap[i] = m_CamoPatternNumColors;
  477. m_CamoPatternNumColors++;
  478. }
  479. }
  480. // remap the color to the beginning of the palette.
  481. for( i = 0; i < indexImageSize; i++ )
  482. {
  483. m_pCamoPatternImage[i] = colorRemap[m_pCamoPatternImage[i]];
  484. // hack
  485. // m_pCamoPatternImage[i] = 0;
  486. }
  487. }
  488. void CCamoMaterialProxy::GenerateRandomPointsInNormalizedCube( void )
  489. {
  490. m_pointsInNormalizedBox = new Vector[m_CamoPatternNumColors];
  491. if( !m_pointsInNormalizedBox )
  492. {
  493. m_pCamoTextureVar = NULL;
  494. return;
  495. }
  496. int i;
  497. for( i = 0; i < m_CamoPatternNumColors; i++ )
  498. {
  499. m_pointsInNormalizedBox[i][0] = random->RandomFloat( m_SubBoundingBoxMin[0], m_SubBoundingBoxMax[0] );
  500. m_pointsInNormalizedBox[i][1] = random->RandomFloat( m_SubBoundingBoxMin[1], m_SubBoundingBoxMax[1] );
  501. m_pointsInNormalizedBox[i][2] = random->RandomFloat( m_SubBoundingBoxMin[2], m_SubBoundingBoxMax[2] );
  502. }
  503. }
  504. IMaterial *CCamoMaterialProxy::GetMaterial()
  505. {
  506. return m_pMaterial;
  507. }
  508. EXPOSE_INTERFACE( CCamoMaterialProxy, IMaterialProxy, "Camo" IMATERIAL_PROXY_INTERFACE_VERSION );