This commit is contained in:
2025-11-24 14:19:51 +05:30
commit f5c1412b28
6734 changed files with 1527575 additions and 0 deletions

View File

@ -0,0 +1,145 @@
/*
* This file was taken from RakNet 4.082 without any modifications.
* Please see licenses/RakNet license.txt for the underlying license and related copyright.
*/
#ifndef __DDS_HEADER_H__
#define __DDS_HEADER_H__
// little-endian, of course
#define DDS_MAGIC 0x20534444
// DDS_header.dwFlags
#define DDSD_CAPS 0x00000001
#define DDSD_HEIGHT 0x00000002
#define DDSD_WIDTH 0x00000004
#define DDSD_PITCH 0x00000008
#define DDSD_PIXELFORMAT 0x00001000
#define DDSD_MIPMAPCOUNT 0x00020000
#define DDSD_LINEARSIZE 0x00080000
#define DDSD_DEPTH 0x00800000
// DDS_header.sPixelFormat.dwFlags
#define DDPF_ALPHAPIXELS 0x00000001
#define DDPF_FOURCC 0x00000004
#define DDPF_INDEXED 0x00000020
#define DDPF_RGB 0x00000040
// DDS_header.sCaps.dwCaps1
#define DDSCAPS_COMPLEX 0x00000008
#define DDSCAPS_TEXTURE 0x00001000
#define DDSCAPS_MIPMAP 0x00400000
// DDS_header.sCaps.dwCaps2
#define DDSCAPS2_CUBEMAP 0x00000200
#define DDSCAPS2_CUBEMAP_POSITIVEX 0x00000400
#define DDSCAPS2_CUBEMAP_NEGATIVEX 0x00000800
#define DDSCAPS2_CUBEMAP_POSITIVEY 0x00001000
#define DDSCAPS2_CUBEMAP_NEGATIVEY 0x00002000
#define DDSCAPS2_CUBEMAP_POSITIVEZ 0x00004000
#define DDSCAPS2_CUBEMAP_NEGATIVEZ 0x00008000
#define DDSCAPS2_VOLUME 0x00200000
#define D3DFMT_DXT1 '1TXD' // DXT1 compression texture format
#define D3DFMT_DXT2 '2TXD' // DXT2 compression texture format
#define D3DFMT_DXT3 '3TXD' // DXT3 compression texture format
#define D3DFMT_DXT4 '4TXD' // DXT4 compression texture format
#define D3DFMT_DXT5 '5TXD' // DXT5 compression texture format
#define PF_IS_DXT1(pf) \
((pf.dwFlags & DDPF_FOURCC) && \
(pf.dwFourCC == D3DFMT_DXT1))
#define PF_IS_DXT3(pf) \
((pf.dwFlags & DDPF_FOURCC) && \
(pf.dwFourCC == D3DFMT_DXT3))
#define PF_IS_DXT5(pf) \
((pf.dwFlags & DDPF_FOURCC) && \
(pf.dwFourCC == D3DFMT_DXT5))
#define PF_IS_BGRA8(pf) \
((pf.dwFlags & DDPF_RGB) && \
(pf.dwFlags & DDPF_ALPHAPIXELS) && \
(pf.dwRGBBitCount == 32) && \
(pf.dwRBitMask == 0xff0000) && \
(pf.dwGBitMask == 0xff00) && \
(pf.dwBBitMask == 0xff) && \
(pf.dwAlphaBitMask == 0xff000000U))
#define PF_IS_BGR8(pf) \
((pf.dwFlags & DDPF_ALPHAPIXELS) && \
!(pf.dwFlags & DDPF_ALPHAPIXELS) && \
(pf.dwRGBBitCount == 24) && \
(pf.dwRBitMask == 0xff0000) && \
(pf.dwGBitMask == 0xff00) && \
(pf.dwBBitMask == 0xff))
#define PF_IS_BGR5A1(pf) \
((pf.dwFlags & DDPF_RGB) && \
(pf.dwFlags & DDPF_ALPHAPIXELS) && \
(pf.dwRGBBitCount == 16) && \
(pf.dwRBitMask == 0x00007c00) && \
(pf.dwGBitMask == 0x000003e0) && \
(pf.dwBBitMask == 0x0000001f) && \
(pf.dwAlphaBitMask == 0x00008000))
#define PF_IS_BGR565(pf) \
((pf.dwFlags & DDPF_RGB) && \
!(pf.dwFlags & DDPF_ALPHAPIXELS) && \
(pf.dwRGBBitCount == 16) && \
(pf.dwRBitMask == 0x0000f800) && \
(pf.dwGBitMask == 0x000007e0) && \
(pf.dwBBitMask == 0x0000001f))
#define PF_IS_INDEX8(pf) \
((pf.dwFlags & DDPF_INDEXED) && \
(pf.dwRGBBitCount == 8))
union DDS_header
{
struct
{
unsigned int dwMagic;
unsigned int dwSize;
unsigned int dwFlags;
unsigned int dwHeight;
unsigned int dwWidth;
unsigned int dwPitchOrLinearSize;
unsigned int dwDepth;
unsigned int dwMipMapCount;
unsigned int dwReserved1[ 11 ];
// DDPIXELFORMAT
struct
{
unsigned int dwSize;
unsigned int dwFlags;
unsigned int dwFourCC;
unsigned int dwRGBBitCount;
unsigned int dwRBitMask;
unsigned int dwGBitMask;
unsigned int dwBBitMask;
unsigned int dwAlphaBitMask;
} sPixelFormat;
// DDCAPS2
struct
{
unsigned int dwCaps1;
unsigned int dwCaps2;
unsigned int dwDDSX;
unsigned int dwReserved;
} sCaps;
unsigned int dwReserved2;
};
char data[ 128 ];
};
#endif // mydds_h

View File

@ -0,0 +1,813 @@
/* ------------------------------------------------------------------------------------------------------------------------------------ */
// 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<68>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);
}

View File

@ -0,0 +1,98 @@
/*
* This file was taken from RakNet 4.082 without any modifications.
* Please see licenses/RakNet license.txt for the underlying license and related copyright.
*/
#ifndef __DXT_COMPRESSOR_H__
#define __DXT_COMPRESSOR_H__
/* ------------------------------------------------------------------------------------------------------------------------------------ */
// Includes
#include <GL/glew.h>
#include <GL/glut.h>
#include <Cg/cg.h>
#include <Cg/cgGL.h>
/* ------------------------------------------------------------------------------------------------------------------------------------ */
// Forward decls.
class FramebufferObject;
class Renderbuffer;
/* ------------------------------------------------------------------------------------------------------------------------------------ */
enum CompressionType
{
DXT1,
DXT5_YCOCG,
};
/* ------------------------------------------------------------------------------------------------------------------------------------ */
class DXTCompressor
{
public:
DXTCompressor();
public:
// These need to be called before using the compressor, and shutdown after using the compressor
static bool Initialize();
static void Shutdown();
// Compresses input data into the desired compressed format.
// The input data is assumed to be 32-bit RGBA (1 byte per channel).
// outputData should be allocated to at least GetBufferSize()
// This will return true if the compression is successful.
static bool CompressImageData( CompressionType compressionType, const void *inputRGBA, int inputWidth, int inputHeight, void *outputData, bool bDisplayResults, bool sourceFormatIsBGRA );
static int GetBufferSize(CompressionType compressionType, int inputWidth, int inputHeight );
// Saves the compressed data into a Microsoft DDS file.
static int GetDDSHeaderSize(void);
static void WriteDDSHeader( CompressionType compressionType, int width, int height, int compresedDataLength, void *outputData );
static void WriteDDSMemoryFile( CompressionType compressionType, int width, int height, const void* pCompressedData, int compresedDataLength, void **outputData, int *outputLength );
// Prints out the accumulated performance of the compressor
static void PrintPerformanceLog();
private:
void SetShaderConstants();
void CompressInternal( bool sourceFormatIsBGRA);
void DoCompression( void* ppOutputData, bool sourceFormatIsBGRA );
static bool InitOpenGL();
static bool InitCG();
static void cgErrorCallback();
static bool IsInitialized();
static void DisplayTexture( GLuint textureID, int texW, int texH );
static FramebufferObject* RequestFBO( CompressionType compressionType, int width, int height );
static void DeallocateBuffers();
private:
// Image related data
int m_imageWidth;
int m_imageHeight;
CompressionType m_compressionType;
GLuint m_imageTexId;
FramebufferObject* m_pCompressFbo;
GLuint m_compressFboTex;
// CG related data
static int m_initRefCount;
static CGcontext m_cgContext;
static CGprofile m_cgVProfile, m_cgFProfile;
static CGprogram m_compressVProg, m_compressDXT1RGBAFProg, m_compressDXT5RGBAFProg, m_compressDXT1BGRAFProg, m_compressDXT5BGRAFProg;
// Used to collect stats
static int m_numIterations;
static int m_currentImageWidth, m_currentImageHeight;
static float m_lastCompressionTime;
static float m_accumulatedTime;
static float m_timeRunningCompressionShader;
static float m_timeCopyingPixelDataToCPU;
};
#endif // __DXT_COMPRESSOR_H__

View File

