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.

571 lines
15 KiB

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