Files
2025-11-24 14:19:51 +05:30

814 lines
26 KiB
C++

/* ------------------------------------------------------------------------------------------------------------------------------------ */
// Portions of this file have been written by using the "Compress YCOCgDXT" sample as a reference.
// Please refer to http://developer.download.nvidia.com/SDK/10/opengl/samples.html#compress_YCoCgDXT for more information.
/* ------------------------------------------------------------------------------------------------------------------------------------ */
/*
* This file was taken from RakNet 4.082.
* Please see licenses/RakNet license.txt for the underlying license and related copyright.
*
* Modified work: Copyright (c) 2020, SLikeSoft UG (haftungsbeschränkt)
*
* This source code was modified by SLikeSoft. Modifications are licensed under the MIT-style
* license found in the license.txt file in the root directory of this source tree.
*/
/* ------------------------------------------------------------------------------------------------------------------------------------ */
// Includes
#include <windows.h>
#include <assert.h>
#include "DXTCompressor.h"
#include "FrameBufferRenderBuffer.hpp"
#include "ShaderSource.h"
#include "OpenGLWindow.hpp"
#include <map>
/* ------------------------------------------------------------------------------------------------------------------------------------ */
// Enable performance timing
// #define DXTCOMPRESSOR_ENABLE_PERFORMANCE_TIMING
/* ------------------------------------------------------------------------------------------------------------------------------------ */
// Link with these libraries
#pragma comment(lib, "glutstatic")
#pragma comment(lib, "glew32")
#pragma comment(lib, "cg")
#pragma comment(lib, "cgGL")
/* ------------------------------------------------------------------------------------------------------------------------------------ */
// Defines
#define DXTCOMPRESSOR_WINDOW_WIDTH 640
#define DXTCOMPRESSOR_WINDOW_HEIGHT 480
/* ------------------------------------------------------------------------------------------------------------------------------------ */
// Static class data
int DXTCompressor::m_initRefCount = 0;
CGcontext DXTCompressor::m_cgContext;
CGprofile DXTCompressor::m_cgVProfile;
CGprofile DXTCompressor::m_cgFProfile;
CGprogram DXTCompressor::m_compressVProg;
CGprogram DXTCompressor::m_compressDXT1RGBAFProg;
CGprogram DXTCompressor::m_compressDXT5RGBAFProg;
CGprogram DXTCompressor::m_compressDXT1BGRAFProg;
CGprogram DXTCompressor::m_compressDXT5BGRAFProg;
int DXTCompressor::m_numIterations = 0;
int DXTCompressor::m_currentImageWidth = 0;
int DXTCompressor::m_currentImageHeight = 0;
float DXTCompressor::m_lastCompressionTime = 0;
float DXTCompressor::m_accumulatedTime = 0;
float DXTCompressor::m_timeRunningCompressionShader = 0;
float DXTCompressor::m_timeCopyingPixelDataToCPU = 0;
/* ------------------------------------------------------------------------------------------------------------------------------------ */
// Hash table to store framebuffer objects
struct FramebufferObjectKeyCompare
{
bool operator()(int s1, int s2) const
{
return s1 < s2;
}
};
typedef int FramebufferObjectKey;
typedef class map< FramebufferObjectKey, FramebufferObject*, FramebufferObjectKeyCompare > FramebufferObjectHashtable;
// The hashtable
FramebufferObjectHashtable s_frameBuffersHash;
// Hashkey generation
FramebufferObjectKey GetHashKey( CompressionType compressionType, int width, int height )
{
return (int(compressionType) + width + (width*height));
}
/* ------------------------------------------------------------------------------------------------------------------------------------ */
#ifdef DXTCOMPRESSOR_ENABLE_PERFORMANCE_TIMING
// Typedef ticks
typedef __int64 Ticks;
inline Ticks GetTicks()
{
Ticks ticks;
QueryPerformanceCounter( (LARGE_INTEGER*) &ticks);
return ticks;
}
inline float TicksToMilliseconds( Ticks ticks )
{
LARGE_INTEGER freq;
QueryPerformanceFrequency(&freq);
return float(float(ticks) * 1000.0f / float(freq.QuadPart));
}
const int TIMER_STACK_SIZE = 256;
static int g_currentStackId = 0;
static Ticks g_startTrack[ TIMER_STACK_SIZE ];
static Ticks g_endTrack[ TIMER_STACK_SIZE ];
// Used for tracking time
inline void StartTracking()
{
g_startTrack[ g_currentStackId++ ] = GetTicks();
}
inline void EndTracking()
{
g_endTrack[ --g_currentStackId ] = GetTicks();
}
inline float GetDeltaTimeInSeconds()
{
Ticks delta = g_endTrack[ g_currentStackId ] - g_startTrack[ g_currentStackId ];
return TicksToMilliseconds( delta ) / 1000.0f;
}
inline float GetDeltaTimeInMilliseconds()
{
Ticks delta = g_endTrack[ g_currentStackId ] - g_startTrack[ g_currentStackId ];
return TicksToMilliseconds( delta );
}
#endif // #ifdef DXTCOMPRESSOR_ENABLE_PERFORMANCE_TIMING
/* ------------------------------------------------------------------------------------------------------------------------------------ */
DXTCompressor::DXTCompressor()
{
m_imageWidth = 0;
m_imageHeight = 0;
m_compressionType = DXT1;
m_pCompressFbo = 0;
m_compressFboTex = 0;
}
/* ------------------------------------------------------------------------------------------------------------------------------------ */
void DXTCompressor::cgErrorCallback()
{
CGerror lastError = cgGetError();
if( lastError )
{
printf( "%s\n", cgGetErrorString( lastError ) );
printf( "%s\n", cgGetLastListing( m_cgContext ) );
assert( false );
}
}
/* ------------------------------------------------------------------------------------------------------------------------------------ */
bool DXTCompressor::Initialize()
{
if( m_initRefCount == 0 )
{
if( !InitOpenGL() )
return false;
if( !InitCG() )
return false;
}
m_initRefCount++;
return true;
}
/* ------------------------------------------------------------------------------------------------------------------------------------ */
void DXTCompressor::Shutdown()
{
if( m_initRefCount > 0 )
m_initRefCount--;
if( m_initRefCount == 0 )
{
// Deallocate buffers
DeallocateBuffers();
// Shutdown cg stuff
cgGLDisableProfile(m_cgVProfile);
cgGLDisableProfile(m_cgFProfile);
cgGLUnloadProgram( m_compressVProg );
cgGLUnloadProgram( m_compressDXT1RGBAFProg );
cgGLUnloadProgram( m_compressDXT5RGBAFProg );
cgGLUnloadProgram( m_compressDXT1BGRAFProg );
cgGLUnloadProgram( m_compressDXT5BGRAFProg );
cgDestroyContext(m_cgContext);
// Kill the OpenGL window
KillGLWindow();
}
}
/* ------------------------------------------------------------------------------------------------------------------------------------ */
bool DXTCompressor::InitOpenGL()
{
bool bFullscreen = false;
#if 1
// Compute desktop window width and height
HWND desktopHwnd = GetDesktopWindow();
RECT windowRect;
GetWindowRect( desktopHwnd, &windowRect );
int windowWidth = windowRect.right - windowRect.left;
int windowHeight = windowRect.bottom - windowRect.top;
bFullscreen = true;
#else
int windowWidth = 640;
int windowHeight = 480;
#endif
// Create the window; this is needed in order to invoke OpenGL commands
BOOL windowCreateSuccess = CreateGLWindow( "Testing", windowWidth, windowHeight, 32, bFullscreen, true );
if( !windowCreateSuccess )
return false;
// Int GLEW
glewInit();
// Make sure these extensions are supported
if (!glewIsSupported(
"GL_VERSION_2_0 "
"GL_ARB_vertex_program "
"GL_ARB_fragment_program "
"GL_NV_gpu_program4 "
"GL_ARB_pixel_buffer_object "
"GL_EXT_framebuffer_object "
"GL_ARB_texture_compression "
"GL_EXT_texture_compression_s3tc "
"GL_EXT_texture_integer "
))
{
printf("Unable to load required OpenGL extension!\n");
return false;
}
// Enable depth testing
glEnable(GL_DEPTH_TEST);
glClearColor(0.2, 0.2, 0.2, 1.0);
// Report any errors to the console screen
glutReportErrors();
// Success
return true;
}
/* ------------------------------------------------------------------------------------------------------------------------------------ */
bool DXTCompressor::InitCG()
{
// Create Cg Context
m_cgContext = cgCreateContext();
cgSetErrorCallback( cgErrorCallback );
// Load Cg programs
m_cgVProfile = cgGLGetLatestProfile( CG_GL_VERTEX );
m_cgFProfile = cgGLGetLatestProfile( CG_GL_FRAGMENT );
// Shader compile options...
const char *args[] =
{
"-unroll", "all",
0,
};
m_compressVProg = cgCreateProgram( m_cgContext, CG_SOURCE, pDXTCompressorShaderSource, m_cgVProfile, "compress_vp", args );
cgGLLoadProgram( m_compressVProg );
m_compressDXT1RGBAFProg = cgCreateProgram( m_cgContext, CG_SOURCE, pDXTCompressorShaderSource, m_cgFProfile, "compress_DXT1_RGBA_fp", args );
cgGLLoadProgram( m_compressDXT1RGBAFProg );
m_compressDXT1BGRAFProg = cgCreateProgram( m_cgContext, CG_SOURCE, pDXTCompressorShaderSource, m_cgFProfile, "compress_DXT1_BGRA_fp", args );
cgGLLoadProgram( m_compressDXT1BGRAFProg );
m_compressDXT5RGBAFProg = cgCreateProgram( m_cgContext, CG_SOURCE, pDXTCompressorShaderSource, m_cgFProfile, "compress_YCoCgDXT5_RGBA_fp", args );
cgGLLoadProgram( m_compressDXT5RGBAFProg );
m_compressDXT5BGRAFProg = cgCreateProgram( m_cgContext, CG_SOURCE, pDXTCompressorShaderSource, m_cgFProfile, "compress_YCoCgDXT5_BGRA_fp", args );
cgGLLoadProgram( m_compressDXT5BGRAFProg );
return true;
}
/* ------------------------------------------------------------------------------------------------------------------------------------ */
bool DXTCompressor::IsInitialized()
{
return (m_initRefCount != 0);
}
/* ------------------------------------------------------------------------------------------------------------------------------------ */
static GLuint CreateTexture( GLenum target, GLint internalformat, GLenum format, GLenum type, int w, int h )
{
GLuint tex;
glGenTextures(1, &tex);
glBindTexture(target, tex);
glTexParameteri(target, GL_TEXTURE_MIN_FILTER, GL_NEAREST);
glTexParameteri(target, GL_TEXTURE_MAG_FILTER, GL_NEAREST);
glTexParameteri(target, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE);
glTexParameteri(target, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE);
glTexImage2D(target, 0, internalformat, w, h, 0, format, type, 0);
return tex;
}
/* ------------------------------------------------------------------------------------------------------------------------------------ */
FramebufferObject* DXTCompressor::RequestFBO( CompressionType compressionType, int width, int height )
{
// Get hash key
FramebufferObjectKey hashKey = GetHashKey( compressionType, width, height );
// See if we have it in the hash
if( s_frameBuffersHash.find( hashKey ) != s_frameBuffersHash.end() )
{
return s_frameBuffersHash[ hashKey ];
}
// Create the texture
GLuint newTextureID = 0;
FramebufferObject* pNewFrameBufferObject = new FramebufferObject();
if( compressionType == DXT1 )
{
newTextureID = CreateTexture(GL_TEXTURE_2D, GL_LUMINANCE_ALPHA32UI_EXT, GL_LUMINANCE_ALPHA_INTEGER_EXT, GL_INT, width/4, height/4);
}
else if( compressionType == DXT5_YCOCG )
{
newTextureID = CreateTexture(GL_TEXTURE_2D, GL_RGBA32UI_EXT, GL_RGBA_INTEGER_EXT, GL_INT, width/4, height/4);
}
// Attach texture to framebuffer object
pNewFrameBufferObject->Bind();
pNewFrameBufferObject->AttachTexture(GL_TEXTURE_2D, newTextureID, GL_COLOR_ATTACHMENT0_EXT);
pNewFrameBufferObject->IsValid();
FramebufferObject::Disable();
// Add to hash
s_frameBuffersHash[ hashKey ] = pNewFrameBufferObject;
// Return
return pNewFrameBufferObject;
}
/* ------------------------------------------------------------------------------------------------------------------------------------ */
void DXTCompressor::DeallocateBuffers()
{
FramebufferObjectHashtable::iterator iter = s_frameBuffersHash.begin();
while( iter != s_frameBuffersHash.end() )
{
// Delete object
FramebufferObject* pFrameBufferObject = iter->second;
GLuint textureID = pFrameBufferObject->GetAttachedTextureID();
glDeleteTextures(1, &textureID);
delete pFrameBufferObject;
// Bump
++iter;
}
}
/* ------------------------------------------------------------------------------------------------------------------------------------ */
static inline void SetParameter( CGprogram prog, char *name, float x, float y=0.0, float z=0.0, float w=0.0 )
{
CGparameter param = cgGetNamedParameter( prog, name );
if( param )
{
cgGLSetParameter4f( param, x, y, z, w );
}
}
/* ------------------------------------------------------------------------------------------------------------------------------------ */
void DXTCompressor::SetShaderConstants()
{
SetParameter( m_compressDXT1RGBAFProg, "imageSize", m_imageWidth, m_imageHeight );
SetParameter( m_compressDXT5RGBAFProg, "imageSize", m_imageWidth, m_imageHeight );
SetParameter( m_compressDXT1BGRAFProg, "imageSize", m_imageWidth, m_imageHeight );
SetParameter( m_compressDXT5BGRAFProg, "imageSize", m_imageWidth, m_imageHeight );
}
/* ------------------------------------------------------------------------------------------------------------------------------------ */
static inline void DrawQuad()
{
glBegin(GL_QUADS);
glTexCoord2f(0.0, 0.0); glVertex2f(-1.0, -1.0);
glTexCoord2f(1.0, 0.0); glVertex2f(1.0, -1.0);
glTexCoord2f(1.0, 1.0); glVertex2f(1.0, 1.0);
glTexCoord2f(0.0, 1.0); glVertex2f(-1.0, 1.0);
glEnd();
}
/* ------------------------------------------------------------------------------------------------------------------------------------ */
void DXTCompressor::CompressInternal(bool sourceFormatIsBGRA)
{
#ifdef DXTCOMPRESSOR_ENABLE_PERFORMANCE_TIMING
StartTracking();
#endif
glViewport(0, 0, m_imageWidth/4, m_imageHeight/4);
glDisable(GL_DEPTH_TEST);
cgGLBindProgram(m_compressVProg);
cgGLEnableProfile(m_cgVProfile);
if( m_compressionType == DXT5_YCOCG )
{
if (sourceFormatIsBGRA==false)
cgGLBindProgram(m_compressDXT5RGBAFProg);
else
cgGLBindProgram(m_compressDXT5BGRAFProg);
}
else if( m_compressionType == DXT1 )
{
if (sourceFormatIsBGRA==false)
cgGLBindProgram(m_compressDXT1RGBAFProg);
else
cgGLBindProgram(m_compressDXT1BGRAFProg);
}
else
{
assert(false );
}
cgGLEnableProfile(m_cgFProfile);
glBindTexture(GL_TEXTURE_2D, m_imageTexId);
SetShaderConstants();
DrawQuad();
cgGLDisableProfile(m_cgVProfile);
cgGLDisableProfile(m_cgFProfile);
#ifdef DXTCOMPRESSOR_ENABLE_PERFORMANCE_TIMING
glFinish();
EndTracking();
m_timeRunningCompressionShader += GetDeltaTimeInMilliseconds();
#endif
}
/* ------------------------------------------------------------------------------------------------------------------------------------ */
int DXTCompressor::GetBufferSize( CompressionType compressionType, int inputWidth, int inputHeight )
{
if( compressionType == DXT5_YCOCG )
{
int size = (inputWidth/4)*(inputHeight/4)*8;
return sizeof(GLushort)*size;
}
else
{
int size = (inputWidth/4)*(inputHeight/4)*4;
return sizeof(GLushort)*size;
}
}
/* ------------------------------------------------------------------------------------------------------------------------------------ */
void DXTCompressor::DoCompression( void* ppOutputData, bool sourceFormatIsBGRA )
{
if( m_compressionType == DXT5_YCOCG )
{
// Render to integer fbo
m_pCompressFbo->Bind();
CompressInternal(sourceFormatIsBGRA);
// Readback data to host
int size = (m_imageWidth/4)*(m_imageHeight/4)*8;
GLushort *data = (GLushort *) ppOutputData;
// Copy pixel data
#ifdef DXTCOMPRESSOR_ENABLE_PERFORMANCE_TIMING
StartTracking();
#endif
glReadBuffer(GL_COLOR_ATTACHMENT0_EXT);
glReadPixels(0, 0, m_imageWidth/4, m_imageHeight/4, GL_RGBA_INTEGER_EXT, GL_UNSIGNED_INT, data);
FramebufferObject::Disable();
#ifdef DXTCOMPRESSOR_ENABLE_PERFORMANCE_TIMING
EndTracking();
m_timeCopyingPixelDataToCPU += GetDeltaTimeInMilliseconds();
#endif
}
else if( m_compressionType == DXT1 )
{
// Render to integer fbo
m_pCompressFbo->Bind();
CompressInternal(sourceFormatIsBGRA);
// Readback data to host
int size = (m_imageWidth/4)*(m_imageHeight/4)*4;
GLushort *data = (GLushort *) ppOutputData;
// Copy pixel data
#ifdef DXTCOMPRESSOR_ENABLE_PERFORMANCE_TIMING
StartTracking();
#endif
glReadBuffer(GL_COLOR_ATTACHMENT0_EXT);
glReadPixels(0, 0, m_imageWidth/4, m_imageHeight/4, GL_LUMINANCE_ALPHA_INTEGER_EXT, GL_UNSIGNED_INT, data);
FramebufferObject::Disable();
#ifdef DXTCOMPRESSOR_ENABLE_PERFORMANCE_TIMING
EndTracking();
m_timeCopyingPixelDataToCPU += GetDeltaTimeInMilliseconds();
#endif
}
}
/* ------------------------------------------------------------------------------------------------------------------------------------ */
bool DXTCompressor::CompressImageData( CompressionType compressionType, const void *inputRGBA, int inputWidth, int inputHeight, void *outputData, bool bDisplayResults, bool sourceFormatIsBGRA )
{
// Make sure we're initialized
if( !IsInitialized() )
{
printf( "You need to initialize DXTCompressor before calling compress!\n " );
return false;
}
// Make sure the source width and height are divisible by 4
// This is a requirement by the DXT compression algorithm
if( !( (inputWidth%4)==0 && (inputHeight%4)==0 ) )
{
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 );
return false;
}
// Accumulate width and heights
m_numIterations++;
m_currentImageWidth = inputWidth;
m_currentImageHeight = inputHeight;
// Instantiate the compressor
DXTCompressor compressor;
compressor.m_imageWidth = inputWidth;
compressor.m_imageHeight = inputHeight;
compressor.m_compressionType = compressionType;
// Make a copy of the source data and flip the Y. OpenGL rendering has Y going down
/*
char* pFlippedData = new char[ inputWidth*inputHeight*4 ];
{
const int rowSize = inputWidth*4;
char* pRunnerDest = pFlippedData + (rowSize*(inputHeight-1));
const char* pRunnerSrc = (const char*)inputRGBA;
for( int row = inputHeight-1; row >=0; row-- )
{
memcpy( pRunnerDest, pRunnerSrc, rowSize );
pRunnerSrc += rowSize;
pRunnerDest -= rowSize;
}
}
*/
// Generate a texture and bind it to the input source data
glGenTextures(1, &compressor.m_imageTexId);
glBindTexture(GL_TEXTURE_2D, compressor.m_imageTexId);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
//glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA8, inputWidth, inputHeight, 0, GL_RGBA, GL_UNSIGNED_BYTE, (const GLvoid*)pFlippedData );
glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA8, inputWidth, inputHeight, 0, GL_RGBA, GL_UNSIGNED_BYTE, (const GLvoid*)inputRGBA );
// Request FBO
compressor.m_pCompressFbo = RequestFBO( compressionType, inputWidth, inputHeight );
compressor.m_compressFboTex = compressor.m_pCompressFbo->GetAttachedTextureID();
#ifdef DXTCOMPRESSOR_ENABLE_PERFORMANCE_TIMING
// Start the clock
StartTracking();
#endif
// Do the compression
compressor.DoCompression( outputData, sourceFormatIsBGRA );
#ifdef DXTCOMPRESSOR_ENABLE_PERFORMANCE_TIMING
// Stop the clock
EndTracking();
m_lastCompressionTime = GetDeltaTimeInMilliseconds();
m_accumulatedTime += m_lastCompressionTime;
printf( "Compression time: %f ms\n", m_lastCompressionTime );
#endif
// Display texture? Only DXT1 supported here.
if( bDisplayResults && compressionType == DXT1 )
{
// Create empty dxt1 compressed texture
GLuint tempDisplayTexture;
int dxt1Size = (inputWidth/4)*(inputHeight/4)*8;
GLubyte * tempPadData = new GLubyte [dxt1Size];
memset(tempPadData, 0, dxt1Size);
glGenTextures(1, &tempDisplayTexture);
glBindTexture(GL_TEXTURE_2D, tempDisplayTexture);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE);
glCompressedTexImage2DARB(GL_TEXTURE_2D, 0, GL_COMPRESSED_RGB_S3TC_DXT1_EXT, inputWidth, inputHeight, 0, dxt1Size, tempPadData);
delete [] tempPadData;
// Re-upload the texture to VRAM for display
int size = (inputWidth/4)*(inputHeight/4);
glBindTexture(GL_TEXTURE_2D, tempDisplayTexture);
glCompressedTexImage2DARB(GL_TEXTURE_2D, 0, GL_COMPRESSED_RGB_S3TC_DXT1_EXT, inputWidth, inputHeight, 0, size*8, outputData);
// Display the texture
DisplayTexture( tempDisplayTexture, inputWidth, inputHeight );
// Get rid of the texture
glDeleteTextures(1, &tempDisplayTexture);
}
// Clean up
// delete [] pFlippedData;
// pFlippedData = nullptr;
glDeleteTextures( 1, &compressor.m_imageTexId );
// Done
return true;
}
#include <stdlib.h>
#include "DDSHeader.h"
/* ------------------------------------------------------------------------------------------------------------------------------------ */
int DXTCompressor::GetDDSHeaderSize(void)
{
return sizeof(DDS_header);
}
/* ------------------------------------------------------------------------------------------------------------------------------------ */
void DXTCompressor::WriteDDSHeader( CompressionType compressionType, int width, int height, int compresedDataLength, void *outputData )
{
DDS_header* pHdr = (DDS_header*)outputData;
memset( pHdr, 0, sizeof(DDS_header) );
pHdr->dwMagic = DDS_MAGIC;
pHdr->dwSize = 124;
pHdr->dwFlags = DDSD_CAPS | DDSD_HEIGHT | DDSD_WIDTH | DDSD_PIXELFORMAT;
pHdr->dwWidth = width;
pHdr->dwHeight = height;
pHdr->sCaps.dwCaps1 = DDSCAPS_TEXTURE | DDSD_CAPS;
pHdr->sPixelFormat.dwSize = 32;
pHdr->sPixelFormat.dwFlags = DDPF_FOURCC;
if( compressionType == DXT1 )
pHdr->sPixelFormat.dwFourCC = D3DFMT_DXT1;
else if( compressionType == DXT5_YCOCG )
pHdr->sPixelFormat.dwFourCC = D3DFMT_DXT5;
}
/* ------------------------------------------------------------------------------------------------------------------------------------ */
void DXTCompressor::WriteDDSMemoryFile( CompressionType compressionType, int width, int height, const void* pCompressedData, int compresedDataLength, void **outputData, int *outputLength )
{
// Allocate the header + data
int totalSize = sizeof(DDS_header) + compresedDataLength;
void* pMemFile = new char[ totalSize ];
// Write the header
WriteDDSHeader(compressionType, width, height, compresedDataLength, pMemFile );
// Write the data
void* pData = ((char*)pMemFile + sizeof(DDS_header));
memcpy( pData, pCompressedData, compresedDataLength );
// Return data to user
*outputData = pMemFile;
*outputLength = totalSize;
}
/* ------------------------------------------------------------------------------------------------------------------------------------ */
void DXTCompressor::PrintPerformanceLog()
{
#ifdef DXTCOMPRESSOR_ENABLE_PERFORMANCE_TIMING
// Compute
float mPixelsPerSec = (m_currentImageWidth*m_currentImageHeight*m_numIterations) / (m_accumulatedTime*1e6/1000.0f);
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 );
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 );
// Reset stats
m_currentImageWidth = 0;
m_currentImageHeight = 0;
m_numIterations = 0;
m_accumulatedTime = 0;
m_timeCopyingPixelDataToCPU = 0;
m_timeRunningCompressionShader = 0;
#endif
}
/* ------------------------------------------------------------------------------------------------------------------------------------ */
static void glutPrint(float x, float y, const char *s, void *font)
{
int i, len;
glRasterPos2f(x, y);
len = (int) strlen(s);
for (i = 0; i < len; i++) {
glutBitmapCharacter(font, s[i]);
}
}
static bool DrawTexture( GLuint textureID )
{
glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
glViewport(0,0,windowWidth,windowHeight);
glMatrixMode(GL_PROJECTION);
glPushMatrix();
glLoadIdentity();
glOrtho(-1.0, 1.0, -1.0, 1.0, -1.0, 1.0);
glMatrixMode(GL_MODELVIEW);
glLoadIdentity();
glActiveTexture(GL_TEXTURE0);
glBindTexture(GL_TEXTURE_2D, textureID);
glEnable(GL_TEXTURE_2D);
glDisable(GL_DEPTH_TEST);
glColor3f(1.0, 1.0, 1.0);
DrawQuad();
glDisable(GL_TEXTURE_2D);
glLoadIdentity();
glutPrint(-0.95, -0.95, "DXT1 compressed (push ESC to close)", GLUT_BITMAP_9_BY_15);
glMatrixMode(GL_PROJECTION);
glPopMatrix();
return true;
}
void ClientResize(HWND hWnd, int nWidth, int nHeight)
{
RECT rcClient, rcWindow;
POINT ptDiff;
GetClientRect(hWnd, &rcClient);
GetWindowRect(hWnd, &rcWindow);
ptDiff.x = (rcWindow.right - rcWindow.left) - rcClient.right;
ptDiff.y = (rcWindow.bottom - rcWindow.top) - rcClient.bottom;
MoveWindow(hWnd,rcWindow.left, rcWindow.top, nWidth + ptDiff.x, nHeight + ptDiff.y, TRUE);
}
void DXTCompressor::DisplayTexture( GLuint textureID, int texW, int texH )
{
// Show the window
ShowWindow(hWnd,SW_SHOW);
// Resize the window to match the size of the texture
ClientResize( hWnd, texW, texH );
// Windows message pump
MSG msg;
BOOL done=FALSE;
while(!done)
{
if (PeekMessage(&msg, nullptr,0,0,PM_REMOVE))
{
if (msg.message==WM_QUIT)
{
done=TRUE;
}
else
{
TranslateMessage(&msg);
DispatchMessage(&msg);
}
}
else
{
if ((active && !DrawTexture( textureID )) || keys[VK_ESCAPE])
{
keys[VK_ESCAPE] = FALSE;
done=TRUE;
}
else
{
SwapBuffers(hDC);
}
}
}
// Hide the window
ShowWindow(hWnd,SW_HIDE);
}