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