DXTCompressor.cpp 25 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804
  1. /* ------------------------------------------------------------------------------------------------------------------------------------ */
  2. // Portions of this file have been written by using the "Compress YCOCgDXT" sample as a reference.
  3. // Please refer to http://developer.download.nvidia.com/SDK/10/opengl/samples.html#compress_YCoCgDXT for more information.
  4. /* ------------------------------------------------------------------------------------------------------------------------------------ */
  5. /* ------------------------------------------------------------------------------------------------------------------------------------ */
  6. // Includes
  7. #include <windows.h>
  8. #include <assert.h>
  9. #include "DXTCompressor.h"
  10. #include "FrameBufferRenderBuffer.hpp"
  11. #include "ShaderSource.h"
  12. #include "OpenGLWindow.hpp"
  13. #include <map>
  14. /* ------------------------------------------------------------------------------------------------------------------------------------ */
  15. // Enable performance timing
  16. // #define DXTCOMPRESSOR_ENABLE_PERFORMANCE_TIMING
  17. /* ------------------------------------------------------------------------------------------------------------------------------------ */
  18. // Link with these libraries
  19. #pragma comment(lib, "glutstatic")
  20. #pragma comment(lib, "glew32")
  21. #pragma comment(lib, "cg")
  22. #pragma comment(lib, "cgGL")
  23. /* ------------------------------------------------------------------------------------------------------------------------------------ */
  24. // Defines
  25. #define DXTCOMPRESSOR_WINDOW_WIDTH 640
  26. #define DXTCOMPRESSOR_WINDOW_HEIGHT 480
  27. /* ------------------------------------------------------------------------------------------------------------------------------------ */
  28. // Static class data
  29. int DXTCompressor::m_initRefCount = 0;
  30. CGcontext DXTCompressor::m_cgContext;
  31. CGprofile DXTCompressor::m_cgVProfile;
  32. CGprofile DXTCompressor::m_cgFProfile;
  33. CGprogram DXTCompressor::m_compressVProg;
  34. CGprogram DXTCompressor::m_compressDXT1RGBAFProg;
  35. CGprogram DXTCompressor::m_compressDXT5RGBAFProg;
  36. CGprogram DXTCompressor::m_compressDXT1BGRAFProg;
  37. CGprogram DXTCompressor::m_compressDXT5BGRAFProg;
  38. int DXTCompressor::m_numIterations = 0;
  39. int DXTCompressor::m_currentImageWidth = 0;
  40. int DXTCompressor::m_currentImageHeight = 0;
  41. float DXTCompressor::m_lastCompressionTime = 0;
  42. float DXTCompressor::m_accumulatedTime = 0;
  43. float DXTCompressor::m_timeRunningCompressionShader = 0;
  44. float DXTCompressor::m_timeCopyingPixelDataToCPU = 0;
  45. /* ------------------------------------------------------------------------------------------------------------------------------------ */
  46. // Hash table to store framebuffer objects
  47. struct FramebufferObjectKeyCompare
  48. {
  49. bool operator()(int s1, int s2) const
  50. {
  51. return s1 < s2;
  52. }
  53. };
  54. typedef int FramebufferObjectKey;
  55. typedef class map< FramebufferObjectKey, FramebufferObject*, FramebufferObjectKeyCompare > FramebufferObjectHashtable;
  56. // The hashtable
  57. FramebufferObjectHashtable s_frameBuffersHash;
  58. // Hashkey generation
  59. FramebufferObjectKey GetHashKey( CompressionType compressionType, int width, int height )
  60. {
  61. return (int(compressionType) + width + (width*height));
  62. }
  63. /* ------------------------------------------------------------------------------------------------------------------------------------ */
  64. #ifdef DXTCOMPRESSOR_ENABLE_PERFORMANCE_TIMING
  65. // Typedef ticks
  66. typedef __int64 Ticks;
  67. inline Ticks GetTicks()
  68. {
  69. Ticks ticks;
  70. QueryPerformanceCounter( (LARGE_INTEGER*) &ticks);
  71. return ticks;
  72. }
  73. inline float TicksToMilliseconds( Ticks ticks )
  74. {
  75. LARGE_INTEGER freq;
  76. QueryPerformanceFrequency(&freq);
  77. return float(float(ticks) * 1000.0f / float(freq.QuadPart));
  78. }
  79. const int TIMER_STACK_SIZE = 256;
  80. static int g_currentStackId = 0;
  81. static Ticks g_startTrack[ TIMER_STACK_SIZE ];
  82. static Ticks g_endTrack[ TIMER_STACK_SIZE ];
  83. // Used for tracking time
  84. inline void StartTracking()
  85. {
  86. g_startTrack[ g_currentStackId++ ] = GetTicks();
  87. }
  88. inline void EndTracking()
  89. {
  90. g_endTrack[ --g_currentStackId ] = GetTicks();
  91. }
  92. inline float GetDeltaTimeInSeconds()
  93. {
  94. Ticks delta = g_endTrack[ g_currentStackId ] - g_startTrack[ g_currentStackId ];
  95. return TicksToMilliseconds( delta ) / 1000.0f;
  96. }
  97. inline float GetDeltaTimeInMilliseconds()
  98. {
  99. Ticks delta = g_endTrack[ g_currentStackId ] - g_startTrack[ g_currentStackId ];
  100. return TicksToMilliseconds( delta );
  101. }
  102. #endif // #ifdef DXTCOMPRESSOR_ENABLE_PERFORMANCE_TIMING
  103. /* ------------------------------------------------------------------------------------------------------------------------------------ */
  104. DXTCompressor::DXTCompressor()
  105. {
  106. m_imageWidth = 0;
  107. m_imageHeight = 0;
  108. m_compressionType = DXT1;
  109. m_pCompressFbo = 0;
  110. m_compressFboTex = 0;
  111. }
  112. /* ------------------------------------------------------------------------------------------------------------------------------------ */
  113. void DXTCompressor::cgErrorCallback()
  114. {
  115. CGerror lastError = cgGetError();
  116. if( lastError )
  117. {
  118. printf( "%s\n", cgGetErrorString( lastError ) );
  119. printf( "%s\n", cgGetLastListing( m_cgContext ) );
  120. assert( false );
  121. }
  122. }
  123. /* ------------------------------------------------------------------------------------------------------------------------------------ */
  124. bool DXTCompressor::Initialize()
  125. {
  126. if( m_initRefCount == 0 )
  127. {
  128. if( !InitOpenGL() )
  129. return false;
  130. if( !InitCG() )
  131. return false;
  132. }
  133. m_initRefCount++;
  134. return true;
  135. }
  136. /* ------------------------------------------------------------------------------------------------------------------------------------ */
  137. void DXTCompressor::Shutdown()
  138. {
  139. if( m_initRefCount > 0 )
  140. m_initRefCount--;
  141. if( m_initRefCount == 0 )
  142. {
  143. // Deallocate buffers
  144. DeallocateBuffers();
  145. // Shutdown cg stuff
  146. cgGLDisableProfile(m_cgVProfile);
  147. cgGLDisableProfile(m_cgFProfile);
  148. cgGLUnloadProgram( m_compressVProg );
  149. cgGLUnloadProgram( m_compressDXT1RGBAFProg );
  150. cgGLUnloadProgram( m_compressDXT5RGBAFProg );
  151. cgGLUnloadProgram( m_compressDXT1BGRAFProg );
  152. cgGLUnloadProgram( m_compressDXT5BGRAFProg );
  153. cgDestroyContext(m_cgContext);
  154. // Kill the OpenGL window
  155. KillGLWindow();
  156. }
  157. }
  158. /* ------------------------------------------------------------------------------------------------------------------------------------ */
  159. bool DXTCompressor::InitOpenGL()
  160. {
  161. bool bFullscreen = false;
  162. #if 1
  163. // Compute desktop window width and height
  164. HWND desktopHwnd = GetDesktopWindow();
  165. RECT windowRect;
  166. GetWindowRect( desktopHwnd, &windowRect );
  167. int windowWidth = windowRect.right - windowRect.left;
  168. int windowHeight = windowRect.bottom - windowRect.top;
  169. bFullscreen = true;
  170. #else
  171. int windowWidth = 640;
  172. int windowHeight = 480;
  173. #endif
  174. // Create the window; this is needed in order to invoke OpenGL commands
  175. BOOL windowCreateSuccess = CreateGLWindow( "Testing", windowWidth, windowHeight, 32, bFullscreen, true );
  176. if( !windowCreateSuccess )
  177. return false;
  178. // Int GLEW
  179. glewInit();
  180. // Make sure these extensions are supported
  181. if (!glewIsSupported(
  182. "GL_VERSION_2_0 "
  183. "GL_ARB_vertex_program "
  184. "GL_ARB_fragment_program "
  185. "GL_NV_gpu_program4 "
  186. "GL_ARB_pixel_buffer_object "
  187. "GL_EXT_framebuffer_object "
  188. "GL_ARB_texture_compression "
  189. "GL_EXT_texture_compression_s3tc "
  190. "GL_EXT_texture_integer "
  191. ))
  192. {
  193. printf("Unable to load required OpenGL extension!\n");
  194. return false;
  195. }
  196. // Enable depth testing
  197. glEnable(GL_DEPTH_TEST);
  198. glClearColor(0.2, 0.2, 0.2, 1.0);
  199. // Report any errors to the console screen
  200. glutReportErrors();
  201. // Success
  202. return true;
  203. }
  204. /* ------------------------------------------------------------------------------------------------------------------------------------ */
  205. bool DXTCompressor::InitCG()
  206. {
  207. // Create Cg Context
  208. m_cgContext = cgCreateContext();
  209. cgSetErrorCallback( cgErrorCallback );
  210. // Load Cg programs
  211. m_cgVProfile = cgGLGetLatestProfile( CG_GL_VERTEX );
  212. m_cgFProfile = cgGLGetLatestProfile( CG_GL_FRAGMENT );
  213. // Shader compile options...
  214. const char *args[] =
  215. {
  216. "-unroll", "all",
  217. 0,
  218. };
  219. m_compressVProg = cgCreateProgram( m_cgContext, CG_SOURCE, pDXTCompressorShaderSource, m_cgVProfile, "compress_vp", args );
  220. cgGLLoadProgram( m_compressVProg );
  221. m_compressDXT1RGBAFProg = cgCreateProgram( m_cgContext, CG_SOURCE, pDXTCompressorShaderSource, m_cgFProfile, "compress_DXT1_RGBA_fp", args );
  222. cgGLLoadProgram( m_compressDXT1RGBAFProg );
  223. m_compressDXT1BGRAFProg = cgCreateProgram( m_cgContext, CG_SOURCE, pDXTCompressorShaderSource, m_cgFProfile, "compress_DXT1_BGRA_fp", args );
  224. cgGLLoadProgram( m_compressDXT1BGRAFProg );
  225. m_compressDXT5RGBAFProg = cgCreateProgram( m_cgContext, CG_SOURCE, pDXTCompressorShaderSource, m_cgFProfile, "compress_YCoCgDXT5_RGBA_fp", args );
  226. cgGLLoadProgram( m_compressDXT5RGBAFProg );
  227. m_compressDXT5BGRAFProg = cgCreateProgram( m_cgContext, CG_SOURCE, pDXTCompressorShaderSource, m_cgFProfile, "compress_YCoCgDXT5_BGRA_fp", args );
  228. cgGLLoadProgram( m_compressDXT5BGRAFProg );
  229. return true;
  230. }
  231. /* ------------------------------------------------------------------------------------------------------------------------------------ */
  232. bool DXTCompressor::IsInitialized()
  233. {
  234. return (m_initRefCount != 0);
  235. }
  236. /* ------------------------------------------------------------------------------------------------------------------------------------ */
  237. static GLuint CreateTexture( GLenum target, GLint internalformat, GLenum format, GLenum type, int w, int h )
  238. {
  239. GLuint tex;
  240. glGenTextures(1, &tex);
  241. glBindTexture(target, tex);
  242. glTexParameteri(target, GL_TEXTURE_MIN_FILTER, GL_NEAREST);
  243. glTexParameteri(target, GL_TEXTURE_MAG_FILTER, GL_NEAREST);
  244. glTexParameteri(target, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE);
  245. glTexParameteri(target, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE);
  246. glTexImage2D(target, 0, internalformat, w, h, 0, format, type, 0);
  247. return tex;
  248. }
  249. /* ------------------------------------------------------------------------------------------------------------------------------------ */
  250. FramebufferObject* DXTCompressor::RequestFBO( CompressionType compressionType, int width, int height )
  251. {
  252. // Get hash key
  253. FramebufferObjectKey hashKey = GetHashKey( compressionType, width, height );
  254. // See if we have it in the hash
  255. if( s_frameBuffersHash.find( hashKey ) != s_frameBuffersHash.end() )
  256. {
  257. return s_frameBuffersHash[ hashKey ];
  258. }
  259. // Create the texture
  260. GLuint newTextureID = 0;
  261. FramebufferObject* pNewFrameBufferObject = new FramebufferObject();
  262. if( compressionType == DXT1 )
  263. {
  264. newTextureID = CreateTexture(GL_TEXTURE_2D, GL_LUMINANCE_ALPHA32UI_EXT, GL_LUMINANCE_ALPHA_INTEGER_EXT, GL_INT, width/4, height/4);
  265. }
  266. else if( compressionType == DXT5_YCOCG )
  267. {
  268. newTextureID = CreateTexture(GL_TEXTURE_2D, GL_RGBA32UI_EXT, GL_RGBA_INTEGER_EXT, GL_INT, width/4, height/4);
  269. }
  270. // Attach texture to framebuffer object
  271. pNewFrameBufferObject->Bind();
  272. pNewFrameBufferObject->AttachTexture(GL_TEXTURE_2D, newTextureID, GL_COLOR_ATTACHMENT0_EXT);
  273. pNewFrameBufferObject->IsValid();
  274. FramebufferObject::Disable();
  275. // Add to hash
  276. s_frameBuffersHash[ hashKey ] = pNewFrameBufferObject;
  277. // Return
  278. return pNewFrameBufferObject;
  279. }
  280. /* ------------------------------------------------------------------------------------------------------------------------------------ */
  281. void DXTCompressor::DeallocateBuffers()
  282. {
  283. FramebufferObjectHashtable::iterator iter = s_frameBuffersHash.begin();
  284. while( iter != s_frameBuffersHash.end() )
  285. {
  286. // Delete object
  287. FramebufferObject* pFrameBufferObject = iter->second;
  288. GLuint textureID = pFrameBufferObject->GetAttachedTextureID();
  289. glDeleteTextures(1, &textureID);
  290. delete pFrameBufferObject;
  291. // Bump
  292. ++iter;
  293. }
  294. }
  295. /* ------------------------------------------------------------------------------------------------------------------------------------ */
  296. static inline void SetParameter( CGprogram prog, char *name, float x, float y=0.0, float z=0.0, float w=0.0 )
  297. {
  298. CGparameter param = cgGetNamedParameter( prog, name );
  299. if( param )
  300. {
  301. cgGLSetParameter4f( param, x, y, z, w );
  302. }
  303. }
  304. /* ------------------------------------------------------------------------------------------------------------------------------------ */
  305. void DXTCompressor::SetShaderConstants()
  306. {
  307. SetParameter( m_compressDXT1RGBAFProg, "imageSize", m_imageWidth, m_imageHeight );
  308. SetParameter( m_compressDXT5RGBAFProg, "imageSize", m_imageWidth, m_imageHeight );
  309. SetParameter( m_compressDXT1BGRAFProg, "imageSize", m_imageWidth, m_imageHeight );
  310. SetParameter( m_compressDXT5BGRAFProg, "imageSize", m_imageWidth, m_imageHeight );
  311. }
  312. /* ------------------------------------------------------------------------------------------------------------------------------------ */
  313. static inline void DrawQuad()
  314. {
  315. glBegin(GL_QUADS);
  316. glTexCoord2f(0.0, 0.0); glVertex2f(-1.0, -1.0);
  317. glTexCoord2f(1.0, 0.0); glVertex2f(1.0, -1.0);
  318. glTexCoord2f(1.0, 1.0); glVertex2f(1.0, 1.0);
  319. glTexCoord2f(0.0, 1.0); glVertex2f(-1.0, 1.0);
  320. glEnd();
  321. }
  322. /* ------------------------------------------------------------------------------------------------------------------------------------ */
  323. void DXTCompressor::CompressInternal(bool sourceFormatIsBGRA)
  324. {
  325. #ifdef DXTCOMPRESSOR_ENABLE_PERFORMANCE_TIMING
  326. StartTracking();
  327. #endif
  328. glViewport(0, 0, m_imageWidth/4, m_imageHeight/4);
  329. glDisable(GL_DEPTH_TEST);
  330. cgGLBindProgram(m_compressVProg);
  331. cgGLEnableProfile(m_cgVProfile);
  332. if( m_compressionType == DXT5_YCOCG )
  333. {
  334. if (sourceFormatIsBGRA==false)
  335. cgGLBindProgram(m_compressDXT5RGBAFProg);
  336. else
  337. cgGLBindProgram(m_compressDXT5BGRAFProg);
  338. }
  339. else if( m_compressionType == DXT1 )
  340. {
  341. if (sourceFormatIsBGRA==false)
  342. cgGLBindProgram(m_compressDXT1RGBAFProg);
  343. else
  344. cgGLBindProgram(m_compressDXT1BGRAFProg);
  345. }
  346. else
  347. {
  348. assert(false );
  349. }
  350. cgGLEnableProfile(m_cgFProfile);
  351. glBindTexture(GL_TEXTURE_2D, m_imageTexId);
  352. SetShaderConstants();
  353. DrawQuad();
  354. cgGLDisableProfile(m_cgVProfile);
  355. cgGLDisableProfile(m_cgFProfile);
  356. #ifdef DXTCOMPRESSOR_ENABLE_PERFORMANCE_TIMING
  357. glFinish();
  358. EndTracking();
  359. m_timeRunningCompressionShader += GetDeltaTimeInMilliseconds();
  360. #endif
  361. }
  362. /* ------------------------------------------------------------------------------------------------------------------------------------ */
  363. int DXTCompressor::GetBufferSize( CompressionType compressionType, int inputWidth, int inputHeight )
  364. {
  365. if( compressionType == DXT5_YCOCG )
  366. {
  367. int size = (inputWidth/4)*(inputHeight/4)*8;
  368. return sizeof(GLushort)*size;
  369. }
  370. else
  371. {
  372. int size = (inputWidth/4)*(inputHeight/4)*4;
  373. return sizeof(GLushort)*size;
  374. }
  375. }
  376. /* ------------------------------------------------------------------------------------------------------------------------------------ */
  377. void DXTCompressor::DoCompression( void* ppOutputData, bool sourceFormatIsBGRA )
  378. {
  379. if( m_compressionType == DXT5_YCOCG )
  380. {
  381. // Render to integer fbo
  382. m_pCompressFbo->Bind();
  383. CompressInternal(sourceFormatIsBGRA);
  384. // Readback data to host
  385. int size = (m_imageWidth/4)*(m_imageHeight/4)*8;
  386. GLushort *data = (GLushort *) ppOutputData;
  387. // Copy pixel data
  388. #ifdef DXTCOMPRESSOR_ENABLE_PERFORMANCE_TIMING
  389. StartTracking();
  390. #endif
  391. glReadBuffer(GL_COLOR_ATTACHMENT0_EXT);
  392. glReadPixels(0, 0, m_imageWidth/4, m_imageHeight/4, GL_RGBA_INTEGER_EXT, GL_UNSIGNED_INT, data);
  393. FramebufferObject::Disable();
  394. #ifdef DXTCOMPRESSOR_ENABLE_PERFORMANCE_TIMING
  395. EndTracking();
  396. m_timeCopyingPixelDataToCPU += GetDeltaTimeInMilliseconds();
  397. #endif
  398. }
  399. else if( m_compressionType == DXT1 )
  400. {
  401. // Render to integer fbo
  402. m_pCompressFbo->Bind();
  403. CompressInternal(sourceFormatIsBGRA);
  404. // Readback data to host
  405. int size = (m_imageWidth/4)*(m_imageHeight/4)*4;
  406. GLushort *data = (GLushort *) ppOutputData;
  407. // Copy pixel data
  408. #ifdef DXTCOMPRESSOR_ENABLE_PERFORMANCE_TIMING
  409. StartTracking();
  410. #endif
  411. glReadBuffer(GL_COLOR_ATTACHMENT0_EXT);
  412. glReadPixels(0, 0, m_imageWidth/4, m_imageHeight/4, GL_LUMINANCE_ALPHA_INTEGER_EXT, GL_UNSIGNED_INT, data);
  413. FramebufferObject::Disable();
  414. #ifdef DXTCOMPRESSOR_ENABLE_PERFORMANCE_TIMING
  415. EndTracking();
  416. m_timeCopyingPixelDataToCPU += GetDeltaTimeInMilliseconds();
  417. #endif
  418. }
  419. }
  420. /* ------------------------------------------------------------------------------------------------------------------------------------ */
  421. bool DXTCompressor::CompressImageData( CompressionType compressionType, const void *inputRGBA, int inputWidth, int inputHeight, void *outputData, bool bDisplayResults, bool sourceFormatIsBGRA )
  422. {
  423. // Make sure we're initialized
  424. if( !IsInitialized() )
  425. {
  426. printf( "You need to initialize DXTCompressor before calling compress!\n " );
  427. return false;
  428. }
  429. // Make sure the source width and height are divisible by 4
  430. // This is a requirement by the DXT compression algorithm
  431. if( !( (inputWidth%4)==0 && (inputHeight%4)==0 ) )
  432. {
  433. printf( "Error! Input image width and height must be multiple of 4, as required by DXT compression rules. You have passed in an image of %dx%d", inputWidth, inputHeight );
  434. return false;
  435. }
  436. // Accumulate width and heights
  437. m_numIterations++;
  438. m_currentImageWidth = inputWidth;
  439. m_currentImageHeight = inputHeight;
  440. // Instantiate the compressor
  441. DXTCompressor compressor;
  442. compressor.m_imageWidth = inputWidth;
  443. compressor.m_imageHeight = inputHeight;
  444. compressor.m_compressionType = compressionType;
  445. // Make a copy of the source data and flip the Y. OpenGL rendering has Y going down
  446. /*
  447. char* pFlippedData = new char[ inputWidth*inputHeight*4 ];
  448. {
  449. const int rowSize = inputWidth*4;
  450. char* pRunnerDest = pFlippedData + (rowSize*(inputHeight-1));
  451. const char* pRunnerSrc = (const char*)inputRGBA;
  452. for( int row = inputHeight-1; row >=0; row-- )
  453. {
  454. memcpy( pRunnerDest, pRunnerSrc, rowSize );
  455. pRunnerSrc += rowSize;
  456. pRunnerDest -= rowSize;
  457. }
  458. }
  459. */
  460. // Generate a texture and bind it to the input source data
  461. glGenTextures(1, &compressor.m_imageTexId);
  462. glBindTexture(GL_TEXTURE_2D, compressor.m_imageTexId);
  463. glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
  464. glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
  465. //glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA8, inputWidth, inputHeight, 0, GL_RGBA, GL_UNSIGNED_BYTE, (const GLvoid*)pFlippedData );
  466. glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA8, inputWidth, inputHeight, 0, GL_RGBA, GL_UNSIGNED_BYTE, (const GLvoid*)inputRGBA );
  467. // Request FBO
  468. compressor.m_pCompressFbo = RequestFBO( compressionType, inputWidth, inputHeight );
  469. compressor.m_compressFboTex = compressor.m_pCompressFbo->GetAttachedTextureID();
  470. #ifdef DXTCOMPRESSOR_ENABLE_PERFORMANCE_TIMING
  471. // Start the clock
  472. StartTracking();
  473. #endif
  474. // Do the compression
  475. compressor.DoCompression( outputData, sourceFormatIsBGRA );
  476. #ifdef DXTCOMPRESSOR_ENABLE_PERFORMANCE_TIMING
  477. // Stop the clock
  478. EndTracking();
  479. m_lastCompressionTime = GetDeltaTimeInMilliseconds();
  480. m_accumulatedTime += m_lastCompressionTime;
  481. printf( "Compression time: %f ms\n", m_lastCompressionTime );
  482. #endif
  483. // Display texture? Only DXT1 supported here.
  484. if( bDisplayResults && compressionType == DXT1 )
  485. {
  486. // Create empty dxt1 compressed texture
  487. GLuint tempDisplayTexture;
  488. int dxt1Size = (inputWidth/4)*(inputHeight/4)*8;
  489. GLubyte * tempPadData = new GLubyte [dxt1Size];
  490. memset(tempPadData, 0, dxt1Size);
  491. glGenTextures(1, &tempDisplayTexture);
  492. glBindTexture(GL_TEXTURE_2D, tempDisplayTexture);
  493. glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST);
  494. glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST);
  495. glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE);
  496. glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE);
  497. glCompressedTexImage2DARB(GL_TEXTURE_2D, 0, GL_COMPRESSED_RGB_S3TC_DXT1_EXT, inputWidth, inputHeight, 0, dxt1Size, tempPadData);
  498. delete [] tempPadData;
  499. // Re-upload the texture to VRAM for display
  500. int size = (inputWidth/4)*(inputHeight/4);
  501. glBindTexture(GL_TEXTURE_2D, tempDisplayTexture);
  502. glCompressedTexImage2DARB(GL_TEXTURE_2D, 0, GL_COMPRESSED_RGB_S3TC_DXT1_EXT, inputWidth, inputHeight, 0, size*8, outputData);
  503. // Display the texture
  504. DisplayTexture( tempDisplayTexture, inputWidth, inputHeight );
  505. // Get rid of the texture
  506. glDeleteTextures(1, &tempDisplayTexture);
  507. }
  508. // Clean up
  509. // delete [] pFlippedData;
  510. // pFlippedData = NULL;
  511. glDeleteTextures( 1, &compressor.m_imageTexId );
  512. // Done
  513. return true;
  514. }
  515. #include <stdlib.h>
  516. #include "DDSHeader.h"
  517. /* ------------------------------------------------------------------------------------------------------------------------------------ */
  518. int DXTCompressor::GetDDSHeaderSize(void)
  519. {
  520. return sizeof(DDS_header);
  521. }
  522. /* ------------------------------------------------------------------------------------------------------------------------------------ */
  523. void DXTCompressor::WriteDDSHeader( CompressionType compressionType, int width, int height, int compresedDataLength, void *outputData )
  524. {
  525. DDS_header* pHdr = (DDS_header*)outputData;
  526. memset( pHdr, 0, sizeof(DDS_header) );
  527. pHdr->dwMagic = DDS_MAGIC;
  528. pHdr->dwSize = 124;
  529. pHdr->dwFlags = DDSD_CAPS | DDSD_HEIGHT | DDSD_WIDTH | DDSD_PIXELFORMAT;
  530. pHdr->dwWidth = width;
  531. pHdr->dwHeight = height;
  532. pHdr->sCaps.dwCaps1 = DDSCAPS_TEXTURE | DDSD_CAPS;
  533. pHdr->sPixelFormat.dwSize = 32;
  534. pHdr->sPixelFormat.dwFlags = DDPF_FOURCC;
  535. if( compressionType == DXT1 )
  536. pHdr->sPixelFormat.dwFourCC = D3DFMT_DXT1;
  537. else if( compressionType == DXT5_YCOCG )
  538. pHdr->sPixelFormat.dwFourCC = D3DFMT_DXT5;
  539. }
  540. /* ------------------------------------------------------------------------------------------------------------------------------------ */
  541. void DXTCompressor::WriteDDSMemoryFile( CompressionType compressionType, int width, int height, const void* pCompressedData, int compresedDataLength, void **outputData, int *outputLength )
  542. {
  543. // Allocate the header + data
  544. int totalSize = sizeof(DDS_header) + compresedDataLength;
  545. void* pMemFile = new char[ totalSize ];
  546. // Write the header
  547. WriteDDSHeader(compressionType, width, height, compresedDataLength, pMemFile );
  548. // Write the data
  549. void* pData = ((char*)pMemFile + sizeof(DDS_header));
  550. memcpy( pData, pCompressedData, compresedDataLength );
  551. // Return data to user
  552. *outputData = pMemFile;
  553. *outputLength = totalSize;
  554. }
  555. /* ------------------------------------------------------------------------------------------------------------------------------------ */
  556. void DXTCompressor::PrintPerformanceLog()
  557. {
  558. #ifdef DXTCOMPRESSOR_ENABLE_PERFORMANCE_TIMING
  559. // Compute
  560. float mPixelsPerSec = (m_currentImageWidth*m_currentImageHeight*m_numIterations) / (m_accumulatedTime*1e6/1000.0f);
  561. printf( "For %dx%d image, compression took %f ms, Average of %f mPixelsPerSec (mPixels/sec)\n", m_currentImageWidth, m_currentImageHeight, m_accumulatedTime/m_numIterations, mPixelsPerSec );
  562. printf( "%f ms was spent in running compression shader, %f ms was spent copying pixel data to main memory for the cpu\n", m_timeRunningCompressionShader/m_numIterations, m_timeCopyingPixelDataToCPU/m_numIterations );
  563. // Reset stats
  564. m_currentImageWidth = 0;
  565. m_currentImageHeight = 0;
  566. m_numIterations = 0;
  567. m_accumulatedTime = 0;
  568. m_timeCopyingPixelDataToCPU = 0;
  569. m_timeRunningCompressionShader = 0;
  570. #endif
  571. }
  572. /* ------------------------------------------------------------------------------------------------------------------------------------ */
  573. static void glutPrint(float x, float y, const char *s, void *font)
  574. {
  575. int i, len;
  576. glRasterPos2f(x, y);
  577. len = (int) strlen(s);
  578. for (i = 0; i < len; i++) {
  579. glutBitmapCharacter(font, s[i]);
  580. }
  581. }
  582. static bool DrawTexture( GLuint textureID )
  583. {
  584. glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
  585. glViewport(0,0,windowWidth,windowHeight);
  586. glMatrixMode(GL_PROJECTION);
  587. glPushMatrix();
  588. glLoadIdentity();
  589. glOrtho(-1.0, 1.0, -1.0, 1.0, -1.0, 1.0);
  590. glMatrixMode(GL_MODELVIEW);
  591. glLoadIdentity();
  592. glActiveTexture(GL_TEXTURE0);
  593. glBindTexture(GL_TEXTURE_2D, textureID);
  594. glEnable(GL_TEXTURE_2D);
  595. glDisable(GL_DEPTH_TEST);
  596. glColor3f(1.0, 1.0, 1.0);
  597. DrawQuad();
  598. glDisable(GL_TEXTURE_2D);
  599. glLoadIdentity();
  600. glutPrint(-0.95, -0.95, "DXT1 compressed (push ESC to close)", GLUT_BITMAP_9_BY_15);
  601. glMatrixMode(GL_PROJECTION);
  602. glPopMatrix();
  603. return true;
  604. }
  605. void ClientResize(HWND hWnd, int nWidth, int nHeight)
  606. {
  607. RECT rcClient, rcWindow;
  608. POINT ptDiff;
  609. GetClientRect(hWnd, &rcClient);
  610. GetWindowRect(hWnd, &rcWindow);
  611. ptDiff.x = (rcWindow.right - rcWindow.left) - rcClient.right;
  612. ptDiff.y = (rcWindow.bottom - rcWindow.top) - rcClient.bottom;
  613. MoveWindow(hWnd,rcWindow.left, rcWindow.top, nWidth + ptDiff.x, nHeight + ptDiff.y, TRUE);
  614. }
  615. void DXTCompressor::DisplayTexture( GLuint textureID, int texW, int texH )
  616. {
  617. // Show the window
  618. ShowWindow(hWnd,SW_SHOW);
  619. // Resize the window to match the size of the texture
  620. ClientResize( hWnd, texW, texH );
  621. // Windows message pump
  622. MSG msg;
  623. BOOL done=FALSE;
  624. while(!done)
  625. {
  626. if (PeekMessage(&msg,NULL,0,0,PM_REMOVE))
  627. {
  628. if (msg.message==WM_QUIT)
  629. {
  630. done=TRUE;
  631. }
  632. else
  633. {
  634. TranslateMessage(&msg);
  635. DispatchMessage(&msg);
  636. }
  637. }
  638. else
  639. {
  640. if ((active && !DrawTexture( textureID )) || keys[VK_ESCAPE])
  641. {
  642. keys[VK_ESCAPE] = FALSE;
  643. done=TRUE;
  644. }
  645. else
  646. {
  647. SwapBuffers(hDC);
  648. }
  649. }
  650. }
  651. // Hide the window
  652. ShowWindow(hWnd,SW_HIDE);
  653. }
粤ICP备19079148号