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