@ -0,0 +1,639 @@
/*
Copyright (c) 2005,
Aaron Lefohn (lefohn@cs.ucdavis.edu)
Adam Moerschell (atmoerschell@ucdavis.edu)
All rights reserved.
This software is licensed under the BSD open-source license. See
http://www.opensource.org/licenses/bsd-license.php for more detail.
*************************************************************
Redistribution and use in source and binary forms, with or
without modification, are permitted provided that the following
conditions are met:
Redistributions of source code must retain the above copyright notice,
this list of conditions and the following disclaimer.
Redistributions in binary form must reproduce the above copyright notice,
this list of conditions and the following disclaimer in the documentation
and/or other materials provided with the distribution.
Neither the name of the University of Californa, Davis nor the names of
the contributors may be used to endorse or promote products derived
from this software without specific prior written permission.
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
"AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL
THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT,
INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE
GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF
THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY
OF SUCH DAMAGE.
*/
#ifndef __FRAMEBUFFERRENDERBUFFER_HPP__
#define __FRAMEBUFFERRENDERBUFFER_HPP__
#include <GL/glew.h>
#include <iostream>
/*!
FramebufferObject Class. This class encapsulates the FramebufferObject
(FBO) OpenGL spec. See the official spec at:
http://oss.sgi.com/projects/ogl-sample/registry/EXT/framebuffer_object.txt
for details.
A framebuffer object (FBO) is conceptually a structure containing pointers
to GPU memory. The memory pointed to is either an OpenGL texture or an
OpenGL RenderBuffer. FBOs can be used to render to one or more textures,
share depth buffers between multiple sets of color buffers/textures and
are a complete replacement for pbuffers.
Performance Notes:
1) It is more efficient (but not required) to call Bind()
on an FBO before making multiple method calls. For example:
FramebufferObject fbo;
fbo.Bind();
fbo.AttachTexture(GL_TEXTURE_2D, texId0, GL_COLOR_ATTACHMENT0_EXT);
fbo.AttachTexture(GL_TEXTURE_2D, texId1, GL_COLOR_ATTACHMENT1_EXT);
fbo.IsValid();
To provide a complete encapsulation, the following usage
pattern works correctly but is less efficient:
FramebufferObject fbo;
// NOTE : No Bind() call
fbo.AttachTexture(GL_TEXTURE_2D, texId0, GL_COLOR_ATTACHMENT0_EXT);
fbo.AttachTexture(GL_TEXTURE_2D, texId1, GL_COLOR_ATTACHMENT1_EXT);
fbo.IsValid();
The first usage pattern binds the FBO only once, whereas
the second usage binds/unbinds the FBO for each method call.
2) Use FramebufferObject::Disable() sparingly. We have intentionally
left out an "Unbind()" method because it is largely unnecessary
and encourages rendundant Bind/Unbind coding. Binding an FBO is
usually much faster than enabling/disabling a pbuffer, but is
still a costly operation. When switching between multiple FBOs
and a visible OpenGL framebuffer, the following usage pattern
is recommended:
FramebufferObject fbo1, fbo2;
fbo1.Bind();
... Render ...
// NOTE : No Unbind/Disable here...
fbo2.Bind();
... Render ...
// Disable FBO rendering and return to visible window
// OpenGL framebuffer.
FramebufferObject::Disable();
*/
class FramebufferObject
{
public:
/// Ctor/Dtor
FramebufferObject();
virtual ~FramebufferObject();
/// Bind this FBO as current render target
void Bind();
/// Bind a texture to the "attachment" point of this FBO
virtual void AttachTexture( GLenum texTarget,
GLuint texId,
GLenum attachment = GL_COLOR_ATTACHMENT0_EXT,
int mipLevel = 0,
int zSlice = 0 );
/// Bind an array of textures to multiple "attachment" points of this FBO
/// - By default, the first 'numTextures' attachments are used,
/// starting with GL_COLOR_ATTACHMENT0_EXT
virtual void AttachTextures( int numTextures,
GLenum texTarget[],
GLuint texId[],
GLenum attachment[] = NULL,
int mipLevel[] = NULL,
int zSlice[] = NULL );
/// Bind a render buffer to the "attachment" point of this FBO
virtual void AttachRenderBuffer( GLuint buffId,
GLenum attachment = GL_COLOR_ATTACHMENT0_EXT );
/// Bind an array of render buffers to corresponding "attachment" points
/// of this FBO.
/// - By default, the first 'numBuffers' attachments are used,
/// starting with GL_COLOR_ATTACHMENT0_EXT
virtual void AttachRenderBuffers( int numBuffers, GLuint buffId[],
GLenum attachment[] = NULL );
/// Free any resource bound to the "attachment" point of this FBO
void Unattach( GLenum attachment );
/// Free any resources bound to any attachment points of this FBO
void UnattachAll();
/// Is this FBO currently a valid render target?
/// - Sends output to std::cerr by default but can
/// be a user-defined C++ stream
///
/// NOTE : This function works correctly in debug build
/// mode but always returns "true" if NDEBUG is
/// is defined (optimized builds)
#ifndef NDEBUG
bool IsValid( std::ostream& ostr = std::cerr );
#else
bool IsValid( std::ostream& ostr = std::cerr ) {
return true;
}
#endif
/// BEGIN : Accessors
/// Is attached type GL_RENDERBUFFER_EXT or GL_TEXTURE?
GLenum GetAttachedType( GLenum attachment );
/// What is the Id of Renderbuffer/texture currently
/// attached to "attachement?"
GLuint GetAttachedId( GLenum attachment );
/// Which mipmap level is currently attached to "attachement?"
GLint GetAttachedMipLevel( GLenum attachment );
/// Which cube face is currently attached to "attachment?"
GLint GetAttachedCubeFace( GLenum attachment );
/// Which z-slice is currently attached to "attachment?"
GLint GetAttachedZSlice( GLenum attachment );
/// END : Accessors
GLuint GetAttachedTextureID() const { return m_attachedTexture; }
/// BEGIN : Static methods global to all FBOs
/// Return number of color attachments permitted
static int GetMaxColorAttachments();
/// Disable all FBO rendering and return to traditional,
/// windowing-system controlled framebuffer
/// NOTE:
/// This is NOT an "unbind" for this specific FBO, but rather
/// disables all FBO rendering. This call is intentionally "static"
/// and named "Disable" instead of "Unbind" for this reason. The
/// motivation for this strange semantic is performance. Providing
/// "Unbind" would likely lead to a large number of unnecessary
/// FBO enablings/disabling.
static void Disable();
/// END : Static methods global to all FBOs
protected:
void _GuardedBind();
void _GuardedUnbind();
void _FramebufferTextureND( GLenum attachment, GLenum texTarget,
GLuint texId, int mipLevel, int zSlice );
static GLuint _GenerateFboId();
private:
GLuint m_fboId;
GLint m_savedFboId;
GLuint m_attachedTexture;
};
#include <iostream>
using namespace std;
FramebufferObject::FramebufferObject()
: m_fboId(_GenerateFboId()),
m_savedFboId(0)
{
// Bind this FBO so that it actually gets created now
_GuardedBind();
_GuardedUnbind();
}
FramebufferObject::~FramebufferObject()
{
glDeleteFramebuffersEXT(1, &m_fboId);
}
void FramebufferObject::Bind()
{
glBindFramebufferEXT(GL_FRAMEBUFFER_EXT, m_fboId);
}
void FramebufferObject::Disable()
{
glBindFramebufferEXT(GL_FRAMEBUFFER_EXT, 0);
}
void
FramebufferObject::AttachTexture( GLenum texTarget, GLuint texId,
GLenum attachment, int mipLevel, int zSlice )
{
_GuardedBind();
/*
#ifndef NDEBUG
if( GetAttachedId(attachment) != texId ) {
#endif
*/
_FramebufferTextureND( attachment, texTarget,
texId, mipLevel, zSlice );
m_attachedTexture = texId;
/*
#ifndef NDEBUG
}
else {
cerr << "FramebufferObject::AttachTexture PERFORMANCE WARNING:\n"
<< "\tRedundant bind of texture (id = " << texId << ").\n"
<< "\tHINT : Compile with -DNDEBUG to remove this warning.\n";
}
#endif
*/
_GuardedUnbind();
}
void
FramebufferObject::AttachTextures( int numTextures, GLenum texTarget[], GLuint texId[],
GLenum attachment[], int mipLevel[], int zSlice[] )
{
for(int i = 0; i < numTextures; ++i) {
AttachTexture( texTarget[i], texId[i],
attachment ? attachment[i] : (GL_COLOR_ATTACHMENT0_EXT + i),
mipLevel ? mipLevel[i] : 0,
zSlice ? zSlice[i] : 0 );
}
}
void
FramebufferObject::AttachRenderBuffer( GLuint buffId, GLenum attachment )
{
_GuardedBind();
#ifndef NDEBUG
if( GetAttachedId(attachment) != buffId ) {
#endif
glFramebufferRenderbufferEXT(GL_FRAMEBUFFER_EXT, attachment,
GL_RENDERBUFFER_EXT, buffId);
#ifndef NDEBUG
}
else {
cerr << "FramebufferObject::AttachRenderBuffer PERFORMANCE WARNING:\n"
<< "\tRedundant bind of Renderbuffer (id = " << buffId << ")\n"
<< "\tHINT : Compile with -DNDEBUG to remove this warning.\n";
}
#endif
_GuardedUnbind();
}
void
FramebufferObject::AttachRenderBuffers( int numBuffers, GLuint buffId[], GLenum attachment[] )
{
for(int i = 0; i < numBuffers; ++i) {
AttachRenderBuffer( buffId[i],
attachment ? attachment[i] : (GL_COLOR_ATTACHMENT0_EXT + i) );
}
}
void
FramebufferObject::Unattach( GLenum attachment )
{
_GuardedBind();
GLenum type = GetAttachedType(attachment);
switch(type) {
case GL_NONE:
break;
case GL_RENDERBUFFER_EXT:
AttachRenderBuffer( 0, attachment );
break;
case GL_TEXTURE:
AttachTexture( GL_TEXTURE_2D, 0, attachment );
break;
default:
cerr << "FramebufferObject::unbind_attachment ERROR: Unknown attached resource type\n";
}
_GuardedUnbind();
}
void
FramebufferObject::UnattachAll()
{
int numAttachments = GetMaxColorAttachments();
for(int i = 0; i < numAttachments; ++i) {
Unattach( GL_COLOR_ATTACHMENT0_EXT + i );
}
}
GLint FramebufferObject::GetMaxColorAttachments()
{
GLint maxAttach = 0;
glGetIntegerv( GL_MAX_COLOR_ATTACHMENTS_EXT, &maxAttach );
return maxAttach;
}
GLuint FramebufferObject::_GenerateFboId()
{
GLuint id = 0;
glGenFramebuffersEXT(1, &id);
return id;
}
void FramebufferObject::_GuardedBind()
{
// Only binds if m_fboId is different than the currently bound FBO
glGetIntegerv( GL_FRAMEBUFFER_BINDING_EXT, &m_savedFboId );
if (m_fboId != (GLuint)m_savedFboId) {
glBindFramebufferEXT(GL_FRAMEBUFFER_EXT, m_fboId);
}
}
void FramebufferObject::_GuardedUnbind()
{
// Returns FBO binding to the previously enabled FBO
if (m_fboId != (GLuint)m_savedFboId) {
glBindFramebufferEXT(GL_FRAMEBUFFER_EXT, (GLuint)m_savedFboId);
}
}
void
FramebufferObject::_FramebufferTextureND( GLenum attachment, GLenum texTarget,
GLuint texId, int mipLevel,
int zSlice )
{
if (texTarget == GL_TEXTURE_1D) {
glFramebufferTexture1DEXT( GL_FRAMEBUFFER_EXT, attachment,
GL_TEXTURE_1D, texId, mipLevel );
}
else if (texTarget == GL_TEXTURE_3D) {
glFramebufferTexture3DEXT( GL_FRAMEBUFFER_EXT, attachment,
GL_TEXTURE_3D, texId, mipLevel, zSlice );
}
else {
// Default is GL_TEXTURE_2D, GL_TEXTURE_RECTANGLE_ARB, or cube faces
glFramebufferTexture2DEXT( GL_FRAMEBUFFER_EXT, attachment,
texTarget, texId, mipLevel );
}
}
#ifndef NDEBUG
bool FramebufferObject::IsValid( ostream& ostr )
{
_GuardedBind();
bool isOK = false;
GLenum status;
status = glCheckFramebufferStatusEXT(GL_FRAMEBUFFER_EXT);
switch(status) {
case GL_FRAMEBUFFER_COMPLETE_EXT: // Everything's OK
isOK = true;
break;
case GL_FRAMEBUFFER_INCOMPLETE_ATTACHMENT_EXT:
ostr << "glift::CheckFramebufferStatus() ERROR:\n\t"
<< "GL_FRAMEBUFFER_INCOMPLETE_ATTACHMENT_EXT\n";
isOK = false;
break;
case GL_FRAMEBUFFER_INCOMPLETE_MISSING_ATTACHMENT_EXT:
ostr << "glift::CheckFramebufferStatus() ERROR:\n\t"
<< "GL_FRAMEBUFFER_INCOMPLETE_MISSING_ATTACHMENT_EXT\n";
isOK = false;
break;
case GL_FRAMEBUFFER_INCOMPLETE_DIMENSIONS_EXT:
ostr << "glift::CheckFramebufferStatus() ERROR:\n\t"
<< "GL_FRAMEBUFFER_INCOMPLETE_DIMENSIONS_EXT\n";
isOK = false;
break;
case GL_FRAMEBUFFER_INCOMPLETE_FORMATS_EXT:
ostr << "glift::CheckFramebufferStatus() ERROR:\n\t"
<< "GL_FRAMEBUFFER_INCOMPLETE_FORMATS_EXT\n";
isOK = false;
break;
case GL_FRAMEBUFFER_INCOMPLETE_DRAW_BUFFER_EXT:
ostr << "glift::CheckFramebufferStatus() ERROR:\n\t"
<< "GL_FRAMEBUFFER_INCOMPLETE_DRAW_BUFFER_EXT\n";
isOK = false;
break;
case GL_FRAMEBUFFER_INCOMPLETE_READ_BUFFER_EXT:
ostr << "glift::CheckFramebufferStatus() ERROR:\n\t"
<< "GL_FRAMEBUFFER_INCOMPLETE_READ_BUFFER_EXT\n";
isOK = false;
break;
case GL_FRAMEBUFFER_UNSUPPORTED_EXT:
ostr << "glift::CheckFramebufferStatus() ERROR:\n\t"
<< "GL_FRAMEBUFFER_UNSUPPORTED_EXT\n";
isOK = false;
break;
default:
ostr << "glift::CheckFramebufferStatus() ERROR:\n\t"
<< "Unknown ERROR\n";
isOK = false;
}
_GuardedUnbind();
return isOK;
}
#endif // NDEBUG
/// Accessors
GLenum FramebufferObject::GetAttachedType( GLenum attachment )
{
// Returns GL_RENDERBUFFER_EXT or GL_TEXTURE
_GuardedBind();
GLint type = 0;
glGetFramebufferAttachmentParameterivEXT(GL_FRAMEBUFFER_EXT, attachment,
GL_FRAMEBUFFER_ATTACHMENT_OBJECT_TYPE_EXT,
&type);
_GuardedUnbind();
return GLenum(type);
}
GLuint FramebufferObject::GetAttachedId( GLenum attachment )
{
_GuardedBind();
GLint id = 0;
glGetFramebufferAttachmentParameterivEXT(GL_FRAMEBUFFER_EXT, attachment,
GL_FRAMEBUFFER_ATTACHMENT_OBJECT_NAME_EXT,
&id);
_GuardedUnbind();
return GLuint(id);
}
GLint FramebufferObject::GetAttachedMipLevel( GLenum attachment )
{
_GuardedBind();
GLint level = 0;
glGetFramebufferAttachmentParameterivEXT(GL_FRAMEBUFFER_EXT, attachment,
GL_FRAMEBUFFER_ATTACHMENT_TEXTURE_LEVEL_EXT,
&level);
_GuardedUnbind();
return level;
}
GLint FramebufferObject::GetAttachedCubeFace( GLenum attachment )
{
_GuardedBind();
GLint level = 0;
glGetFramebufferAttachmentParameterivEXT(GL_FRAMEBUFFER_EXT, attachment,
GL_FRAMEBUFFER_ATTACHMENT_TEXTURE_CUBE_MAP_FACE_EXT,
&level);
_GuardedUnbind();
return level;
}
GLint FramebufferObject::GetAttachedZSlice( GLenum attachment )
{
_GuardedBind();
GLint slice = 0;
glGetFramebufferAttachmentParameterivEXT(GL_FRAMEBUFFER_EXT, attachment,
GL_FRAMEBUFFER_ATTACHMENT_TEXTURE_3D_ZOFFSET_EXT,
&slice);
_GuardedUnbind();
return slice;
}
/*!
Renderbuffer Class. This class encapsulates the Renderbuffer OpenGL
object described in the FramebufferObject (FBO) OpenGL spec.
See the official spec at:
http://oss.sgi.com/projects/ogl-sample/registry/EXT/framebuffer_object.txt
for complete details.
A "Renderbuffer" is a chunk of GPU memory used by FramebufferObjects to
represent "traditional" framebuffer memory (depth, stencil, and color buffers).
By "traditional," we mean that the memory cannot be bound as a texture.
With respect to GPU shaders, Renderbuffer memory is "write-only." Framebuffer
operations such as alpha blending, depth test, alpha test, stencil test, etc.
read from this memory in post-fragement-shader (ROP) operations.
The most common use of Renderbuffers is to create depth and stencil buffers.
Note that as of 7/1/05, NVIDIA drivers to do not support stencil Renderbuffers.
Usage Notes:
1) "internalFormat" can be any of the following:
Valid OpenGL internal formats beginning with:
RGB, RGBA, DEPTH_COMPONENT
or a stencil buffer format (not currently supported
in NVIDIA drivers as of 7/1/05).
STENCIL_INDEX1_EXT
STENCIL_INDEX4_EXT
STENCIL_INDEX8_EXT
STENCIL_INDEX16_EXT
*/
class Renderbuffer
{
public:
/// Ctors/Dtors
Renderbuffer();
Renderbuffer(GLenum internalFormat, int width, int height);
~Renderbuffer();
void Bind();
void Unbind();
void Set(GLenum internalFormat, int width, int height);
GLuint GetId() const;
static GLint GetMaxSize();
private:
GLuint m_bufId;
static GLuint _CreateBufferId();
};
#include <iostream>
using namespace std;
Renderbuffer::Renderbuffer()
: m_bufId(_CreateBufferId())
{}
Renderbuffer::Renderbuffer(GLenum internalFormat, int width, int height)
: m_bufId(_CreateBufferId())
{
Set(internalFormat, width, height);
}
Renderbuffer::~Renderbuffer()
{
glDeleteRenderbuffersEXT(1, &m_bufId);
}
void Renderbuffer::Bind()
{
glBindRenderbufferEXT(GL_RENDERBUFFER_EXT, m_bufId);
}
void Renderbuffer::Unbind()
{
glBindRenderbufferEXT(GL_RENDERBUFFER_EXT, 0);
}
void Renderbuffer::Set(GLenum internalFormat, int width, int height)
{
int maxSize = Renderbuffer::GetMaxSize();
if (width > maxSize || height > maxSize ) {
cerr << "Renderbuffer::Renderbuffer() ERROR:\n\t"
<< "Size too big (" << width << ", " << height << ")\n";
return;
}
// Guarded bind
GLint savedId = 0;
glGetIntegerv( GL_RENDERBUFFER_BINDING_EXT, &savedId );
if (savedId != (GLint)m_bufId) {
Bind();
}
// Allocate memory for renderBuffer
glRenderbufferStorageEXT(GL_RENDERBUFFER_EXT, internalFormat, width, height );
// Guarded unbind
if (savedId != (GLint)m_bufId) {
glBindRenderbufferEXT(GL_RENDERBUFFER_EXT, savedId);
}
}
GLuint Renderbuffer::GetId() const
{
return m_bufId;
}
GLint Renderbuffer::GetMaxSize()
{
GLint maxAttach = 0;
glGetIntegerv( GL_MAX_RENDERBUFFER_SIZE_EXT, &maxAttach );
return maxAttach;
}
GLuint Renderbuffer::_CreateBufferId()
{
GLuint id = 0;
glGenRenderbuffersEXT(1, &id);
return id;
}
#endif // __FRAMEBUFFERRENDERBUFFER_HPP__

