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.

416 lines
10 KiB

  1. //========== Copyright � 2005, Valve Corporation, All rights reserved. ========
  2. //
  3. // Purpose:
  4. //
  5. //=============================================================================
  6. #include "pch_materialsystem.h"
  7. #ifndef _PS3
  8. #define MATSYS_INTERNAL
  9. #endif
  10. #include "cmaterialsystem.h"
  11. #include "IHardwareConfigInternal.h"
  12. #include "cmatpaintmaps.h"
  13. #include "cmatlightmaps.h"
  14. #include "materialsystem_global.h"
  15. #include "materialsystem/materialsystem_config.h"
  16. #include "itextureinternal.h"
  17. // src/public/
  18. #include "game/shared/portal2/paint_enum.h"
  19. static Color g_PaintColors[PAINT_POWER_TYPE_COUNT_PLUS_NO_POWER];
  20. static void RegisterPaintColors()
  21. {
  22. #if defined ( PORTAL2 )
  23. // These ConVar are defined in src/game/shared/portal/paint_color_manager.cpp
  24. static ConVarRef speed_paint_color( "speed_paint_color" );
  25. static ConVarRef bounce_paint_color( "bounce_paint_color" );
  26. static ConVarRef reflect_paint_color( "reflect_paint_color" );
  27. static ConVarRef portal_paint_color( "portal_paint_color" );
  28. static ConVarRef erase_color( "erase_color" );
  29. g_PaintColors[SPEED_POWER] = speed_paint_color.GetColor();
  30. g_PaintColors[BOUNCE_POWER] = bounce_paint_color.GetColor();
  31. g_PaintColors[PORTAL_POWER] = portal_paint_color.GetColor();
  32. g_PaintColors[REFLECT_POWER] = reflect_paint_color.GetColor();
  33. g_PaintColors[NO_POWER] = erase_color.GetColor();
  34. #endif
  35. }
  36. static const BYTE NUM_ALPHA_BITS = 5;
  37. static const BYTE PAINT_COLOR_BITS = 7 << NUM_ALPHA_BITS; // 224
  38. static const BYTE PAINT_ALPHA_BITS = PAINT_COLOR_BITS ^ 0xFF; // 31
  39. BYTE GetColorIndex( BYTE byte )
  40. {
  41. return ( PAINT_COLOR_BITS & byte ) >> NUM_ALPHA_BITS;
  42. }
  43. inline const Color &GetColor( BYTE byte )
  44. {
  45. BYTE colorIndex = GetColorIndex( byte );
  46. return g_PaintColors[ colorIndex ];
  47. }
  48. inline float GetAlpha( BYTE byte )
  49. {
  50. double alpha = ( PAINT_ALPHA_BITS & byte ); // leave as double to postpone the frsp...
  51. alpha /= PAINT_ALPHA_BITS;
  52. alpha = clamp( alpha, 0.0, 1.0 );
  53. return alpha; // ...to here
  54. }
  55. CMatPaintmaps::CMatPaintmaps( void )
  56. {
  57. m_pDataManager = NULL;
  58. m_nUpdatingPaintmapsStackDepth = 0;
  59. m_nLockedPaintmap = -1;
  60. }
  61. bool CMatPaintmaps::IsEnabled( void )
  62. {
  63. return (m_pDataManager != NULL);
  64. }
  65. void CMatPaintmaps::RegisterPaintmapDataManager( IPaintmapDataManager *pDataManager )
  66. {
  67. m_pDataManager = pDataManager;
  68. RegisterPaintColors();
  69. }
  70. void CMatPaintmaps::BeginPaintTextureAllocation( int iPaintmapCount )
  71. {
  72. CleanupPaintmaps();
  73. m_pDataManager->BeginPaintmapsDataAllocation( iPaintmapCount );
  74. }
  75. void CMatPaintmaps::EndPaintTextureAllocation( void )
  76. {
  77. //do we need to do anything?
  78. }
  79. void CMatPaintmaps::ReleasePaintmaps( void )
  80. {
  81. // clean up paint textures, leave the paint data alone
  82. for( int i = 0; i < m_PaintmapTextureHandles.Count(); i++ )
  83. {
  84. g_pShaderAPI->DeleteTexture( m_PaintmapTextureHandles[i] );
  85. }
  86. m_PaintmapTextureHandles.RemoveAll();
  87. }
  88. void CMatPaintmaps::RestorePaintmaps( int nNumLightmaps )
  89. {
  90. Assert( m_PaintmapTextureHandles.Count() == 0 );
  91. // reallocate + update paint textures
  92. for ( int i=0; i<nNumLightmaps; ++i )
  93. {
  94. int width, height;
  95. m_pDataManager->GetPaintmapSize( i, width, height );
  96. AllocatePaintmapTexture( i, width, height );
  97. }
  98. m_pDataManager->OnRestorePaintmaps();
  99. }
  100. void CMatPaintmaps::CleanupPaintmaps( void )
  101. {
  102. for( int i = 0; i < m_PaintmapTextureHandles.Count(); i++ )
  103. {
  104. g_pShaderAPI->DeleteTexture( m_PaintmapTextureHandles[i] );
  105. }
  106. m_PaintmapTextureHandles.RemoveAll();
  107. if( m_pDataManager )
  108. {
  109. m_pDataManager->DestroyPaintmapsData();
  110. }
  111. }
  112. ShaderAPITextureHandle_t CMatPaintmaps::GetPaintmapPageTextureHandle( int paintmap )
  113. {
  114. //test new texture
  115. if( paintmap >= 0 && paintmap < m_PaintmapTextureHandles.Count() )
  116. {
  117. return m_PaintmapTextureHandles[paintmap];
  118. }
  119. return INVALID_SHADERAPI_TEXTURE_HANDLE;
  120. }
  121. void CMatPaintmaps::BeginUpdatePaintmaps()
  122. {
  123. CMatCallQueue *pCallQueue = GetMaterialSystem()->GetRenderContextInternal()->GetCallQueueInternal();
  124. if ( pCallQueue )
  125. {
  126. pCallQueue->QueueCall( this, &CMatPaintmaps::BeginUpdatePaintmaps );
  127. return;
  128. }
  129. m_nUpdatingPaintmapsStackDepth++;
  130. }
  131. void CMatPaintmaps::FillRect( int paintmap, Rect_t* RESTRICT pRect, BYTE* RESTRICT pPaintData, Rect_t* RESTRICT pSubRect /*= NULL*/ ) RESTRICT
  132. {
  133. VPROF("CMatPaintmaps::FillRect");
  134. int width, height;
  135. m_pDataManager->GetPaintmapSize( paintmap, width, height );
  136. // trap corrupted paint rect
  137. // TODO: Server writing to and Client reading from rect list in paint.cpp in the engine is not threadsafe
  138. if ( pRect->x < 0 || pRect->y < 0 || pRect->x >= width || pRect->y >= height ||
  139. pRect->width < 0 || pRect->height < 0 || pRect->width > width || pRect->height > height ||
  140. pRect->x + pRect->width > width || pRect->y + pRect->height > height )
  141. {
  142. DevWarning( "Corrupted paint rect\n" );
  143. return;
  144. }
  145. int rectOffset[2] = { pRect->x, pRect->y };
  146. if ( pSubRect )
  147. {
  148. rectOffset[0] -= pSubRect->x;
  149. rectOffset[1] -= pSubRect->y;
  150. }
  151. int index;
  152. for( int t = 0; t < pRect->height; ++t )
  153. {
  154. m_PaintmapPixelWriter.Seek( rectOffset[0], rectOffset[1] + t );
  155. index = ( t + pRect->y ) * width;
  156. for( int s = 0; s < pRect->width; ++s )
  157. {
  158. BYTE paintData = pPaintData[index + s + pRect->x];
  159. const Color &color = GetColor( paintData );
  160. float alpha = GetAlpha( paintData );
  161. #ifndef _PS3
  162. m_PaintmapPixelWriter.WritePixel( color.r(), color.g(), color.b(), alpha * 255 );
  163. #else // is PS3
  164. Assert( m_PaintmapPixelWriter.IsUsing16BitFloatFormat() );
  165. m_PaintmapPixelWriter.WritePixelNoAdvance16F(
  166. (float)color.r() / 255.0f,
  167. (float)color.g() / 255.0f,
  168. (float)color.b() / 255.0f,
  169. alpha );
  170. m_PaintmapPixelWriter.SkipPixels(1);
  171. #endif
  172. }
  173. }
  174. }
  175. void CMatPaintmaps::UpdatePaintmap( int paintmap, BYTE* pPaintData, int numRects, Rect_t* pRects )
  176. {
  177. VPROF("CMatPaintmaps::UpdatePaintmap");
  178. if ( paintmap >= GetMaterialSystem()->GetNumLightmapPages() || paintmap < 0 )
  179. {
  180. Error( "CMatPaintmaps::UpdatePaintmap paintmap=%d out of range\n", paintmap );
  181. return;
  182. }
  183. bool bLockSubRect = pRects != NULL;
  184. Rect_t rect;
  185. if ( bLockSubRect )
  186. {
  187. int minX = 512;
  188. int minY = 512;
  189. int maxX = 0;
  190. int maxY = 0;
  191. // find min/max rect
  192. for ( int i=0; i<numRects; ++i )
  193. {
  194. Rect_t* pCurrentRect = &pRects[i];
  195. minX = MIN( pCurrentRect->x, minX );
  196. minY = MIN( pCurrentRect->y, minY );
  197. maxX = MAX( pCurrentRect->x + pCurrentRect->width, maxX );
  198. maxY = MAX( pCurrentRect->y + pCurrentRect->height, maxY );
  199. }
  200. rect.x = minX;
  201. rect.y = minY;
  202. rect.width = maxX - minX;
  203. rect.height = maxY - minY;
  204. }
  205. else
  206. {
  207. rect.x = rect.y = 0;
  208. m_pDataManager->GetPaintmapSize( paintmap, rect.width, rect.height );
  209. }
  210. if ( bLockSubRect )
  211. {
  212. g_pShaderAPI->ModifyTexture( m_PaintmapTextureHandles[paintmap] );
  213. if ( !g_pShaderAPI->TexLock( 0, 0, rect.x, rect.y, rect.width, rect.height, m_PaintmapPixelWriter ) )
  214. {
  215. Assert("Failed to lock paint texture!");
  216. return;
  217. }
  218. }
  219. else
  220. {
  221. if ( !LockPaintmap( paintmap ) )
  222. {
  223. Assert("Failed to lock paint texture!");
  224. return;
  225. }
  226. }
  227. // modify texture!
  228. if ( pRects )
  229. {
  230. for ( int i=0; i<numRects; ++i )
  231. {
  232. FillRect( paintmap, &pRects[i], pPaintData, &rect );
  233. }
  234. }
  235. else
  236. {
  237. FillRect( paintmap, &rect, pPaintData );
  238. }
  239. if ( bLockSubRect )
  240. {
  241. g_pShaderAPI->TexUnlock();
  242. }
  243. }
  244. void CMatPaintmaps::EndUpdatePaintmaps()
  245. {
  246. CMatCallQueue *pCallQueue = GetMaterialSystem()->GetRenderContextInternal()->GetCallQueueInternal();
  247. if ( pCallQueue )
  248. {
  249. pCallQueue->QueueCall( this, &CMatPaintmaps::EndUpdatePaintmaps );
  250. return;
  251. }
  252. m_nUpdatingPaintmapsStackDepth--;
  253. Assert( m_nUpdatingPaintmapsStackDepth >= 0 );
  254. if( m_nUpdatingPaintmapsStackDepth <= 0 && m_nLockedPaintmap != -1 )
  255. {
  256. g_pShaderAPI->TexUnlock();
  257. m_nLockedPaintmap = -1;
  258. }
  259. }
  260. ConVar mat_dynamicPaintmaps( "mat_dynamicPaintmaps", "0", FCVAR_CHEAT );
  261. void CMatPaintmaps::AllocatePaintmapTexture( int paintmap, int iWidth, int iHeight )
  262. {
  263. // allocate paint texture
  264. int flags = 0;
  265. bool bUseDynamicTextures = HardwareConfig()->PreferDynamicTextures() && mat_dynamicPaintmaps.GetBool();
  266. if ( bUseDynamicTextures || IsPS3() ) // On PS3, we need the dynamic flag as a hint that we're going to update this texture incrementally in the future
  267. {
  268. flags |= TEXTURE_CREATE_DYNAMIC;
  269. }
  270. else
  271. {
  272. flags |= TEXTURE_CREATE_MANAGED;
  273. }
  274. //flags |= TEXTUREFLAGS_PROCEDURAL;
  275. m_PaintmapTextureHandles.EnsureCount( paintmap + 1 );
  276. char debugName[256];
  277. Q_snprintf( debugName, sizeof( debugName ), "[paintmap %d]", paintmap );
  278. ImageFormat imageFormat;
  279. #if !defined( _X360 )
  280. imageFormat = IMAGE_FORMAT_RGBA8888;
  281. #else
  282. imageFormat = IMAGE_FORMAT_LINEAR_RGBA8888;
  283. #endif
  284. #ifdef _PS3
  285. // PS3 needs 16F textures...but the HDR_TYPE_FLOAT codepath has a lot of other baggage with it. Just lie here.
  286. imageFormat = IMAGE_FORMAT_RGBA16161616F;
  287. #endif // _PS3
  288. m_PaintmapTextureHandles[paintmap] = g_pShaderAPI->CreateTexture(
  289. iWidth, iHeight, 1,
  290. imageFormat,
  291. 1, 1, flags, debugName, TEXTURE_GROUP_LIGHTMAP ); // don't mipmap Paintmaps
  292. Assert( m_PaintmapTextureHandles[paintmap] != INVALID_SHADERAPI_TEXTURE_HANDLE );
  293. // Load up the texture data
  294. g_pShaderAPI->ModifyTexture( m_PaintmapTextureHandles[paintmap] );
  295. g_pShaderAPI->TexMinFilter( SHADER_TEXFILTERMODE_LINEAR );
  296. g_pShaderAPI->TexMagFilter( SHADER_TEXFILTERMODE_LINEAR );
  297. // Blat out the paintmap bits
  298. InitPaintmapBits( paintmap );
  299. }
  300. void CMatPaintmaps::AllocatePaintmap( int paintmap, int iWidth, int iHeight )
  301. {
  302. if( !IsEnabled() )
  303. return;
  304. // allocate paint data
  305. m_pDataManager->AllocatePaintmapData( paintmap, iWidth, iHeight );
  306. // allocate paint texture
  307. AllocatePaintmapTexture( paintmap, iWidth, iHeight );
  308. }
  309. void CMatPaintmaps::InitPaintmapBits( int paintmap )
  310. {
  311. CPixelWriter writer;
  312. int width, height;
  313. m_pDataManager->GetPaintmapSize( paintmap, width, height );
  314. g_pShaderAPI->ModifyTexture( m_PaintmapTextureHandles[paintmap] );
  315. if ( !g_pShaderAPI->TexLock( 0, 0, 0, 0, width, height, writer ) )
  316. return;
  317. // This always needs to be initialized fully to black
  318. void *pBits = writer.GetPixelMemory();
  319. memset( pBits, 0, width * height * writer.GetPixelSize() );
  320. g_pShaderAPI->TexUnlock();
  321. }
  322. bool CMatPaintmaps::LockPaintmap( int paintmap )
  323. {
  324. if( m_nLockedPaintmap != -1 )
  325. {
  326. g_pShaderAPI->TexUnlock();
  327. }
  328. g_pShaderAPI->ModifyTexture( m_PaintmapTextureHandles[paintmap] );
  329. int width, height;
  330. m_pDataManager->GetPaintmapSize( paintmap, width, height );
  331. if ( !g_pShaderAPI->TexLock( 0, 0, 0, 0, width, height, m_PaintmapPixelWriter ) )
  332. {
  333. Assert( 0 );
  334. return false;
  335. }
  336. m_nLockedPaintmap = paintmap;
  337. return true;
  338. }