View File

@ -0,0 +1,358 @@
/*
* This Code Was Created By Jeff Molofee 2000
* A HUGE Thanks To Fredric Echols For Cleaning Up
* And Optimizing This Code, Making It More Flexible!
* If You've Found This Code Useful, Please Let Me Know.
* Visit My Site At nehe.gamedev.net
*/
/*
* 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) 2015-2020, SLikeSoft UG (haftungsbeschr<68>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.
*/
#include <windows.h> // Header File For Windows
#include <tchar.h> // Header File For Unicode conversion support
#include <gl\gl.h> // Header File For The OpenGL32 Library
#include <gl\glu.h> // Header File For The GLu32 Library
HDC hDC= nullptr; // Private GDI Device Context
HGLRC hRC= nullptr; // Permanent Rendering Context
HWND hWnd= nullptr; // Holds Our Window Handle
HINSTANCE hInstance; // Holds The Instance Of The Application
int windowWidth = 0, windowHeight = 0;
bool keys[256]; // Array Used For The Keyboard Routine
bool active=TRUE; // Window Active Flag Set To TRUE By Default
bool fullscreen=TRUE; // Fullscreen Flag Set To Fullscreen Mode By Default
static void MessageBoxPrivate( HWND hWnd, const char* pMessage, const char* pTitle, int flags )
{
printf( "%s: %s\n", pTitle, pMessage );
}
LRESULT CALLBACK WndProc(HWND, UINT, WPARAM, LPARAM); // Declaration For WndProc
GLvoid ReSizeGLScene(GLsizei width, GLsizei height) // Resize And Initialize The GL Window
{
if (height==0) // Prevent A Divide By Zero By
{
height=1; // Making Height Equal One
}
glViewport(0,0,width,height); // Reset The Current Viewport
glMatrixMode(GL_PROJECTION); // Select The Projection Matrix
glLoadIdentity(); // Reset The Projection Matrix
// Calculate The Aspect Ratio Of The Window
gluPerspective(45.0f,(GLfloat)width/(GLfloat)height,0.1f,100.0f);
glMatrixMode(GL_MODELVIEW); // Select The Modelview Matrix
glLoadIdentity(); // Reset The Modelview Matrix
}
int InitGL(GLvoid) // All Setup For OpenGL Goes Here
{
glShadeModel(GL_SMOOTH); // Enable Smooth Shading
glClearColor(0.0f, 0.0f, 0.0f, 0.5f); // Black Background
glClearDepth(1.0f); // Depth Buffer Setup
glEnable(GL_DEPTH_TEST); // Enables Depth Testing
glDepthFunc(GL_LEQUAL); // The Type Of Depth Testing To Do
glHint(GL_PERSPECTIVE_CORRECTION_HINT, GL_NICEST); // Really Nice Perspective Calculations
return TRUE; // Initialization Went OK
}
int DrawGLScene(GLvoid) // Here's Where We Do All The Drawing
{
glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT); // Clear Screen And Depth Buffer
glLoadIdentity(); // Reset The Current Modelview Matrix
return TRUE; // Everything Went OK
}
GLvoid KillGLWindow(GLvoid) // Properly Kill The Window
{
if (fullscreen) // Are We In Fullscreen Mode?
{
ChangeDisplaySettings(nullptr,0); // If So Switch Back To The Desktop
ShowCursor(TRUE); // Show Mouse Pointer
}
if (hRC) // Do We Have A Rendering Context?
{
if (!wglMakeCurrent(nullptr, nullptr)) // Are We Able To Release The DC And RC Contexts?
{
MessageBoxPrivate(nullptr,"Release Of DC And RC Failed.","SHUTDOWN ERROR",MB_OK | MB_ICONINFORMATION);
}
if (!wglDeleteContext(hRC)) // Are We Able To Delete The RC?
{
MessageBoxPrivate(nullptr,"Release Rendering Context Failed.","SHUTDOWN ERROR",MB_OK | MB_ICONINFORMATION);
}
hRC= nullptr; // Set RC To nullptr
}
if (hDC && !ReleaseDC(hWnd,hDC)) // Are We Able To Release The DC
{
MessageBoxPrivate(nullptr,"Release Device Context Failed.","SHUTDOWN ERROR",MB_OK | MB_ICONINFORMATION);
hDC= nullptr; // Set DC To nullptr
}
if (hWnd && !DestroyWindow(hWnd)) // Are We Able To Destroy The Window?
{
MessageBoxPrivate(nullptr,"Could Not Release hWnd.","SHUTDOWN ERROR",MB_OK | MB_ICONINFORMATION);
hWnd= nullptr; // Set hWnd To nullptr
}
if (!UnregisterClass(_T("OpenGL"),hInstance)) // Are We Able To Unregister Class
{
MessageBoxPrivate(nullptr,"Could Not Unregister Class.","SHUTDOWN ERROR",MB_OK | MB_ICONINFORMATION);
hInstance= nullptr; // Set hInstance To nullptr
}
}
/* This Code Creates Our OpenGL Window. Parameters Are: *
* title - Title To Appear At The Top Of The Window *
* width - Width Of The GL Window Or Fullscreen Mode *
* height - Height Of The GL Window Or Fullscreen Mode *
* bits - Number Of Bits To Use For Color (8/16/24/32) *
* fullscreenflag - Use Fullscreen Mode (TRUE) Or Windowed Mode (FALSE) */
BOOL CreateGLWindow(char* title, int width, int height, int bits, bool fullscreenflag, bool hideWindow=true)
{
GLuint PixelFormat; // Holds The Results After Searching For A Match
WNDCLASS wc; // Windows Class Structure
DWORD dwExStyle; // Window Extended Style
DWORD dwStyle; // Window Style
RECT WindowRect; // Grabs Rectangle Upper Left / Lower Right Values
WindowRect.left=(long)0; // Set Left Value To 0
WindowRect.right=(long)width; // Set Right Value To Requested Width
WindowRect.top=(long)0; // Set Top Value To 0
WindowRect.bottom=(long)height; // Set Bottom Value To Requested Height
fullscreen=fullscreenflag; // Set The Global Fullscreen Flag
hInstance = GetModuleHandle(nullptr); // Grab An Instance For Our Window
wc.style = CS_HREDRAW | CS_VREDRAW | CS_OWNDC; // Redraw On Size, And Own DC For Window.
wc.lpfnWndProc = (WNDPROC) WndProc; // WndProc Handles Messages
wc.cbClsExtra = 0; // No Extra Window Data
wc.cbWndExtra = 0; // No Extra Window Data
wc.hInstance = hInstance; // Set The Instance
wc.hIcon = LoadIcon(nullptr, IDI_WINLOGO); // Load The Default Icon
wc.hCursor = LoadCursor(nullptr, IDC_ARROW); // Load The Arrow Pointer
wc.hbrBackground = nullptr; // No Background Required For GL
wc.lpszMenuName = nullptr; // We Don't Want A Menu
wc.lpszClassName = _T("OpenGL"); // Set The Class Name
if (!RegisterClass(&wc)) // Attempt To Register The Window Class
{
MessageBoxPrivate(nullptr,"Failed To Register The Window Class.","ERROR",MB_OK|MB_ICONEXCLAMATION);
return FALSE; // Return FALSE
}
if (fullscreen) // Attempt Fullscreen Mode?
{
DEVMODE dmScreenSettings; // Device Mode
memset(&dmScreenSettings,0,sizeof(dmScreenSettings)); // Makes Sure Memory's Cleared
dmScreenSettings.dmSize=sizeof(dmScreenSettings); // Size Of The Devmode Structure
dmScreenSettings.dmPelsWidth = width; // Selected Screen Width
dmScreenSettings.dmPelsHeight = height; // Selected Screen Height
dmScreenSettings.dmBitsPerPel = bits; // Selected Bits Per Pixel
dmScreenSettings.dmFields=DM_BITSPERPEL|DM_PELSWIDTH|DM_PELSHEIGHT;
// Try To Set Selected Mode And Get Results. NOTE: CDS_FULLSCREEN Gets Rid Of Start Bar.
if (ChangeDisplaySettings(&dmScreenSettings,CDS_FULLSCREEN)!=DISP_CHANGE_SUCCESSFUL)
{
/*
// If The Mode Fails, Offer Two Options. Quit Or Use Windowed Mode.
if (MessageBoxPrivate(nullptr,"The Requested Fullscreen Mode Is Not Supported By\nYour Video Card. Use Windowed Mode Instead?","NeHe GL",MB_YESNO|MB_ICONEXCLAMATION)==IDYES)
{
fullscreen=FALSE; // Windowed Mode Selected. Fullscreen = FALSE
}
else
{
// Pop Up A Message Box Letting User Know The Program Is Closing.
MessageBoxPrivate(nullptr,"Program Will Now Close.","ERROR",MB_OK|MB_ICONSTOP);
return FALSE; // Return FALSE
}
*/
fullscreen=FALSE;
}
}
if (fullscreen) // Are We Still In Fullscreen Mode?
{
dwExStyle=WS_EX_APPWINDOW; // Window Extended Style
dwStyle=WS_POPUP; // Windows Style
ShowCursor(FALSE); // Hide Mouse Pointer
}
else
{
dwExStyle=WS_EX_APPWINDOW | WS_EX_WINDOWEDGE; // Window Extended Style
dwStyle=WS_OVERLAPPEDWINDOW; // Windows Style
}
AdjustWindowRectEx(&WindowRect, dwStyle, FALSE, dwExStyle); // Adjust Window To True Requested Size
// Create The Window
if (!(hWnd=CreateWindowEx( dwExStyle, // Extended Style For The Window
_T("OpenGL"), // Class Name
_T("DXTCompress"), // Window Title
dwStyle | // Defined Window Style
WS_CLIPSIBLINGS | // Required Window Style
WS_CLIPCHILDREN, // Required Window Style
0, 0, // Window Position
WindowRect.right-WindowRect.left, // Calculate Window Width
WindowRect.bottom-WindowRect.top, // Calculate Window Height
nullptr, // No Parent Window
nullptr, // No Menu
hInstance, // Instance
nullptr))) // Dont Pass Anything To WM_CREATE
{
KillGLWindow(); // Reset The Display
MessageBoxPrivate(nullptr,"Window Creation Error.","ERROR",MB_OK|MB_ICONEXCLAMATION);
return FALSE; // Return FALSE
}
static PIXELFORMATDESCRIPTOR pfd= // pfd Tells Windows How We Want Things To Be
{
sizeof(PIXELFORMATDESCRIPTOR), // Size Of This Pixel Format Descriptor
1, // Version Number
PFD_DRAW_TO_WINDOW | // Format Must Support Window
PFD_SUPPORT_OPENGL | // Format Must Support OpenGL
PFD_DOUBLEBUFFER, // Must Support Double Buffering
PFD_TYPE_RGBA, // Request An RGBA Format
static_cast<BYTE>(bits), // Select Our Color Depth
0, 0, 0, 0, 0, 0, // Color Bits Ignored
0, // No Alpha Buffer
0, // Shift Bit Ignored
0, // No Accumulation Buffer
0, 0, 0, 0, // Accumulation Bits Ignored
16, // 16Bit Z-Buffer (Depth Buffer)
0, // No Stencil Buffer
0, // No Auxiliary Buffer
PFD_MAIN_PLANE, // Main Drawing Layer
0, // Reserved
0, 0, 0 // Layer Masks Ignored
};
if (!(hDC=GetDC(hWnd))) // Did We Get A Device Context?
{
KillGLWindow(); // Reset The Display
MessageBoxPrivate(nullptr,"Can't Create A GL Device Context.","ERROR",MB_OK|MB_ICONEXCLAMATION);
return FALSE; // Return FALSE
}
if (!(PixelFormat=ChoosePixelFormat(hDC,&pfd))) // Did Windows Find A Matching Pixel Format?
{
KillGLWindow(); // Reset The Display
MessageBoxPrivate(nullptr,"Can't Find A Suitable PixelFormat.","ERROR",MB_OK|MB_ICONEXCLAMATION);
return FALSE; // Return FALSE
}
if(!SetPixelFormat(hDC,PixelFormat,&pfd)) // Are We Able To Set The Pixel Format?
{
KillGLWindow(); // Reset The Display
MessageBoxPrivate(nullptr,"Can't Set The PixelFormat.","ERROR",MB_OK|MB_ICONEXCLAMATION);
return FALSE; // Return FALSE
}
if (!(hRC=wglCreateContext(hDC))) // Are We Able To Get A Rendering Context?
{
KillGLWindow(); // Reset The Display
MessageBoxPrivate(nullptr,"Can't Create A GL Rendering Context.","ERROR",MB_OK|MB_ICONEXCLAMATION);
return FALSE; // Return FALSE
}
if(!wglMakeCurrent(hDC,hRC)) // Try To Activate The Rendering Context
{
KillGLWindow(); // Reset The Display
MessageBoxPrivate(nullptr,"Can't Activate The GL Rendering Context.","ERROR",MB_OK|MB_ICONEXCLAMATION);
return FALSE; // Return FALSE
}
if( hideWindow )
ShowWindow(hWnd,SW_HIDE); // Show The Window
else
ShowWindow(hWnd,SW_SHOW); // Show The Window
SetForegroundWindow(hWnd); // Slightly Higher Priority
SetFocus(hWnd); // Sets Keyboard Focus To The Window
ReSizeGLScene(width, height); // Set Up Our Perspective GL Screen
if (!InitGL()) // Initialize Our Newly Created GL Window
{
KillGLWindow(); // Reset The Display
MessageBoxPrivate(nullptr,"Initialization Failed.","ERROR",MB_OK|MB_ICONEXCLAMATION);
return FALSE; // Return FALSE
}
return TRUE; // Success
}
LRESULT CALLBACK WndProc( HWND hWnd, // Handle For This Window
UINT uMsg, // Message For This Window
WPARAM wParam, // Additional Message Information
LPARAM lParam) // Additional Message Information
{
switch (uMsg) // Check For Windows Messages
{
case WM_ACTIVATE: // Watch For Window Activate Message
{
if (!HIWORD(wParam)) // Check Minimization State
{
active=TRUE; // Program Is Active
}
else
{
active=FALSE; // Program Is No Longer Active
}
return 0; // Return To The Message Loop
}
case WM_SYSCOMMAND: // Intercept System Commands
{
switch (wParam) // Check System Calls
{
case SC_SCREENSAVE: // Screensaver Trying To Start?
case SC_MONITORPOWER: // Monitor Trying To Enter Powersave?
return 0; // Prevent From Happening
}
break; // Exit
}
case WM_CLOSE: // Did We Receive A Close Message?
{
PostQuitMessage(0); // Send A Quit Message
return 0; // Jump Back
}
case WM_KEYDOWN: // Is A Key Being Held Down?
{
keys[wParam] = TRUE; // If So, Mark It As TRUE
return 0; // Jump Back
}
case WM_KEYUP: // Has A Key Been Released?
{
keys[wParam] = FALSE; // If So, Mark It As FALSE
return 0; // Jump Back
}
case WM_SIZE: // Resize The OpenGL Window
{
windowWidth = LOWORD(lParam);
windowHeight = HIWORD(lParam);
ReSizeGLScene(windowWidth, windowHeight); // LoWord=Width, HiWord=Height
return 0; // Jump Back
}
}
// Pass All Unhandled Messages To DefWindowProc
return DefWindowProc(hWnd,uMsg,wParam,lParam);
}

View File

@ -0,0 +1,571 @@
/*
Real-time DXT1 & YCoCg DXT5 compression (Cg 2.0)
Copyright (c) NVIDIA Corporation.
Written by: Ignacio Castano <icastano@nvidia.com>
Thanks to JMP van Waveren, Simon Green, Eric Werness, Simon Brown
Permission is hereby granted, free of charge, to any person
obtaining a copy of this software and associated documentation
files (the "Software"), to deal in the Software without
restriction, including without limitation the rights to use,
copy, modify, merge, publish, distribute, sublicense, and/or sell
copies of the Software, and to permit persons to whom the
Software is furnished to do so, subject to the following
conditions:
The above copyright notice and this permission notice shall be
included in all copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES
OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT
HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
OTHER DEALINGS IN THE SOFTWARE.
*/
const char* pDXTCompressorShaderSource =
" \n"
"// vertex program \n"
"void compress_vp(float4 pos : POSITION, \n"
" float2 texcoord : TEXCOORD0, \n"
" out float4 hpos : POSITION, \n"
" out float2 o_texcoord : TEXCOORD0 \n"
" ) \n"
"{ \n"
" o_texcoord = texcoord; \n"
" hpos = pos; \n"
"} \n"
" \n"
"typedef unsigned int uint; \n"
"typedef unsigned int2 uint2; \n"
"typedef unsigned int3 uint3; \n"
"typedef unsigned int4 uint4; \n"
" \n"
"const float offset = 128.0 / 255.0; \n"
" \n"
"// Use dot product to minimize RMS instead absolute distance like in the CPU compressor. \n"
"float colorDistance(float3 c0, float3 c1) \n"
"{ \n"
" return dot(c0-c1, c0-c1); \n"
"} \n"
"float colorDistance(float2 c0, float2 c1) \n"
"{ \n"
" return dot(c0-c1, c0-c1); \n"
"} \n"
" \n"
" \n"
"void ExtractColorBlockRGB(out float3 col[16], sampler2D image, float2 texcoord, float2 imageSize) \n"
"{ \n"
" // use TXF instruction (integer coordinates with offset) \n"
" // note offsets must be constant \n"
" //int4 base = int4(wpos*4-2, 0, 0); \n"
" int4 base = int4(texcoord * imageSize - 1.5, 0, 0); \n"
" col[0] = tex2Dfetch(image, base, int2(0, 0)).rgb; \n"
" col[1] = tex2Dfetch(image, base, int2(1, 0)).rgb; \n"
" col[2] = tex2Dfetch(image, base, int2(2, 0)).rgb; \n"
" col[3] = tex2Dfetch(image, base, int2(3, 0)).rgb; \n"
" col[4] = tex2Dfetch(image, base, int2(0, 1)).rgb; \n"
" col[5] = tex2Dfetch(image, base, int2(1, 1)).rgb; \n"
" col[6] = tex2Dfetch(image, base, int2(2, 1)).rgb; \n"
" col[7] = tex2Dfetch(image, base, int2(3, 1)).rgb; \n"
" col[8] = tex2Dfetch(image, base, int2(0, 2)).rgb; \n"
" col[9] = tex2Dfetch(image, base, int2(1, 2)).rgb; \n"
" col[10] = tex2Dfetch(image, base, int2(2, 2)).rgb; \n"
" col[11] = tex2Dfetch(image, base, int2(3, 2)).rgb; \n"
" col[12] = tex2Dfetch(image, base, int2(0, 3)).rgb; \n"
" col[13] = tex2Dfetch(image, base, int2(1, 3)).rgb; \n"
" col[14] = tex2Dfetch(image, base, int2(2, 3)).rgb; \n"
" col[15] = tex2Dfetch(image, base, int2(3, 3)).rgb; \n"
"} \n"
" \n"
"void ExtractColorBlockBGR(out float3 col[16], sampler2D image, float2 texcoord, float2 imageSize) \n"
"{ \n"
" // use TXF instruction (integer coordinates with offset) \n"
" // note offsets must be constant \n"
" //int4 base = int4(wpos*4-2, 0, 0); \n"
" int4 base = int4(texcoord * imageSize - 1.5, 0, 0); \n"
" col[0] = tex2Dfetch(image, base, int2(0, 0)).bgr; \n"
" col[1] = tex2Dfetch(image, base, int2(1, 0)).bgr; \n"
" col[2] = tex2Dfetch(image, base, int2(2, 0)).bgr; \n"
" col[3] = tex2Dfetch(image, base, int2(3, 0)).bgr; \n"
" col[4] = tex2Dfetch(image, base, int2(0, 1)).bgr; \n"
" col[5] = tex2Dfetch(image, base, int2(1, 1)).bgr; \n"
" col[6] = tex2Dfetch(image, base, int2(2, 1)).bgr; \n"
" col[7] = tex2Dfetch(image, base, int2(3, 1)).bgr; \n"
" col[8] = tex2Dfetch(image, base, int2(0, 2)).bgr; \n"
" col[9] = tex2Dfetch(image, base, int2(1, 2)).bgr; \n"
" col[10] = tex2Dfetch(image, base, int2(2, 2)).bgr; \n"
" col[11] = tex2Dfetch(image, base, int2(3, 2)).bgr; \n"
" col[12] = tex2Dfetch(image, base, int2(0, 3)).bgr; \n"
" col[13] = tex2Dfetch(image, base, int2(1, 3)).bgr; \n"
" col[14] = tex2Dfetch(image, base, int2(2, 3)).bgr; \n"
" col[15] = tex2Dfetch(image, base, int2(3, 3)).bgr; \n"
"} \n"
" \n"
"float3 toYCoCg(float3 c) \n"
"{ \n"
" float Y = (c.r + 2 * c.g + c.b) * 0.25; \n"
" float Co = ( ( 2 * c.r - 2 * c.b ) * 0.25 + offset ); \n"
" float Cg = ( ( -c.r + 2 * c.g - c.b) * 0.25 + offset ); \n"
" \n"
" return float3(Y, Co, Cg); \n"
"} \n"
" \n"
"void ExtractColorBlockYCoCg_RGB(out float3 col[16], sampler2D image, float2 texcoord, float2 imageSize) \n"
"{ \n"
" // use TXF instruction (integer coordinates with offset) \n"
" // note offsets must be constant \n"
" //int4 base = int4(wpos*4-2, 0, 0); \n"
" int4 base = int4(texcoord * imageSize - 1.5, 0, 0); \n"
" col[0] = toYCoCg(tex2Dfetch(image, base, int2(0, 0)).rgb); \n"
" col[1] = toYCoCg(tex2Dfetch(image, base, int2(1, 0)).rgb); \n"
" col[2] = toYCoCg(tex2Dfetch(image, base, int2(2, 0)).rgb); \n"
" col[3] = toYCoCg(tex2Dfetch(image, base, int2(3, 0)).rgb); \n"
" col[4] = toYCoCg(tex2Dfetch(image, base, int2(0, 1)).rgb); \n"
" col[5] = toYCoCg(tex2Dfetch(image, base, int2(1, 1)).rgb); \n"
" col[6] = toYCoCg(tex2Dfetch(image, base, int2(2, 1)).rgb); \n"
" col[7] = toYCoCg(tex2Dfetch(image, base, int2(3, 1)).rgb); \n"
" col[8] = toYCoCg(tex2Dfetch(image, base, int2(0, 2)).rgb); \n"
" col[9] = toYCoCg(tex2Dfetch(image, base, int2(1, 2)).rgb); \n"
" col[10] = toYCoCg(tex2Dfetch(image, base, int2(2, 2)).rgb); \n"
" col[11] = toYCoCg(tex2Dfetch(image, base, int2(3, 2)).rgb); \n"
" col[12] = toYCoCg(tex2Dfetch(image, base, int2(0, 3)).rgb); \n"
" col[13] = toYCoCg(tex2Dfetch(image, base, int2(1, 3)).rgb); \n"
" col[14] = toYCoCg(tex2Dfetch(image, base, int2(2, 3)).rgb); \n"
" col[15] = toYCoCg(tex2Dfetch(image, base, int2(3, 3)).rgb); \n"
"} \n"
" \n"
"void ExtractColorBlockYCoCg_BGR(out float3 col[16], sampler2D image, float2 texcoord, float2 imageSize) \n"
"{ \n"
" // use TXF instruction (integer coordinates with offset) \n"
" // note offsets must be constant \n"
" //int4 base = int4(wpos*4-2, 0, 0); \n"
" int4 base = int4(texcoord * imageSize - 1.5, 0, 0); \n"
" col[0] = toYCoCg(tex2Dfetch(image, base, int2(0, 0)).bgr); \n"
" col[1] = toYCoCg(tex2Dfetch(image, base, int2(1, 0)).bgr); \n"
" col[2] = toYCoCg(tex2Dfetch(image, base, int2(2, 0)).bgr); \n"
" col[3] = toYCoCg(tex2Dfetch(image, base, int2(3, 0)).bgr); \n"
" col[4] = toYCoCg(tex2Dfetch(image, base, int2(0, 1)).bgr); \n"
" col[5] = toYCoCg(tex2Dfetch(image, base, int2(1, 1)).bgr); \n"
" col[6] = toYCoCg(tex2Dfetch(image, base, int2(2, 1)).bgr); \n"
" col[7] = toYCoCg(tex2Dfetch(image, base, int2(3, 1)).bgr); \n"
" col[8] = toYCoCg(tex2Dfetch(image, base, int2(0, 2)).bgr); \n"
" col[9] = toYCoCg(tex2Dfetch(image, base, int2(1, 2)).bgr); \n"
" col[10] = toYCoCg(tex2Dfetch(image, base, int2(2, 2)).bgr); \n"
" col[11] = toYCoCg(tex2Dfetch(image, base, int2(3, 2)).bgr); \n"
" col[12] = toYCoCg(tex2Dfetch(image, base, int2(0, 3)).bgr); \n"
" col[13] = toYCoCg(tex2Dfetch(image, base, int2(1, 3)).bgr); \n"
" col[14] = toYCoCg(tex2Dfetch(image, base, int2(2, 3)).bgr); \n"
" col[15] = toYCoCg(tex2Dfetch(image, base, int2(3, 3)).bgr); \n"
"} \n"
" \n"
"// find minimum and maximum colors based on bounding box in color space \n"
"void FindMinMaxColorsBox(float3 block[16], out float3 mincol, out float3 maxcol) \n"
"{ \n"
" mincol = block[0]; \n"
" maxcol = block[0]; \n"
" \n"
" for (int i = 1; i < 16; i++) { \n"
" mincol = min(mincol, block[i]); \n"
" maxcol = max(maxcol, block[i]); \n"
" } \n"
"} \n"
" \n"
"void InsetBBox(in out float3 mincol, in out float3 maxcol) \n"
"{ \n"
" float3 inset = (maxcol - mincol) / 16.0 - (8.0 / 255.0) / 16; \n"
" mincol = saturate(mincol + inset); \n"
" maxcol = saturate(maxcol - inset); \n"
"} \n"
"void InsetYBBox(in out float mincol, in out float maxcol) \n"
"{ \n"
" float inset = (maxcol - mincol) / 32.0 - (16.0 / 255.0) / 32.0; \n"
" mincol = saturate(mincol + inset); \n"
" maxcol = saturate(maxcol - inset); \n"
"} \n"
"void InsetCoCgBBox(in out float2 mincol, in out float2 maxcol) \n"
"{ \n"
" float2 inset = (maxcol - mincol) / 16.0 - (8.0 / 255.0) / 16; \n"
" mincol = saturate(mincol + inset); \n"
" maxcol = saturate(maxcol - inset); \n"
"} \n"
" \n"
"void SelectDiagonal(float3 block[16], in out float3 mincol, in out float3 maxcol) \n"
"{ \n"
" float3 center = (mincol + maxcol) * 0.5; \n"
" \n"
" float2 cov = 0; \n"
" for (int i = 0; i < 16; i++) \n"
" { \n"
" float3 t = block[i] - center; \n"
" cov.x += t.x * t.z; \n"
" cov.y += t.y * t.z; \n"
" } \n"
" \n"
" if (cov.x < 0) { \n"
" float temp = maxcol.x; \n"
" maxcol.x = mincol.x; \n"
" mincol.x = temp; \n"
" } \n"
" if (cov.y < 0) { \n"
" float temp = maxcol.y; \n"
" maxcol.y = mincol.y; \n"
" mincol.y = temp; \n"
" } \n"
"} \n"
" \n"
"float3 RoundAndExpand(float3 v, out uint w) \n"
"{ \n"
" int3 c = round(v * float3(31, 63, 31)); \n"
" w = (c.r << 11) | (c.g << 5) | c.b; \n"
" \n"
" c.rb = (c.rb << 3) | (c.rb >> 2); \n"
" c.g = (c.g << 2) | (c.g >> 4); \n"
" \n"
" return (float3)c * (1.0 / 255.0); \n"
"} \n"
" \n"
"uint EmitEndPointsDXT1(in out float3 mincol, in out float3 maxcol) \n"
"{ \n"
" uint2 output; \n"
" maxcol = RoundAndExpand(maxcol, output.x); \n"
" mincol = RoundAndExpand(mincol, output.y); \n"
" \n"
" // We have to do this in case we select an alternate diagonal. \n"
" if (output.x < output.y) \n"
" { \n"
" float3 tmp = mincol; \n"
" mincol = maxcol; \n"
" maxcol = tmp; \n"
" return output.y | (output.x << 16); \n"
" } \n"
" \n"
" return output.x | (output.y << 16); \n"
"} \n"
" \n"
"uint EmitIndicesDXT1(float3 block[16], float3 mincol, float3 maxcol) \n"
"{ \n"
" const float RGB_RANGE = 3; \n"
" \n"
" float3 dir = (maxcol - mincol); \n"
" float3 origin = maxcol + dir / (2.0 * RGB_RANGE); \n"
" dir /= dot(dir, dir); \n"
" \n"
" // Compute indices \n"
" uint indices = 0; \n"
" for (int i = 0; i < 16; i++) \n"
" { \n"
" uint index = saturate(dot(origin - block[i], dir)) * RGB_RANGE; \n"
" indices |= index << (i * 2); \n"
" } \n"
" \n"
" uint i0 = (indices & 0x55555555); \n"
" uint i1 = (indices & 0xAAAAAAAA) >> 1; \n"
" indices = ((i0 ^ i1) << 1) | i1; \n"
" \n"
" // Output indices \n"
" return indices; \n"
"} \n"
" \n"
"int ScaleYCoCg(float2 minColor, float2 maxColor) \n"
"{ \n"
" float2 m0 = abs(minColor - offset); \n"
" float2 m1 = abs(maxColor - offset); \n"
" \n"
" float m = max(max(m0.x, m0.y), max(m1.x, m1.y)); \n"
" \n"
" const float s0 = 64.0 / 255.0; \n"
" const float s1 = 32.0 / 255.0; \n"
" \n"
" int scale = 1; \n"
" if (m < s0) scale = 2; \n"
" if (m < s1) scale = 4; \n"
" \n"
" return scale; \n"
"} \n"
" \n"
"void SelectYCoCgDiagonal(const float3 block[16], in out float2 minColor, in out float2 maxColor) \n"
"{ \n"
" float2 mid = (maxColor + minColor) * 0.5; \n"
" \n"
" float cov = 0; \n"
" for (int i = 0; i < 16; i++) \n"
" { \n"
" float2 t = block[i].yz - mid; \n"
" cov += t.x * t.y; \n"
" } \n"
" if (cov < 0) { \n"
" float tmp = maxColor.y; \n"
" maxColor.y = minColor.y; \n"
" minColor.y = tmp; \n"
" } \n"
"} \n"
" \n"
" \n"
"uint EmitEndPointsYCoCgDXT5(in out float2 mincol, in out float2 maxcol, int scale) \n"
"{ \n"
" maxcol = (maxcol - offset) * scale + offset; \n"
" mincol = (mincol - offset) * scale + offset; \n"
" \n"
" InsetCoCgBBox(mincol, maxcol); \n"
" \n"
" maxcol = round(maxcol * float2(31, 63)); \n"
" mincol = round(mincol * float2(31, 63)); \n"
" \n"
" int2 imaxcol = maxcol; \n"
" int2 imincol = mincol; \n"
" \n"
" uint2 output; \n"
" output.x = (imaxcol.r << 11) | (imaxcol.g << 5) | (scale - 1); \n"
" output.y = (imincol.r << 11) | (imincol.g << 5) | (scale - 1); \n"
" \n"
" imaxcol.r = (imaxcol.r << 3) | (imaxcol.r >> 2); \n"
" imaxcol.g = (imaxcol.g << 2) | (imaxcol.g >> 4); \n"
" imincol.r = (imincol.r << 3) | (imincol.r >> 2); \n"
" imincol.g = (imincol.g << 2) | (imincol.g >> 4); \n"
" \n"
" maxcol = (float2)imaxcol * (1.0 / 255.0); \n"
" mincol = (float2)imincol * (1.0 / 255.0); \n"
" \n"
" // Undo rescale. \n"
" maxcol = (maxcol - offset) / scale + offset; \n"
" mincol = (mincol - offset) / scale + offset; \n"
" \n"
" return output.x | (output.y << 16); \n"
"} \n"
" \n"
"uint EmitIndicesYCoCgDXT5(float3 block[16], float2 mincol, float2 maxcol) \n"
"{ \n"
" const float COCG_RANGE = 3; \n"
" \n"
" float2 dir = (maxcol - mincol); \n"
" float2 origin = maxcol + dir / (2.0 * COCG_RANGE); \n"
" dir /= dot(dir, dir); \n"
" \n"
" // Compute indices \n"
" uint indices = 0; \n"
" for (int i = 0; i < 16; i++) \n"
" { \n"
" uint index = saturate(dot(origin - block[i].yz, dir)) * COCG_RANGE; \n"
" indices |= index << (i * 2); \n"
" } \n"
" \n"
" uint i0 = (indices & 0x55555555); \n"
" uint i1 = (indices & 0xAAAAAAAA) >> 1; \n"
" indices = ((i0 ^ i1) << 1) | i1; \n"
" \n"
" // Output indices \n"
" return indices; \n"
"} \n"
" \n"
"uint EmitAlphaEndPointsYCoCgDXT5(float mincol, float maxcol) \n"
"{ \n"
" uint c0 = round(mincol * 255); \n"
" uint c1 = round(maxcol * 255); \n"
" \n"
" return (c0 << 8) | c1; \n"
"} \n"
" \n"
"// Optimized index selection. \n"
"uint2 EmitAlphaIndicesYCoCgDXT5(float3 block[16], float minAlpha, float maxAlpha) \n"
"{ \n"
" const int ALPHA_RANGE = 7; \n"
" \n"
" float bias = maxAlpha + (maxAlpha - minAlpha) / (2.0 * ALPHA_RANGE); \n"
" float scale = 1.0f / (maxAlpha - minAlpha); \n"
" \n"
" uint2 indices = 0; \n"
" \n"
" for (int i = 0; i < 6; i++) \n"
" { \n"
" uint index = saturate((bias - block[i].x) * scale) * ALPHA_RANGE; \n"
" indices.x |= index << (3 * i); \n"
" } \n"
" \n"
" for (int i = 6; i < 16; i++) \n"
" { \n"
" uint index = saturate((bias - block[i].x) * scale) * ALPHA_RANGE; \n"
" indices.y |= index << (3 * i - 18); \n"
" } \n"
" \n"
" uint2 i0 = (indices >> 0) & 0x09249249; \n"
" uint2 i1 = (indices >> 1) & 0x09249249; \n"
" uint2 i2 = (indices >> 2) & 0x09249249; \n"
" \n"
" i2 ^= i0 & i1; \n"
" i1 ^= i0; \n"
" i0 ^= (i1 | i2); \n"
" \n"
" indices.x = (i2.x << 2) | (i1.x << 1) | i0.x; \n"
" indices.y = (((i2.y << 2) | (i1.y << 1) | i0.y) << 2) | (indices.x >> 16); \n"
" indices.x <<= 16; \n"
" \n"
" return indices; \n"
"} \n"
" \n"
"// compress a 4x4 block to DXT1 format \n"
"// integer version, renders to 2 x int32 buffer \n"
"uint4 compress_DXT1_RGBA_fp(float2 texcoord : TEXCOORD0, \n"
" uniform sampler2D image, \n"
" uniform float2 imageSize = { 512.0, 512.0 } \n"
" ) : COLOR \n"
"{ \n"
" // read block \n"
" float3 block[16]; \n"
" ExtractColorBlockRGB(block, image, texcoord, imageSize); \n"
" \n"
" // find min and max colors \n"
" float3 mincol, maxcol; \n"
" FindMinMaxColorsBox(block, mincol, maxcol); \n"
" \n"
" SelectDiagonal(block, mincol, maxcol); \n"
" \n"
" InsetBBox(mincol, maxcol); \n"
" \n"
" uint4 output; \n"
" output.x = EmitEndPointsDXT1(mincol, maxcol); \n"
" output.w = EmitIndicesDXT1(block, mincol, maxcol); \n"
" \n"
" return output; \n"
"} \n"
" \n"
"uint4 compress_DXT1_BGRA_fp(float2 texcoord : TEXCOORD0, \n"
" uniform sampler2D image, \n"
" uniform float2 imageSize = { 512.0, 512.0 } \n"
" ) : COLOR \n"
"{ \n"
" // read block \n"
" float3 block[16]; \n"
" ExtractColorBlockBGR(block, image, texcoord, imageSize); \n"
" \n"
" // find min and max colors \n"
" float3 mincol, maxcol; \n"
" FindMinMaxColorsBox(block, mincol, maxcol); \n"
" \n"
" SelectDiagonal(block, mincol, maxcol); \n"
" \n"
" InsetBBox(mincol, maxcol); \n"
" \n"
" uint4 output; \n"
" output.x = EmitEndPointsDXT1(mincol, maxcol); \n"
" output.w = EmitIndicesDXT1(block, mincol, maxcol); \n"
" \n"
" return output; \n"
"} \n"
" \n"
" \n"
"// compress a 4x4 block to YCoCg DXT5 format \n"
"// integer version, renders to 4 x int32 buffer \n"
"uint4 compress_YCoCgDXT5_RGBA_fp(float2 texcoord : TEXCOORD0, \n"
" uniform sampler2D image, \n"
" uniform float2 imageSize = { 512.0, 512.0 } \n"
" ) : COLOR \n"
"{ \n"
" //imageSize = tex2Dsize(image, texcoord); \n"
" \n"
" // read block \n"
" float3 block[16]; \n"
" ExtractColorBlockYCoCg_RGB(block, image, texcoord, imageSize); \n"
" \n"
" // find min and max colors \n"
" float3 mincol, maxcol; \n"
" FindMinMaxColorsBox(block, mincol, maxcol); \n"
" \n"
" SelectYCoCgDiagonal(block, mincol.yz, maxcol.yz); \n"
" \n"
" int scale = ScaleYCoCg(mincol.yz, maxcol.yz); \n"
" \n"
" // Output CoCg in DXT1 block. \n"
" uint4 output; \n"
" output.z = EmitEndPointsYCoCgDXT5(mincol.yz, maxcol.yz, scale); \n"
" output.w = EmitIndicesYCoCgDXT5(block, mincol.yz, maxcol.yz); \n"
" \n"
" InsetYBBox(mincol.x, maxcol.x); \n"
" \n"
" // Output Y in DXT5 alpha block. \n"
" output.x = EmitAlphaEndPointsYCoCgDXT5(mincol.x, maxcol.x); \n"
" \n"
" uint2 indices = EmitAlphaIndicesYCoCgDXT5(block, mincol.x, maxcol.x); \n"
" output.x |= indices.x; \n"
" output.y = indices.y; \n"
" \n"
" return output; \n"
"} \n"
" \n"
"uint4 compress_YCoCgDXT5_BGRA_fp(float2 texcoord : TEXCOORD0, \n"
" uniform sampler2D image, \n"
" uniform float2 imageSize = { 512.0, 512.0 } \n"
" ) : COLOR \n"
"{ \n"
" //imageSize = tex2Dsize(image, texcoord); \n"
" \n"
" // read block \n"
" float3 block[16]; \n"
" ExtractColorBlockYCoCg_BGR(block, image, texcoord, imageSize); \n"
" \n"
" // find min and max colors \n"
" float3 mincol, maxcol; \n"
" FindMinMaxColorsBox(block, mincol, maxcol); \n"
" \n"
" SelectYCoCgDiagonal(block, mincol.yz, maxcol.yz); \n"
" \n"
" int scale = ScaleYCoCg(mincol.yz, maxcol.yz); \n"
" \n"
" // Output CoCg in DXT1 block. \n"
" uint4 output; \n"
" output.z = EmitEndPointsYCoCgDXT5(mincol.yz, maxcol.yz, scale); \n"
" output.w = EmitIndicesYCoCgDXT5(block, mincol.yz, maxcol.yz); \n"
" \n"
" InsetYBBox(mincol.x, maxcol.x); \n"
" \n"
" // Output Y in DXT5 alpha block. \n"
" output.x = EmitAlphaEndPointsYCoCgDXT5(mincol.x, maxcol.x); \n"
" \n"
" uint2 indices = EmitAlphaIndicesYCoCgDXT5(block, mincol.x, maxcol.x); \n"
" output.x |= indices.x; \n"
" output.y = indices.y; \n"
" \n"
" return output; \n"
"} \n"
" \n"
"uniform bool reconstructColor = false; \n"
"uniform bool displayError = false; \n"
"uniform float errorScale = 4.0f; \n"
" \n"
"uniform sampler2D image : TEXUNIT0; \n"
"uniform sampler2D originalImage : TEXUNIT1; \n"
" \n"
"float4 display_fp(float2 texcoord : TEXCOORD0) : COLOR \n"
"{ \n"
" float4 rgba = tex2D(image, texcoord); \n"
" \n"
" if (reconstructColor) \n"
" { \n"
" float Y = rgba.a; \n"
" float scale = 1.0 / ((255.0 / 8.0) * rgba.b + 1); \n"
" float Co = (rgba.r - offset) * scale; \n"
" float Cg = (rgba.g - offset) * scale; \n"
" \n"
" float R = Y + Co - Cg; \n"
" float G = Y + Cg; \n"
" float B = Y - Co - Cg; \n"
" \n"
" rgba = float4(R, G, B, 1); \n"
" } \n"
" \n"
" if (displayError) \n"
" { \n"
" float3 originalColor = tex2D(originalImage, texcoord).rgb; \n"
" float3 diff = abs(rgba.rgb - originalColor) * errorScale; \n"
" return float4(diff, 1); \n"
" } \n"
" else \n"
" { \n"
" return rgba; \n"
" } \n"
"} \n"
" \n";

View File

@ -0,0 +1,194 @@
/*
* This file was taken from RakNet 4.082 without any modifications.
* Please see licenses/RakNet license.txt for the underlying license and related copyright.
*/
#include <stdio.h>
#include <stdlib.h>
#include <memory.h>
#include "DXTCompressor.h"
/* ------------------------------------------------------------------------------------------------------------------------------------ */
bool LoadTGAFromFile( const char* pFilename, void **image, int* width, int* height )
{
typedef struct
{
char identsize;
char colourmaptype;
char imagetype;
unsigned short colourmapstart;
unsigned short colourmaplength;
char colourmapbits;
unsigned short xstart;
unsigned short ystart;
unsigned short width;
unsigned short height;
char bits;
char descriptor;
} TGA_HEADER;
// Open the file
FILE* pic;
if((pic=fopen( pFilename, "rb"))==NULL )
{
return false;
}
// Zero out the header
TGA_HEADER TGAheader;
memset(&TGAheader,0,sizeof(TGA_HEADER));
// Read the header
fread(&TGAheader.identsize,sizeof(char),1,pic);
fread(&TGAheader.colourmaptype,sizeof(char),1,pic);
fread(&TGAheader.imagetype,sizeof(char),1,pic);
fread(&TGAheader.colourmapstart,sizeof(unsigned short),1,pic);
fread(&TGAheader.colourmaplength,sizeof(unsigned short),1,pic);
fread(&TGAheader.colourmapbits,sizeof(char),1,pic);
fread(&TGAheader.xstart,sizeof(unsigned short),1,pic);
fread(&TGAheader.ystart,sizeof(unsigned short),1,pic);
fread(&TGAheader.width,sizeof(unsigned short),1,pic);
fread(&TGAheader.height,sizeof(unsigned short),1,pic);
fread(&TGAheader.bits,sizeof(char),1,pic);
fread(&TGAheader.descriptor,sizeof(char),1,pic);
*width = TGAheader.width;
*height = TGAheader.height;
int DataSize = TGAheader.width*TGAheader.height*4;
// Read the pixels
*image = new char[DataSize];
if ((TGAheader.descriptor>>5) & 1)
{
// Right side up
fread(*image, sizeof(char),DataSize, pic);
}
else
{
//Upside down
for (int row=TGAheader.height-1; row >=0; row--)
{
fread(((char*) (*image))+row*TGAheader.width*TGAheader.bits/8, TGAheader.bits/8, TGAheader.width, pic);
}
}
// Close the file
fclose(pic);
// TGA is stored on disk BGRA
// Endian swap bits so that the image is actually in RGBA format
if( TGAheader.bits == 32 )
{
unsigned char* pRunner = (unsigned char*)*image;
for( int i = 0; i < DataSize; i+=4 )
{
char color[4] =
{
pRunner[ 0 ],
pRunner[ 1 ],
pRunner[ 2 ],
pRunner[ 3 ],
};
pRunner[ 0 ] = color[ 2 ];
pRunner[ 1 ] = color[ 1 ];
pRunner[ 2 ] = color[ 0 ];
pRunner[ 3 ] = color[ 3 ];
pRunner += 4;
}
}
return true;
}
/* ------------------------------------------------------------------------------------------------------------------------------------ */
int main( int argc, const char* argv[] )
{
// Initialize the compressor
DXTCompressor::Initialize();
// Load sample .tga
void* pSourceData;
int w, h;
//bool bFileLoaded = LoadTGAFromFile( "1600x1200.tga", &pSourceData, &w, &h );
bool bFileLoaded = LoadTGAFromFile( "320x200.tga", &pSourceData, &w, &h );
if( bFileLoaded )
{
// Test performance
// const int numIterations = 100;
// for( int i = 0; i < numIterations; i++ )
// {
// // Compress the data
// void* pOutputData;
// int outputLength;
// bool bCompressSuccess = DXTCompressor::CompressRGBAImageData( DXT1, pSourceData, w, h, &pOutputData, &outputLength, false );
//
// // Clean up
// delete [] pOutputData;
// pOutputData = NULL;
// }
// Print total stats
// printf( "\n\n****Total stats on %d iterations****\n", numIterations );
// DXTCompressor::PrintPerformanceLog();
// Now test saving to DDS memory file
{
// Compress the data
// void* pCompressedOutput;
// int compressedOutputLength;
// bool bCompressSuccess = DXTCompressor::CompressRGBAImageData( DXT1, pSourceData, w, h, &pCompressedOutput, &compressedOutputLength, false );
char *outputData;
int bufferSize = DXTCompressor::GetBufferSize(DXT1,
w,
h);
int ddsHeaderSize = DXTCompressor::GetDDSHeaderSize();
outputData = (char*) malloc(bufferSize + ddsHeaderSize );
bool bCompressSuccess = DXTCompressor::CompressRGBAImageData(
DXT1,
pSourceData,
w,
h,
outputData+ddsHeaderSize, false );
if( bCompressSuccess )
{
// Save DDS file
// void* pOutputDDSFile;
// int outputDDSFileLength;
// DXTCompressor::WriteDDSMemoryFile( DXT1, w, h, pCompressedOutput, compressedOutputLength, &pOutputDDSFile, &outputDDSFileLength );
// Clean up
// delete [] pCompressedOutput;
// pCompressedOutput = NULL;
// delete [] pOutputDDSFile;
// pOutputDDSFile = NULL;
DXTCompressor::WriteDDSHeader(DXT1,
w,
h,
bufferSize,
outputData);
FILE *fp = fopen("DXTCompressorTGAtoDDS.dds", "wb");
fwrite(outputData,1,bufferSize + ddsHeaderSize,fp);
fclose(fp);
free(outputData);
}
}
}
// Shutdown the compressor
DXTCompressor::Shutdown();
return 0;
}