Merge recent changes from the witness.

This commit is contained in:
castano
2010-08-31 01:39:08 +00:00
parent 47e8f23e9f
commit e8dc679874
44 changed files with 2465 additions and 2216 deletions

View File

@ -235,13 +235,13 @@ namespace nv
}
/// Return true if element found.
bool find(const T & element, uint * index)
bool find(const T & element, uint * index) const
{
return find(element, 0, m_size, index);
}
/// Return true if element found within the given range.
bool find(const T & element, uint first, uint count, uint * index)
bool find(const T & element, uint first, uint count, uint * index) const
{
for (uint i = first; i < first+count; i++) {
if (m_buffer[i] == element) {

View File

@ -21,6 +21,7 @@
# include <dbghelp.h>
# endif
# endif
# pragma comment(lib,"dbghelp.lib")
#endif
#if !NV_OS_WIN32 && defined(HAVE_SIGNAL_H)
@ -76,55 +77,191 @@ namespace
#if NV_OS_WIN32 && NV_CC_MSVC
// TODO write minidump
static LONG WINAPI nvTopLevelFilter( struct _EXCEPTION_POINTERS * pExceptionInfo)
static bool writeMiniDump(EXCEPTION_POINTERS * pExceptionInfo)
{
NV_UNUSED(pExceptionInfo);
/* BOOL (WINAPI * Dump) (HANDLE, DWORD, HANDLE, MINIDUMP_TYPE, PMINIDUMP_EXCEPTION_INFORMATION, PMINIDUMP_USER_STREAM_INFORMATION, PMINIDUMP_CALLBACK_INFORMATION );
AutoString dbghelp_path(512);
getcwd(dbghelp_path, 512);
dbghelp_path.Append("\\DbgHelp.dll");
nvTranslatePath(dbghelp_path);
PiLibrary DbgHelp_lib(dbghelp_path, true);
if( !DbgHelp_lib.IsValid() ) {
nvDebug("*** 'DbgHelp.dll' not found.\n");
return EXCEPTION_CONTINUE_SEARCH;
}
if( !DbgHelp_lib.BindSymbol( (void **)&Dump, "MiniDumpWriteDump" ) ) {
nvDebug("*** 'DbgHelp.dll' too old.\n");
return EXCEPTION_CONTINUE_SEARCH;
}
// create the file
HANDLE hFile = ::CreateFile( "nv.dmp", GENERIC_WRITE, FILE_SHARE_WRITE, NULL, CREATE_ALWAYS, FILE_ATTRIBUTE_NORMAL, NULL );
if( hFile == INVALID_HANDLE_VALUE ) {
nvDebug("*** Failed to create dump file.\n");
return EXCEPTION_CONTINUE_SEARCH;
HANDLE hFile = CreateFile("crash.dmp", GENERIC_WRITE, FILE_SHARE_WRITE, NULL, CREATE_ALWAYS, FILE_ATTRIBUTE_NORMAL, NULL);
if (hFile == INVALID_HANDLE_VALUE) {
nvDebug("*** Failed to create dump file.\n");
return false;
}
_MINIDUMP_EXCEPTION_INFORMATION ExInfo;
MINIDUMP_EXCEPTION_INFORMATION ExInfo;
ExInfo.ThreadId = ::GetCurrentThreadId();
ExInfo.ExceptionPointers = pExceptionInfo;
ExInfo.ClientPointers = NULL;
// write the dump
bool ok = Dump( GetCurrentProcess(), GetCurrentProcessId(), hFile, MiniDumpNormal, &ExInfo, NULL, NULL )!=0;
::CloseHandle(hFile);
BOOL ok = MiniDumpWriteDump(GetCurrentProcess(), GetCurrentProcessId(), hFile, MiniDumpNormal, &ExInfo, NULL, NULL) != 0;
CloseHandle(hFile);
if( !ok ) {
nvDebug("*** Failed to save dump file.\n");
return EXCEPTION_CONTINUE_SEARCH;
if (ok == FALSE) {
nvDebug("*** Failed to save dump file.\n");
return false;
}
nvDebug("--- Dump file saved.\n");
*/
nvDebug("\nDump file saved.\n");
return true;
}
static bool hasStackTrace() {
return true;
}
/*static NV_NOINLINE int backtrace(void * trace[], int maxcount) {
// In Windows XP and Windows Server 2003, the sum of the FramesToSkip and FramesToCapture parameters must be less than 63.
int xp_maxcount = min(63-1, maxcount);
int count = RtlCaptureStackBackTrace(1, xp_maxcount, trace, NULL);
nvDebugCheck(count <= maxcount);
return count;
}*/
static NV_NOINLINE int backtraceWithSymbols(CONTEXT * ctx, void * trace[], int maxcount, int skip = 0) {
// Init the stack frame for this function
STACKFRAME64 stackFrame = { 0 };
#if NV_CPU_X86_64
DWORD dwMachineType = IMAGE_FILE_MACHINE_AMD64;
stackFrame.AddrPC.Offset = ctx->Rip;
stackFrame.AddrFrame.Offset = ctx->Rbp;
stackFrame.AddrStack.Offset = ctx->Rsp;
#elif NV_CPU_X86
DWORD dwMachineType = IMAGE_FILE_MACHINE_I386;
stackFrame.AddrPC.Offset = ctx->Eip;
stackFrame.AddrFrame.Offset = ctx->Ebp;
stackFrame.AddrStack.Offset = ctx->Esp;
#else
#error "Platform not supported!"
#endif
stackFrame.AddrPC.Mode = AddrModeFlat;
stackFrame.AddrFrame.Mode = AddrModeFlat;
stackFrame.AddrStack.Mode = AddrModeFlat;
// Walk up the stack
const HANDLE hThread = GetCurrentThread();
const HANDLE hProcess = GetCurrentProcess();
int i;
for (i = 0; i < maxcount; i++)
{
// walking once first makes us skip self
if (!StackWalk64(dwMachineType, hProcess, hThread, &stackFrame, ctx, NULL, &SymFunctionTableAccess64, &SymGetModuleBase64, NULL)) {
break;
}
/*if (stackFrame.AddrPC.Offset == stackFrame.AddrReturn.Offset || stackFrame.AddrPC.Offset == 0) {
break;
}*/
if (i >= skip) {
trace[i - skip] = (PVOID)stackFrame.AddrPC.Offset;
}
}
return i - skip;
}
static NV_NOINLINE int backtrace(void * trace[], int maxcount) {
CONTEXT ctx = { 0 };
#if NV_CPU_X86 && !NV_CPU_X86_64
ctx.ContextFlags = CONTEXT_CONTROL;
_asm {
call x
x: pop eax
mov ctx.Eip, eax
mov ctx.Ebp, ebp
mov ctx.Esp, esp
}
#else
RtlCaptureContext(&ctx);
#endif
return backtraceWithSymbols(&ctx, trace, maxcount, 1);
}
static NV_NOINLINE void printStackTrace(void * trace[], int size, int start=0)
{
HANDLE hProcess = GetCurrentProcess();
nvDebug( "\nDumping stacktrace:\n" );
// Resolve PC to function names
for (int i = start; i < size; i++)
{
// Check for end of stack walk
DWORD64 ip = (DWORD64)trace[i];
if (ip == NULL)
break;
// Get function name
#define MAX_STRING_LEN (512)
unsigned char byBuffer[sizeof(IMAGEHLP_SYMBOL64) + MAX_STRING_LEN] = { 0 };
IMAGEHLP_SYMBOL64 * pSymbol = (IMAGEHLP_SYMBOL64*)byBuffer;
pSymbol->SizeOfStruct = sizeof(IMAGEHLP_SYMBOL64);
pSymbol->MaxNameLength = MAX_STRING_LEN;
DWORD64 dwDisplacement;
if (SymGetSymFromAddr64(hProcess, ip, &dwDisplacement, pSymbol))
{
pSymbol->Name[MAX_STRING_LEN-1] = 0;
/*
// Make the symbol readable for humans
UnDecorateSymbolName( pSym->Name, lpszNonUnicodeUnDSymbol, BUFFERSIZE,
UNDNAME_COMPLETE |
UNDNAME_NO_THISTYPE |
UNDNAME_NO_SPECIAL_SYMS |
UNDNAME_NO_MEMBER_TYPE |
UNDNAME_NO_MS_KEYWORDS |
UNDNAME_NO_ACCESS_SPECIFIERS );
*/
// pSymbol->Name
const char * pFunc = pSymbol->Name;
// Get file/line number
IMAGEHLP_LINE64 theLine = { 0 };
theLine.SizeOfStruct = sizeof(theLine);
DWORD dwDisplacement;
if (!SymGetLineFromAddr64(hProcess, ip, &dwDisplacement, &theLine))
{
nvDebug("unknown(%08X) : %s\n", (uint32)ip, pFunc);
}
else
{
/*
const char* pFile = strrchr(theLine.FileName, '\\');
if ( pFile == NULL ) pFile = theLine.FileName;
else pFile++;
*/
const char * pFile = theLine.FileName;
int line = theLine.LineNumber;
nvDebug("%s(%d) : %s\n", pFile, line, pFunc);
}
}
}
}
// Write mini dump and print stack trace.
static LONG WINAPI topLevelFilter(EXCEPTION_POINTERS * pExceptionInfo)
{
void * trace[64];
int size = backtraceWithSymbols(pExceptionInfo->ContextRecord, trace, 64);
printStackTrace(trace, size, 0);
writeMiniDump(pExceptionInfo);
return EXCEPTION_CONTINUE_SEARCH;
}
@ -132,7 +269,7 @@ namespace
#if defined(HAVE_EXECINFO_H) // NV_OS_LINUX
static bool nvHasStackTrace() {
static bool hasStackTrace() {
#if NV_OS_DARWIN
return backtrace != NULL;
#else
@ -140,7 +277,7 @@ namespace
#endif
}
static void nvPrintStackTrace(void * trace[], int size, int start=0) {
static void printStackTrace(void * trace[], int size, int start=0) {
char ** string_array = backtrace_symbols(trace, size);
nvDebug( "\nDumping stacktrace:\n" );
@ -260,7 +397,7 @@ namespace
}
#if defined(HAVE_EXECINFO_H)
if (nvHasStackTrace()) // in case of weak linking
if (hasStackTrace()) // in case of weak linking
{
void * trace[64];
int size = backtrace(trace, 64);
@ -270,7 +407,7 @@ namespace
trace[1] = pnt;
}
nvPrintStackTrace(trace, size, 1);
printStackTrace(trace, size, 1);
}
#endif // defined(HAVE_EXECINFO_H)
@ -289,18 +426,14 @@ namespace
// Code from Daniel Vogel.
static bool isDebuggerPresent()
{
bool result = false;
HINSTANCE kern_lib = LoadLibraryExA( "kernel32.dll", NULL, 0 );
if( kern_lib ) {
FARPROC lIsDebuggerPresent = GetProcAddress( kern_lib, "IsDebuggerPresent" );
if( lIsDebuggerPresent && lIsDebuggerPresent() ) {
result = true;
HINSTANCE kernel32 = GetModuleHandle("kernel32.dll");
if (kernel32) {
FARPROC IsDebuggerPresent = GetProcAddress(kernel32, "IsDebuggerPresent");
if (IsDebuggerPresent != NULL && IsDebuggerPresent()) {
return true;
}
FreeLibrary( kern_lib );
}
return result;
return false;
}
// Flush the message queue. This is necessary for the message box to show up.
@ -322,11 +455,11 @@ namespace
StringBuilder error_string;
if( func != NULL ) {
error_string.format( "*** Assertion failed: %s\n On file: %s\n On function: %s\n On line: %d\n ", exp, file, func, line );
nvDebug( error_string );
nvDebug( error_string.str() );
}
else {
error_string.format( "*** Assertion failed: %s\n On file: %s\n On line: %d\n ", exp, file, line );
nvDebug( error_string );
nvDebug( error_string.str() );
}
if (isDebuggerPresent()) {
@ -334,7 +467,7 @@ namespace
}
flushMessageQueue();
int action = MessageBoxA(NULL, error_string, "Assertion failed", MB_ABORTRETRYIGNORE|MB_ICONERROR);
int action = MessageBoxA(NULL, error_string.str(), "Assertion failed", MB_ABORTRETRYIGNORE|MB_ICONERROR);
switch( action ) {
case IDRETRY:
ret = NV_ABORT_DEBUG;
@ -352,7 +485,7 @@ namespace
}*/
if( ret == NV_ABORT_EXIT ) {
// Exit cleanly.
// Exit cleanly.
throw "Assertion failed";
}
@ -402,16 +535,16 @@ namespace
#endif
#if defined(HAVE_EXECINFO_H)
if (nvHasStackTrace())
if (hasStackTrace())
{
void * trace[64];
int size = backtrace(trace, 64);
nvPrintStackTrace(trace, size, 2);
printStackTrace(trace, size, 2);
}
#endif
// Exit cleanly.
throw std::runtime_error("Assertion failed");
throw "Assertion failed";
}
};
@ -453,14 +586,12 @@ void NV_CDECL nvDebugPrint(const char *msg, ...)
/// Dump debug info.
void debug::dumpInfo()
{
#if !NV_OS_WIN32 && defined(HAVE_SIGNAL_H) && defined(HAVE_EXECINFO_H)
if (nvHasStackTrace())
if (hasStackTrace())
{
void * trace[64];
int size = backtrace(trace, 64);
nvPrintStackTrace(trace, size, 1);
printStackTrace(trace, size, 1);
}
#endif
}
@ -497,7 +628,12 @@ void debug::enableSigHandler()
#if NV_OS_WIN32 && NV_CC_MSVC
s_old_exception_filter = ::SetUnhandledExceptionFilter( nvTopLevelFilter );
s_old_exception_filter = ::SetUnhandledExceptionFilter( topLevelFilter );
// SYMOPT_DEFERRED_LOADS make us not take a ton of time unless we actual log traces
SymSetOptions(SYMOPT_DEFERRED_LOADS|SYMOPT_FAIL_CRITICAL_ERRORS|SYMOPT_LOAD_LINES|SYMOPT_UNDNAME);
SymInitialize(GetCurrentProcess(), NULL, TRUE);
#elif !NV_OS_WIN32 && defined(HAVE_SIGNAL_H)
@ -526,6 +662,8 @@ void debug::disableSigHandler()
::SetUnhandledExceptionFilter( s_old_exception_filter );
s_old_exception_filter = NULL;
SymCleanup(GetCurrentProcess());
#elif !NV_OS_WIN32 && defined(HAVE_SIGNAL_H)
sigaction(SIGSEGV, &s_old_sigsegv, NULL);

View File

@ -3,35 +3,54 @@
#include "Memory.h"
#include "Debug.h"
//#if HAVE_MALLOC_H
//#include <malloc.h>
//#endif
#include <stdlib.h>
#define USE_EFENCE 0
#if USE_EFENCE
extern "C" void *EF_malloc(size_t size);
extern "C" void *EF_realloc(void * oldBuffer, size_t newSize);
extern "C" void EF_free(void * address);
#endif
using namespace nv;
void * nv::mem::malloc(size_t size)
{
#if USE_EFENCE
return EF_malloc(size);
#else
return ::malloc(size);
#endif
}
void * nv::mem::malloc(size_t size, const char * file, int line)
{
NV_UNUSED(file);
NV_UNUSED(line);
#if USE_EFENCE
return EF_malloc(size);
#else
return ::malloc(size);
#endif
}
void nv::mem::free(const void * ptr)
{
#if USE_EFENCE
return EF_free(const_cast<void *>(ptr));
#else
::free(const_cast<void *>(ptr));
#endif
}
void * nv::mem::realloc(void * ptr, size_t size)
{
nvDebugCheck(ptr != NULL || size != 0); // undefined realloc behavior.
#if USE_EFENCE
return EF_realloc(ptr, size);
#else
return ::realloc(ptr, size);
#endif
}

View File

@ -211,9 +211,7 @@ StringBuilder::StringBuilder( const char * s, int extra_size_hint/*=0*/ ) : m_si
/** Delete the string. */
StringBuilder::~StringBuilder()
{
m_size = 0;
strFree(m_str);
m_str = NULL;
}
@ -237,7 +235,7 @@ StringBuilder & StringBuilder::formatList( const char * fmt, va_list arg )
{
nvDebugCheck(fmt != NULL);
if( m_size == 0 ) {
if (m_size == 0) {
m_size = 64;
m_str = strAlloc( m_size );
}
@ -287,21 +285,19 @@ StringBuilder & StringBuilder::append( const char * s )
const uint slen = uint(strlen( s ));
if( m_str == NULL ) {
if (m_str == NULL) {
m_size = slen + 1;
m_str = strAlloc(m_size);
strCpy( m_str, m_size, s );
memcpy(m_str, s, m_size + 1);
}
else {
const uint len = uint(strlen( m_str ));
if( m_size < len + slen + 1 ) {
if (m_size < len + slen + 1) {
m_size = len + slen + 1;
m_str = strReAlloc(m_str, m_size);
}
strCat( m_str, m_size, s );
memcpy(m_str + len, s, slen + 1);
}
return *this;
@ -338,7 +334,7 @@ StringBuilder & StringBuilder::appendFormatList( const char * fmt, va_list arg )
else {
StringBuilder tmp_str;
tmp_str.formatList( fmt, tmp );
append( tmp_str );
append( tmp_str.str() );
}
va_end(tmp);
@ -391,7 +387,7 @@ StringBuilder & StringBuilder::number( uint i, int base )
StringBuilder & StringBuilder::reserve( uint size_hint )
{
nvCheck(size_hint != 0);
if( size_hint > m_size ) {
if (size_hint > m_size) {
m_str = strReAlloc(m_str, size_hint);
m_size = size_hint;
}
@ -403,9 +399,9 @@ StringBuilder & StringBuilder::reserve( uint size_hint )
StringBuilder & StringBuilder::copy( const char * s, int extra_size/*=0*/ )
{
nvCheck( s != NULL );
uint str_size = uint(strlen( s )) + 1;
const uint str_size = uint(strlen( s )) + 1;
reserve(str_size + extra_size);
strCpy( m_str, str_size, s );
memcpy(m_str, s, str_size);
return *this;
}
@ -413,11 +409,9 @@ StringBuilder & StringBuilder::copy( const char * s, int extra_size/*=0*/ )
/** Copy an StringBuilder. */
StringBuilder & StringBuilder::copy( const StringBuilder & s )
{
if( s.m_str == NULL ) {
if (s.m_str == NULL) {
nvCheck( s.m_size == 0 );
m_size = 0;
strFree( m_str );
m_str = NULL;
reset();
}
else {
reserve( s.m_size );
@ -428,8 +422,8 @@ StringBuilder & StringBuilder::copy( const StringBuilder & s )
bool StringBuilder::endsWith(const char * str) const
{
size_t l = strlen(str);
size_t ml = strlen(m_str);
uint l = uint(strlen(str));
uint ml = uint(strlen(m_str));
if (ml < l) return false;
return strncmp(m_str + ml - l, str, l) == 0;
}
@ -596,7 +590,7 @@ void String::setString(const StringBuilder & str)
data = NULL;
}
else {
allocString(str);
allocString(str.str());
addRef();
}
}

View File

@ -89,8 +89,8 @@ namespace nv
bool isNull() const { return m_size == 0; }
// const char * accessors
operator const char * () const { return m_str; }
operator char * () { return m_str; }
//operator const char * () const { return m_str; }
//operator char * () { return m_str; }
const char * str() const { return m_str; }
char * str() { return m_str; }

View File

@ -42,6 +42,8 @@ using namespace nv;
(uint(uint8(ch2)) << 16) | (uint(uint8(ch3)) << 24 ))
#endif
const uint nv::FOURCC_NVTT = MAKEFOURCC('N', 'V', 'T', 'T');
namespace
{
static const uint FOURCC_DDS = MAKEFOURCC('D', 'D', 'S', ' ');
@ -58,6 +60,8 @@ namespace
static const uint FOURCC_DX10 = MAKEFOURCC('D', 'X', '1', '0');
static const uint FOURCC_UVER = MAKEFOURCC('U', 'V', 'E', 'R');
// 32 bit RGB formats.
static const uint D3DFMT_R8G8B8 = 20;
static const uint D3DFMT_A8R8G8B8 = 21;
@ -480,63 +484,62 @@ namespace nv
} // nv namespace
/* Not used!
namespace
{
struct FormatDescriptor
{
uint format;
uint bitcount;
uint rmask;
uint gmask;
uint bmask;
uint amask;
};
struct FormatDescriptor
{
uint format;
uint bitcount;
uint rmask;
uint gmask;
uint bmask;
uint amask;
};
static const FormatDescriptor s_d3dFormats[] =
{
{ D3DFMT_R8G8B8, 24, 0xFF0000, 0xFF00, 0xFF, 0 },
{ D3DFMT_A8R8G8B8, 32, 0xFF0000, 0xFF00, 0xFF, 0xFF000000 }, // DXGI_FORMAT_B8G8R8A8_UNORM
{ D3DFMT_X8R8G8B8, 32, 0xFF0000, 0xFF00, 0xFF, 0 }, // DXGI_FORMAT_B8G8R8X8_UNORM
{ D3DFMT_R5G6B5, 16, 0xF800, 0x7E0, 0x1F, 0 }, // DXGI_FORMAT_B5G6R5_UNORM
{ D3DFMT_X1R5G5B5, 16, 0x7C00, 0x3E0, 0x1F, 0 },
{ D3DFMT_A1R5G5B5, 16, 0x7C00, 0x3E0, 0x1F, 0x8000 }, // DXGI_FORMAT_B5G5R5A1_UNORM
{ D3DFMT_A4R4G4B4, 16, 0xF00, 0xF0, 0xF, 0xF000 },
{ D3DFMT_R3G3B2, 8, 0xE0, 0x1C, 0x3, 0 },
{ D3DFMT_A8, 8, 0, 0, 0, 8 }, // DXGI_FORMAT_A8_UNORM
{ D3DFMT_A8R3G3B2, 16, 0xE0, 0x1C, 0x3, 0xFF00 },
{ D3DFMT_X4R4G4B4, 16, 0xF00, 0xF0, 0xF, 0 },
{ D3DFMT_A2B10G10R10, 32, 0x3FF, 0xFFC00, 0x3FF00000, 0xC0000000 }, // DXGI_FORMAT_R10G10B10A2
{ D3DFMT_A8B8G8R8, 32, 0xFF, 0xFF00, 0xFF0000, 0xFF000000 }, // DXGI_FORMAT_R8G8B8A8_UNORM
{ D3DFMT_X8B8G8R8, 32, 0xFF, 0xFF00, 0xFF0000, 0 },
{ D3DFMT_G16R16, 32, 0xFFFF, 0xFFFF0000, 0, 0 }, // DXGI_FORMAT_R16G16_UNORM
{ D3DFMT_A2R10G10B10, 32, 0x3FF00000, 0xFFC00, 0x3FF, 0xC0000000 },
static const FormatDescriptor s_d3dFormats[] =
{
{ D3DFMT_R8G8B8, 24, 0xFF0000, 0xFF00, 0xFF, 0 },
{ D3DFMT_A8R8G8B8, 32, 0xFF0000, 0xFF00, 0xFF, 0xFF000000 }, // DXGI_FORMAT_B8G8R8A8_UNORM
{ D3DFMT_X8R8G8B8, 32, 0xFF0000, 0xFF00, 0xFF, 0 }, // DXGI_FORMAT_B8G8R8X8_UNORM
{ D3DFMT_R5G6B5, 16, 0xF800, 0x7E0, 0x1F, 0 }, // DXGI_FORMAT_B5G6R5_UNORM
{ D3DFMT_X1R5G5B5, 16, 0x7C00, 0x3E0, 0x1F, 0 },
{ D3DFMT_A1R5G5B5, 16, 0x7C00, 0x3E0, 0x1F, 0x8000 }, // DXGI_FORMAT_B5G5R5A1_UNORM
{ D3DFMT_A4R4G4B4, 16, 0xF00, 0xF0, 0xF, 0xF000 },
{ D3DFMT_R3G3B2, 8, 0xE0, 0x1C, 0x3, 0 },
{ D3DFMT_A8, 8, 0, 0, 0, 8 }, // DXGI_FORMAT_A8_UNORM
{ D3DFMT_A8R3G3B2, 16, 0xE0, 0x1C, 0x3, 0xFF00 },
{ D3DFMT_X4R4G4B4, 16, 0xF00, 0xF0, 0xF, 0 },
{ D3DFMT_A2B10G10R10, 32, 0x3FF, 0xFFC00, 0x3FF00000, 0xC0000000 }, // DXGI_FORMAT_R10G10B10A2
{ D3DFMT_A8B8G8R8, 32, 0xFF, 0xFF00, 0xFF0000, 0xFF000000 }, // DXGI_FORMAT_R8G8B8A8_UNORM
{ D3DFMT_X8B8G8R8, 32, 0xFF, 0xFF00, 0xFF0000, 0 },
{ D3DFMT_G16R16, 32, 0xFFFF, 0xFFFF0000, 0, 0 }, // DXGI_FORMAT_R16G16_UNORM
{ D3DFMT_A2R10G10B10, 32, 0x3FF00000, 0xFFC00, 0x3FF, 0xC0000000 },
{ D3DFMT_A2B10G10R10, 32, 0x3FF, 0xFFC00, 0x3FF00000, 0xC0000000 },
{ D3DFMT_L8, 8, 8, 0, 0, 0 }, // DXGI_FORMAT_R8_UNORM
{ D3DFMT_L16, 16, 16, 0, 0, 0 }, // DXGI_FORMAT_R16_UNORM
};
{ D3DFMT_L8, 8, 8, 0, 0, 0 }, // DXGI_FORMAT_R8_UNORM
{ D3DFMT_L16, 16, 16, 0, 0, 0 }, // DXGI_FORMAT_R16_UNORM
};
static const uint s_d3dFormatCount = sizeof(s_d3dFormats) / sizeof(s_d3dFormats[0]);
static const uint s_d3dFormatCount = sizeof(s_d3dFormats) / sizeof(s_d3dFormats[0]);
static uint findD3D9Format(uint bitcount, uint rmask, uint gmask, uint bmask, uint amask)
{
for (int i = 0; i < s_d3dFormatCount; i++)
{
if (s_d3dFormats[i].bitcount == bitcount &&
s_d3dFormats[i].rmask == rmask &&
s_d3dFormats[i].gmask == gmask &&
s_d3dFormats[i].bmask == bmask &&
s_d3dFormats[i].amask == amask)
{
return s_d3dFormats[i].format;
}
}
static uint findD3D9Format(uint bitcount, uint rmask, uint gmask, uint bmask, uint amask)
{
for (int i = 0; i < s_d3dFormatCount; i++)
{
if (s_d3dFormats[i].bitcount == bitcount &&
s_d3dFormats[i].rmask == rmask &&
s_d3dFormats[i].gmask == gmask &&
s_d3dFormats[i].bmask == bmask &&
s_d3dFormats[i].amask == amask)
{
return s_d3dFormats[i].format;
}
}
return 0;
}
return 0;
}
} // nv namespace
*/
} // namespace
DDSHeader::DDSHeader()
{
@ -551,7 +554,7 @@ DDSHeader::DDSHeader()
memset(this->reserved, 0, sizeof(this->reserved));
// Store version information on the reserved header attributes.
this->reserved[9] = MAKEFOURCC('N', 'V', 'T', 'T');
this->reserved[9] = FOURCC_NVTT;
this->reserved[10] = (2 << 16) | (1 << 8) | (0); // major.minor.revision
this->pf.size = 32;
@ -598,7 +601,7 @@ void DDSHeader::setMipmapCount(uint count)
if (count == 0 || count == 1)
{
this->flags &= ~DDSD_MIPMAPCOUNT;
this->mipmapcount = 0;
this->mipmapcount = 1;
if (this->caps.caps2 == 0) {
this->caps.caps1 = DDSCAPS_TEXTURE;
@ -725,15 +728,13 @@ void DDSHeader::setPixelFormat(uint bitcount, uint rmask, uint gmask, uint bmask
}
}
nvCheck(bitcount > 0 && bitcount <= 32);
// Align to 8.
if (bitcount <= 8) bitcount = 8;
else if (bitcount <= 16) bitcount = 16;
else if (bitcount <= 24) bitcount = 24;
else bitcount = 32;
// D3DX functions do not like this:
this->pf.fourcc = 0; //findD3D9Format(bitcount, rmask, gmask, bmask, amask);
/*if (this->pf.fourcc) {
this->pf.flags |= DDPF_FOURCC;
}*/
nvCheck(bitcount > 0 && bitcount <= 32);
this->pf.bitcount = bitcount;
this->pf.rmask = rmask;
this->pf.gmask = gmask;
@ -760,6 +761,12 @@ void DDSHeader::setHasAlphaFlag(bool b)
else this->pf.flags &= ~DDPF_ALPHAPIXELS;
}
void DDSHeader::setUserVersion(int version)
{
this->reserved[7] = FOURCC_UVER;
this->reserved[8] = version;
}
void DDSHeader::swapBytes()
{
this->fourcc = POSH_LittleU32(this->fourcc);
@ -798,10 +805,48 @@ void DDSHeader::swapBytes()
bool DDSHeader::hasDX10Header() const
{
return this->pf.fourcc == FOURCC_DX10; // @@ This is according to AMD
//return this->pf.flags == 0; // @@ This is according to MS
return this->pf.fourcc == FOURCC_DX10;
}
uint DDSHeader::signature() const
{
return this->reserved[9];
}
uint DDSHeader::toolVersion() const
{
return this->reserved[10];
}
uint DDSHeader::userVersion() const
{
if (this->reserved[7] == FOURCC_UVER) {
return this->reserved[8];
}
return 0;
}
bool DDSHeader::isNormalMap() const
{
return (pf.flags & DDPF_NORMAL) != 0;
}
bool DDSHeader::hasAlpha() const
{
return (pf.flags & DDPF_ALPHAPIXELS) != 0;
}
uint DDSHeader::d3d9Format() const
{
if (pf.flags & DDPF_FOURCC) {
return pf.fourcc;
}
else {
return findD3D9Format(pf.bitcount, pf.rmask, pf.gmask, pf.bmask, pf.amask);
}
}
DirectDrawSurface::DirectDrawSurface() : stream(NULL)
{
@ -955,7 +1000,7 @@ bool DirectDrawSurface::hasAlpha() const
}
else
{
// @@ Here we could check the ALPHA_PIXELS flag, but nobody sets it.
// @@ Here we could check the ALPHA_PIXELS flag, but nobody sets it. (except us?)
return true;
}
}
@ -1047,6 +1092,11 @@ void DirectDrawSurface::setHasAlphaFlag(bool b)
header.setHasAlphaFlag(b);
}
void DirectDrawSurface::setUserVersion(int version)
{
nvDebugCheck(isValid());
header.setUserVersion(version);
}
void DirectDrawSurface::mipmap(Image * img, uint face, uint mipmap)
{
@ -1093,6 +1143,28 @@ void DirectDrawSurface::mipmap(Image * img, uint face, uint mipmap)
}
}
void * DirectDrawSurface::readData(uint * sizePtr)
{
uint header_size = 128; // sizeof(DDSHeader);
if (header.hasDX10Header())
{
header_size += 20; // sizeof(DDSHeader10);
}
stream->seek(header_size);
int size = stream->size() - header_size;
*sizePtr = size;
void * data = new unsigned char [size];
size = stream->serialize(data, size);
nvDebugCheck(size == *sizePtr);
return data;
}
void DirectDrawSurface::readLinearImage(Image * img)
{
nvDebugCheck(stream != NULL);
@ -1411,26 +1483,33 @@ void DirectDrawSurface::printInfo() const
if (header.pf.flags & DDPF_ALPHAPREMULT) printf("\t\tDDPF_ALPHAPREMULT\n");
if (header.pf.flags & DDPF_NORMAL) printf("\t\tDDPF_NORMAL\n");
printf("\tFourCC: '%c%c%c%c'\n",
((header.pf.fourcc >> 0) & 0xFF),
((header.pf.fourcc >> 8) & 0xFF),
((header.pf.fourcc >> 16) & 0xFF),
((header.pf.fourcc >> 24) & 0xFF));
if ((header.pf.fourcc & DDPF_FOURCC) && (header.pf.bitcount != 0))
if (header.pf.fourcc != 0) {
// Display fourcc code even when DDPF_FOURCC flag not set.
printf("\tFourCC: '%c%c%c%c' (0x%.8X)\n",
((header.pf.fourcc >> 0) & 0xFF),
((header.pf.fourcc >> 8) & 0xFF),
((header.pf.fourcc >> 16) & 0xFF),
((header.pf.fourcc >> 24) & 0xFF),
header.pf.fourcc);
}
if ((header.pf.flags & DDPF_FOURCC) && (header.pf.bitcount != 0))
{
printf("\tSwizzle: '%c%c%c%c'\n",
printf("\tSwizzle: '%c%c%c%c' (0x%.8X)\n",
(header.pf.bitcount >> 0) & 0xFF,
(header.pf.bitcount >> 8) & 0xFF,
(header.pf.bitcount >> 16) & 0xFF,
(header.pf.bitcount >> 24) & 0xFF);
(header.pf.bitcount >> 24) & 0xFF,
header.pf.bitcount);
}
else
{
printf("\tBit count: %d\n", header.pf.bitcount);
}
printf("\tRed mask: 0x%.8X\n", header.pf.rmask);
printf("\tRed mask: 0x%.8X\n", header.pf.rmask);
printf("\tGreen mask: 0x%.8X\n", header.pf.gmask);
printf("\tBlue mask: 0x%.8X\n", header.pf.bmask);
printf("\tBlue mask: 0x%.8X\n", header.pf.bmask);
printf("\tAlpha mask: 0x%.8X\n", header.pf.amask);
printf("Caps:\n");
@ -1467,7 +1546,7 @@ void DirectDrawSurface::printInfo() const
printf("\tArray size: %u\n", header.header10.arraySize);
}
if (header.reserved[9] == MAKEFOURCC('N', 'V', 'T', 'T'))
if (header.reserved[9] == FOURCC_NVTT)
{
int major = (header.reserved[10] >> 16) & 0xFF;
int minor = (header.reserved[10] >> 8) & 0xFF;
@ -1476,5 +1555,10 @@ void DirectDrawSurface::printInfo() const
printf("Version:\n");
printf("\tNVIDIA Texture Tools %d.%d.%d\n", major, minor, revision);
}
if (header.reserved[7] == FOURCC_UVER)
{
printf("User Version: %d\n", header.reserved[8]);
}
}

View File

@ -33,6 +33,8 @@ namespace nv
class Stream;
struct ColorBlock;
extern const uint FOURCC_NVTT;
struct NVIMAGE_CLASS DDSPixelFormat
{
uint size;
@ -100,10 +102,17 @@ namespace nv
void setDX10Format(uint format);
void setNormalFlag(bool b);
void setHasAlphaFlag(bool b);
void setUserVersion(int version);
void swapBytes();
bool hasDX10Header() const;
uint signature() const;
uint toolVersion() const;
uint userVersion() const;
bool isNormalMap() const;
bool hasAlpha() const;
uint d3d9Format() const;
};
NVIMAGE_API Stream & operator<< (Stream & s, DDSHeader & header);
@ -137,9 +146,11 @@ namespace nv
void setNormalFlag(bool b);
void setHasAlphaFlag(bool b);
void setUserVersion(int version);
void mipmap(Image * img, uint f, uint m);
// void mipmap(FloatImage * img, uint f, uint m);
void * readData(uint * sizePtr);
void printInfo() const;

View File

@ -199,12 +199,12 @@ void FloatImage::normalize(uint base_component)
void FloatImage::packNormals(uint base_component)
{
scaleBias(base_component, 3, 0.5f, 1.0f);
scaleBias(base_component, 3, 0.5f, 0.5f);
}
void FloatImage::expandNormals(uint base_component)
{
scaleBias(base_component, 3, 2, -0.5);
scaleBias(base_component, 3, 2, -1.0);
}
void FloatImage::scaleBias(uint base_component, uint num, float scale, float bias)
@ -215,7 +215,7 @@ void FloatImage::scaleBias(uint base_component, uint num, float scale, float bia
float * ptr = this->channel(base_component + c);
for(uint i = 0; i < size; i++) {
ptr[i] = scale * (ptr[i] + bias);
ptr[i] = scale * ptr[i] + bias;
}
}
}

View File

@ -5,8 +5,10 @@
#include "FloatImage.h"
#include "TgaFile.h"
#include "PsdFile.h"
#include "DirectDrawSurface.h"
#include "nvmath/Color.h"
#include "nvmath/Half.h"
#include "nvcore/Ptr.h"
#include "nvcore/Utils.h"
@ -93,6 +95,8 @@ namespace nv
#endif // defined(HAVE_FREEIMAGE)
static FloatImage * loadFloatDDS(Stream & s);
} // ImageIO namespace
} // nv namespace
@ -207,12 +211,18 @@ FloatImage * nv::ImageIO::loadFloat(const char * fileName, Stream & s)
const uint spos = s.tell(); // Save stream position.
if (strCaseCmp(extension, ".dds") == 0) {
floatImage = loadFloatDDS(s);
}
// Try to load as a floating point image.
#if defined(HAVE_FREEIMAGE)
FREE_IMAGE_FORMAT fif = FreeImage_GetFIFFromFilename(fileName);
if (fif != FIF_UNKNOWN && FreeImage_FIFSupportsReading(fif)) {
floatImage = loadFloatFreeImage(fif, s);
}
if (floatImage == NULL) {
FREE_IMAGE_FORMAT fif = FreeImage_GetFIFFromFilename(fileName);
if (fif != FIF_UNKNOWN && FreeImage_FIFSupportsReading(fif)) {
floatImage = loadFloatFreeImage(fif, s);
}
}
#else // defined(HAVE_FREEIMAGE)
#pragma message(NV_FILE_LINE "TODO: Load TIFF and EXR files from stream.")
#if defined(HAVE_TIFF)
@ -1697,3 +1707,44 @@ bool nv::ImageIO::saveFloatEXR(const char * fileName, const FloatImage * fimage,
#endif // defined(HAVE_OPENEXR)
#endif // defined(HAVE_FREEIMAGE)
FloatImage * nv::ImageIO::loadFloatDDS(Stream & s)
{
nvCheck(s.isLoading());
nvCheck(!s.isError());
DDSHeader header;
s << header;
static const uint D3DFMT_A16B16G16R16F = 113;
// @@ We only support RGBA16F for now.
if (header.pf.fourcc == D3DFMT_A16B16G16R16F) {
const int size = header.width * header.height;
uint16 * const data = new uint16[size * 4];
s.serialize(data, size * 4 * sizeof(uint16));
FloatImage * img = new FloatImage;
img->allocate(4, header.width, header.height);
uint32 * r = (uint32 *)img->channel(0);
uint32 * g = (uint32 *)img->channel(1);
uint32 * b = (uint32 *)img->channel(2);
uint32 * a = (uint32 *)img->channel(3);
uint16 * ptr = data;
for (int i = 0; i < size; i++) {
*r++ = half_to_float( *ptr++ );
*g++ = half_to_float( *ptr++ );
*b++ = half_to_float( *ptr++ );
*a++ = half_to_float( *ptr++ );
}
delete [] data;
return img;
}
return NULL;
}

View File

@ -59,7 +59,9 @@ void CompressionOptions::reset()
m.gsize = 8;
m.bsize = 8;
m.asize = 8;
m.pixelType = PixelType_UnsignedNorm;
m.pixelType = PixelType_UnsignedNorm;
m.pitchAlignment = 1;
m.enableColorDithering = false;
m.enableAlphaDithering = false;
@ -98,10 +100,10 @@ void CompressionOptions::setColorWeights(float red, float green, float blue, flo
/// Set color mask to describe the RGB/RGBA format.
void CompressionOptions::setPixelFormat(uint bitcount, uint rmask, uint gmask, uint bmask, uint amask)
void CompressionOptions::setPixelFormat(uint bitCount, uint rmask, uint gmask, uint bmask, uint amask)
{
// Validate arguments.
nvCheck(bitcount == 8 || bitcount == 16 || bitcount == 24 || bitcount == 32);
nvCheck(bitCount <= 32);
nvCheck((rmask & gmask) == 0);
nvCheck((rmask & bmask) == 0);
nvCheck((rmask & amask) == 0);
@ -109,16 +111,16 @@ void CompressionOptions::setPixelFormat(uint bitcount, uint rmask, uint gmask, u
nvCheck((gmask & amask) == 0);
nvCheck((bmask & amask) == 0);
if (bitcount != 32)
if (bitCount != 32)
{
uint maxMask = (1 << bitcount);
uint maxMask = (1 << bitCount);
nvCheck(maxMask > rmask);
nvCheck(maxMask > gmask);
nvCheck(maxMask > bmask);
nvCheck(maxMask > amask);
}
m.bitcount = bitcount;
m.bitcount = bitCount;
m.rmask = rmask;
m.gmask = gmask;
m.bmask = bmask;
@ -153,6 +155,14 @@ void CompressionOptions::setPixelType(PixelType pixelType)
}
/// Set pitch alignment in bytes.
void CompressionOptions::setPitchAlignment(int pitchAlignment)
{
nvDebugCheck(pitchAlignment > 0 && isPowerOfTwo(pitchAlignment));
m.pitchAlignment = pitchAlignment;
}
/// Use external compressor.
void CompressionOptions::setExternalCompressor(const char * name)
{

View File

@ -51,7 +51,8 @@ namespace nvtt
uint8 asize;
PixelType pixelType;
uint pitchAlignment;
nv::String externalCompressor;
// Quantization.

View File

@ -40,12 +40,9 @@ using namespace nvtt;
namespace
{
inline uint computePitch(uint w, uint bitsize)
inline uint computePitch(uint w, uint bitsize, uint alignment)
{
uint p = w * ((bitsize + 7) / 8);
// Align to 32 bits.
return ((p + 3) / 4) * 4;
return ((w * bitsize + 8 * alignment - 1) / (8 * alignment)) * alignment;
}
inline void convert_to_a8r8g8b8(const void * src, void * dst, uint w)
@ -65,6 +62,67 @@ namespace
return half_from_float(c.u);
}
struct BitStream
{
BitStream(uint8 * ptr) : ptr(ptr), buffer(0), bits(0) {
}
void putBits(uint p, int bitCount)
{
nvDebugCheck(bits < 8);
nvDebugCheck(bitCount <= 32);
uint64 buffer = (this->buffer << bitCount) | p;
uint bits = this->bits + bitCount;
while (bits >= 8)
{
*ptr++ = (buffer & 0xFF);
buffer >>= 8;
bits -= 8;
}
this->buffer = (uint8)buffer;
this->bits = bits;
}
void putFloat(float f)
{
nvDebugCheck(bits == 0);
*((float *)ptr) = f;
ptr += 4;
}
void putHalf(float f)
{
nvDebugCheck(bits == 0);
*((uint16 *)ptr) = to_half(f);
ptr += 2;
}
void flush()
{
nvDebugCheck(bits < 8);
if (bits) {
*ptr++ = buffer;
buffer = 0;
bits = 0;
}
}
void align(int alignment)
{
nvDebugCheck(alignment >= 1);
flush();
putBits(0, ((size_t)ptr % alignment) * 8);
}
uint8 * ptr;
uint8 buffer;
uint8 bits;
};
} // namespace
@ -96,7 +154,7 @@ void PixelFormatConverter::compress(nvtt::InputFormat inputFormat, nvtt::AlphaMo
if (compressionOptions.bitcount != 0)
{
bitCount = compressionOptions.bitcount;
nvCheck(bitCount == 8 || bitCount == 16 || bitCount == 24 || bitCount == 32);
nvCheck(bitCount <= 32);
rmask = compressionOptions.rmask;
gmask = compressionOptions.gmask;
@ -130,20 +188,16 @@ void PixelFormatConverter::compress(nvtt::InputFormat inputFormat, nvtt::AlphaMo
}
}
uint byteCount = (bitCount + 7) / 8;
uint pitch = computePitch(w, bitCount);
uint srcPitch = w;
uint srcPlane = w * h;
const uint pitch = computePitch(w, bitCount, compressionOptions.pitchAlignment);
const uint wh = w * h;
// Allocate output scanline.
uint8 * dst = (uint8 *)mem::malloc(pitch + 4);
uint8 * const dst = (uint8 *)mem::malloc(pitch);
for (uint y = 0; y < h; y++)
{
const uint * src = (const uint *)data + y * srcPitch;
const float * fsrc = (const float *)data + y * srcPitch;
const uint * src = (const uint *)data + y * w;
const float * fsrc = (const float *)data + y * w;
if (inputFormat == nvtt::InputFormat_BGRA_8UB && compressionOptions.pixelType == nvtt::PixelType_UnsignedNorm && bitCount == 32 && rmask == 0xFF0000 && gmask == 0xFF00 && bmask == 0xFF && amask == 0xFF000000)
{
@ -151,7 +205,7 @@ void PixelFormatConverter::compress(nvtt::InputFormat inputFormat, nvtt::AlphaMo
}
else
{
uint8 * ptr = dst;
BitStream stream(dst);
for (uint x = 0; x < w; x++)
{
@ -171,29 +225,25 @@ void PixelFormatConverter::compress(nvtt::InputFormat inputFormat, nvtt::AlphaMo
//g = ((float *)src)[4 * x + 1];
//b = ((float *)src)[4 * x + 2];
//a = ((float *)src)[4 * x + 3];
r = fsrc[x + 0 * srcPlane];
g = fsrc[x + 1 * srcPlane];
b = fsrc[x + 2 * srcPlane];
a = fsrc[x + 3 * srcPlane];
r = fsrc[x + 0 * wh];
g = fsrc[x + 1 * wh];
b = fsrc[x + 2 * wh];
a = fsrc[x + 3 * wh];
}
if (compressionOptions.pixelType == nvtt::PixelType_Float)
{
if (rsize == 32) *((float *)ptr) = r;
else if (rsize == 16) *((uint16 *)ptr) = to_half(r);
ptr += rsize / 8;
if (rsize == 32) stream.putFloat(r);
else if (rsize == 16) stream.putHalf(r);
if (gsize == 32) *((float *)ptr) = g;
else if (gsize == 16) *((uint16 *)ptr) = to_half(g);
ptr += gsize / 8;
if (gsize == 32) stream.putFloat(g);
else if (gsize == 16) stream.putHalf(g);
if (bsize == 32) *((float *)ptr) = b;
else if (bsize == 16) *((uint16 *)ptr) = to_half(b);
ptr += bsize / 8;
if (bsize == 32) stream.putFloat(b);
else if (bsize == 16) stream.putHalf(b);
if (asize == 32) *((float *)ptr) = a;
else if (asize == 16) *((uint16 *)ptr) = to_half(a);
ptr += asize / 8;
if (asize == 32) stream.putFloat(a);
else if (asize == 16) stream.putHalf(a);
}
else
{
@ -212,25 +262,27 @@ void PixelFormatConverter::compress(nvtt::InputFormat inputFormat, nvtt::AlphaMo
p |= PixelFormat::convert(c.b, 8, bsize) << bshift;
p |= PixelFormat::convert(c.a, 8, asize) << ashift;
stream.putBits(p, bitCount);
// Output one byte at a time.
for (uint i = 0; i < byteCount; i++)
/*for (uint i = 0; i < byteCount; i++)
{
*(dst + x * byteCount + i) = (p >> (i * 8)) & 0xFF;
}
}*/
}
}
// Zero padding.
for (uint x = w * byteCount; x < pitch; x++)
stream.align(compressionOptions.pitchAlignment);
nvDebugCheck(stream.ptr == dst + pitch);
/*for (uint x = w * byteCount; x < pitch; x++)
{
*(dst + x) = 0;
}
}*/
}
if (outputOptions.outputHandler != NULL)
{
outputOptions.outputHandler->writeData(dst, pitch);
}
outputOptions.writeData(dst, pitch);
}
mem::free(dst);

View File

@ -89,18 +89,15 @@ namespace
return 0;
}
inline uint computePitch(uint w, uint bitsize)
{
uint p = w * ((bitsize + 7) / 8);
inline uint computePitch(uint w, uint bitsize, uint alignment)
{
return ((w * bitsize + 8 * alignment - 1) / (8 * alignment)) * alignment;
}
// Align to 32 bits.
return ((p + 3) / 4) * 4;
}
static int computeImageSize(uint w, uint h, uint d, uint bitCount, Format format)
static int computeImageSize(uint w, uint h, uint d, uint bitCount, uint alignment, Format format)
{
if (format == Format_RGBA) {
return d * h * computePitch(w, bitCount);
return d * h * computePitch(w, bitCount, alignment);
}
else {
// @@ Handle 3D textures. DXT and VTC have different behaviors.
@ -324,7 +321,7 @@ int Compressor::estimateSize(int w, int h, int d, const CompressionOptions & com
uint bitCount = co.getBitCount();
return computeImageSize(w, h, d, bitCount, format);
return computeImageSize(w, h, d, bitCount, co.pitchAlignment, format);
}
@ -413,7 +410,20 @@ bool Compressor::Private::outputHeader(const InputOptions::Private & inputOption
if (outputOptions.container == Container_DDS || outputOptions.container == Container_DDS10)
{
DDSHeader header;
header.setUserVersion(outputOptions.version);
if (inputOptions.textureType == TextureType_2D) {
header.setTexture2D();
}
else if (inputOptions.textureType == TextureType_Cube) {
header.setTextureCube();
}
/*else if (inputOptions.textureType == TextureType_3D) {
header.setTexture3D();
header.setDepth(inputOptions.targetDepth);
}*/
header.setWidth(inputOptions.targetWidth);
header.setHeight(inputOptions.targetHeight);
@ -499,7 +509,7 @@ bool Compressor::Private::outputHeader(const InputOptions::Private & inputOption
if (compressionOptions.format == Format_RGBA)
{
// Get output bit count.
header.setPitch(computePitch(inputOptions.targetWidth, compressionOptions.getBitCount()));
header.setPitch(computePitch(inputOptions.targetWidth, compressionOptions.getBitCount(), compressionOptions.pitchAlignment));
if (compressionOptions.pixelType == PixelType_Float)
{
@ -564,7 +574,7 @@ bool Compressor::Private::outputHeader(const InputOptions::Private & inputOption
}
else
{
header.setLinearSize(computeImageSize(inputOptions.targetWidth, inputOptions.targetHeight, inputOptions.targetDepth, compressionOptions.bitcount, compressionOptions.format));
header.setLinearSize(computeImageSize(inputOptions.targetWidth, inputOptions.targetHeight, inputOptions.targetDepth, compressionOptions.bitcount, compressionOptions.pitchAlignment, compressionOptions.format));
if (compressionOptions.format == Format_DXT1 || compressionOptions.format == Format_DXT1a || compressionOptions.format == Format_DXT1n) {
header.setFourCC('D', 'X', 'T', '1');
@ -618,17 +628,6 @@ bool Compressor::Private::outputHeader(const InputOptions::Private & inputOption
return false;
}
if (inputOptions.textureType == TextureType_2D) {
header.setTexture2D();
}
else if (inputOptions.textureType == TextureType_Cube) {
header.setTextureCube();
}
/*else if (inputOptions.textureType == TextureType_3D) {
header.setTexture3D();
header.setDepth(inputOptions.targetDepth);
}*/
// Swap bytes if necessary.
header.swapBytes();
@ -669,6 +668,19 @@ bool Compressor::Private::outputHeader(const TexImage & tex, int mipmapCount, co
{
DDSHeader header;
header.setUserVersion(outputOptions.version);
if (tex.textureType() == TextureType_2D) {
header.setTexture2D();
}
else if (tex.textureType() == TextureType_Cube) {
header.setTextureCube();
}
/*else if (tex.textureType() == TextureType_3D) {
header.setTexture3D();
header.setDepth(tex.depth());
}*/
header.setWidth(tex.width());
header.setHeight(tex.height());
header.setMipmapCount(mipmapCount);
@ -750,7 +762,7 @@ bool Compressor::Private::outputHeader(const TexImage & tex, int mipmapCount, co
if (compressionOptions.format == Format_RGBA)
{
// Get output bit count.
header.setPitch(computePitch(tex.width(), compressionOptions.getBitCount()));
header.setPitch(computePitch(tex.width(), compressionOptions.getBitCount(), compressionOptions.pitchAlignment));
if (compressionOptions.pixelType == PixelType_Float)
{
@ -815,7 +827,7 @@ bool Compressor::Private::outputHeader(const TexImage & tex, int mipmapCount, co
}
else
{
header.setLinearSize(computeImageSize(tex.width(), tex.height(), tex.depth(), compressionOptions.bitcount, compressionOptions.format));
header.setLinearSize(computeImageSize(tex.width(), tex.height(), tex.depth(), compressionOptions.bitcount, compressionOptions.pitchAlignment, compressionOptions.format));
if (compressionOptions.format == Format_DXT1 || compressionOptions.format == Format_DXT1a || compressionOptions.format == Format_DXT1n) {
header.setFourCC('D', 'X', 'T', '1');
@ -869,17 +881,6 @@ bool Compressor::Private::outputHeader(const TexImage & tex, int mipmapCount, co
return false;
}
if (tex.textureType() == TextureType_2D) {
header.setTexture2D();
}
else if (tex.textureType() == TextureType_Cube) {
header.setTextureCube();
}
/*else if (tex.textureType() == TextureType_3D) {
header.setTexture3D();
header.setDepth(tex.depth());
}*/
// Swap bytes if necessary.
header.swapBytes();
@ -890,7 +891,7 @@ bool Compressor::Private::outputHeader(const TexImage & tex, int mipmapCount, co
headerSize = 128 + 20;
}
bool writeSucceed = outputOptions.outputHandler->writeData(&header, headerSize);
bool writeSucceed = outputOptions.writeData(&header, headerSize);
if (!writeSucceed)
{
outputOptions.error(Error_FileWrite);
@ -916,7 +917,7 @@ bool Compressor::Private::compressMipmaps(uint f, const InputOptions::Private &
for (uint m = 0; m < mipmapCount; m++)
{
int size = computeImageSize(w, h, d, compressionOptions.getBitCount(), compressionOptions.format);
int size = computeImageSize(w, h, d, compressionOptions.getBitCount(), compressionOptions.pitchAlignment, compressionOptions.format);
outputOptions.beginImage(size, w, h, d, f, m);
if (!initMipmap(mipmap, inputOptions, w, h, d, f, m))
@ -1553,12 +1554,12 @@ int Compressor::Private::estimateSize(const InputOptions::Private & inputOptions
{
const Format format = compressionOptions.format;
uint bitCount = compressionOptions.bitcount;
if (format == Format_RGBA && bitCount == 0) bitCount = compressionOptions.rsize + compressionOptions.gsize + compressionOptions.bsize + compressionOptions.asize;
const uint bitCount = compressionOptions.getBitCount();
const uint pitchAlignment = compressionOptions.pitchAlignment;
inputOptions.computeTargetExtents();
uint mipmapCount = inputOptions.realMipmapCount();
const uint mipmapCount = inputOptions.realMipmapCount();
int size = 0;
@ -1570,7 +1571,7 @@ int Compressor::Private::estimateSize(const InputOptions::Private & inputOptions
for (uint m = 0; m < mipmapCount; m++)
{
size += computeImageSize(w, h, d, bitCount, format);
size += computeImageSize(w, h, d, bitCount, pitchAlignment, format);
// Compute extents of next mipmap:
w = max(1U, w / 2);

View File

@ -49,13 +49,20 @@ void OutputOptions::reset()
m.outputHeader = true;
m.container = Container_DDS;
m.version = 0;
}
/// Set output file name.
void OutputOptions::setFileName(const char * fileName)
{
m.fileName = fileName; // @@ Do we need to record filename?
if (!m.fileName.isNull())
{
// To close the file and avoid leak.
delete m.outputHandler;
}
m.fileName = fileName;
m.outputHandler = NULL;
DefaultOutputHandler * oh = new DefaultOutputHandler(fileName);
@ -94,6 +101,11 @@ void OutputOptions::setContainer(Container container)
m.container = container;
}
/// Set user version.
void OutputOptions::setUserVersion(int version)
{
m.version = version;
}
bool OutputOptions::Private::hasValidOutputHandler() const
{

View File

@ -35,9 +35,7 @@ namespace nvtt
{
DefaultOutputHandler(const char * fileName) : stream(fileName) {}
virtual ~DefaultOutputHandler()
{
}
virtual ~DefaultOutputHandler() {}
virtual void beginImage(int size, int width, int height, int depth, int face, int miplevel)
{
@ -66,6 +64,7 @@ namespace nvtt
bool outputHeader;
Container container;
int version;
bool hasValidOutputHandler() const;

View File

@ -271,23 +271,19 @@ float TexImage::alphaTestCoverage(float alphaRef/*= 0.5*/) const
bool TexImage::load(const char * fileName)
{
#pragma message(NV_FILE_LINE "TODO: Add support for DDS textures in TexImage::load().")
AutoPtr<FloatImage> img(ImageIO::loadFloat(fileName));
if (img == NULL) {
return false;
}
AutoPtr<FloatImage> img(ImageIO::loadFloat(fileName));
detach();
if (img == NULL)
{
return false;
}
img->resizeChannelCount(4);
detach();
m->imageArray.resize(1);
m->imageArray[0] = img.release();
img->resizeChannelCount(4);
m->imageArray.resize(1);
m->imageArray[0] = img.release();
return true;
return true;
}
bool TexImage::save(const char * fileName) const
@ -560,25 +556,25 @@ void TexImage::resize(int w, int h, ResizeFilter filter)
if (filter == ResizeFilter_Box)
{
BoxFilter filter;
m->imageArray[i]->resize(filter, w, h, wrapMode, 3);
img = img->resize(filter, w, h, wrapMode, 3);
}
else if (filter == ResizeFilter_Triangle)
{
TriangleFilter filter;
m->imageArray[i]->resize(filter, w, h, wrapMode, 3);
img = img->resize(filter, w, h, wrapMode, 3);
}
else if (filter == ResizeFilter_Kaiser)
{
//KaiserFilter filter(inputOptions.kaiserWidth);
//filter.setParameters(inputOptions.kaiserAlpha, inputOptions.kaiserStretch);
KaiserFilter filter(3);
m->imageArray[i]->resize(filter, w, h, wrapMode, 3);
img = img->resize(filter, w, h, wrapMode, 3);
}
else //if (filter == ResizeFilter_Mitchell)
{
nvDebugCheck(filter == ResizeFilter_Mitchell);
MitchellFilter filter;
m->imageArray[i]->resize(filter, w, h, wrapMode, 3);
img = img->resize(filter, w, h, wrapMode, 3);
}
}
else
@ -586,27 +582,30 @@ void TexImage::resize(int w, int h, ResizeFilter filter)
if (filter == ResizeFilter_Box)
{
BoxFilter filter;
m->imageArray[i]->resize(filter, w, h, wrapMode);
img = img->resize(filter, w, h, wrapMode);
}
else if (filter == ResizeFilter_Triangle)
{
TriangleFilter filter;
m->imageArray[i]->resize(filter, w, h, wrapMode);
img = img->resize(filter, w, h, wrapMode);
}
else if (filter == ResizeFilter_Kaiser)
{
//KaiserFilter filter(inputOptions.kaiserWidth);
//filter.setParameters(inputOptions.kaiserAlpha, inputOptions.kaiserStretch);
KaiserFilter filter(3);
m->imageArray[i]->resize(filter, w, h, wrapMode);
img = img->resize(filter, w, h, wrapMode);
}
else //if (filter == ResizeFilter_Mitchell)
{
nvDebugCheck(filter == ResizeFilter_Mitchell);
MitchellFilter filter;
m->imageArray[i]->resize(filter, w, h, wrapMode);
img = img->resize(filter, w, h, wrapMode);
}
}
delete m->imageArray[i];
m->imageArray[i] = img;
}
}
@ -813,6 +812,18 @@ void TexImage::scaleBias(int channel, float scale, float bias)
}
}
void TexImage::clamp(int channel, float low, float high)
{
detach();
foreach (i, m->imageArray)
{
if (m->imageArray[i] == NULL) continue;
m->imageArray[i]->clamp(channel, 1, low, high);
}
}
void TexImage::packNormal()
{
scaleBias(0, 0.5f, 0.5f);

View File

@ -48,7 +48,7 @@
# define NVTT_API
#endif
#define NVTT_VERSION 020100
#define NVTT_VERSION 20100
#define NVTT_FORBID_COPY(Class) \
private: \
@ -144,6 +144,8 @@ namespace nvtt
NVTT_API void setPixelType(PixelType pixelType);
NVTT_API void setPitchAlignment(int pitchAlignment);
NVTT_API void setQuantization(bool colorDithering, bool alphaDithering, bool binaryAlpha, int alphaThreshold = 127);
};
@ -345,6 +347,7 @@ namespace nvtt
NVTT_API void setOutputHeader(bool outputHeader);
NVTT_API void setContainer(Container container);
NVTT_API void setUserVersion(int version);
};
@ -432,6 +435,7 @@ namespace nvtt
NVTT_API void transform(const float w0[4], const float w1[4], const float w2[4], const float w3[4], const float offset[4]);
NVTT_API void swizzle(int r, int g, int b, int a);
NVTT_API void scaleBias(int channel, float scale, float bias);
NVTT_API void clamp(int channel, float low = 0.0f, float high = 1.0f);
NVTT_API void packNormal();
NVTT_API void expandNormal();
NVTT_API void blend(float r, float g, float b, float a, float t);

View File

@ -47,7 +47,7 @@
# define NVTT_API
#endif
#define NVTT_VERSION 020100
#define NVTT_VERSION 20100
#ifdef __cplusplus
typedef struct nvtt::InputOptions NvttInputOptions;

View File

@ -55,7 +55,7 @@ int main(int argc, char *argv[])
outputFileName.stripExtension();
outputFileName.append(".dds");
outputOptions.setFileName(outputFileName);
outputOptions.setFileName(outputFileName.str());
// Output compressed image.
context.outputHeader(image, image.countMipmaps(), compressionOptions, outputOptions);

View File

@ -423,7 +423,7 @@ int main(int argc, char *argv[])
Path csvFileName;
csvFileName.format("%s/result.csv", outPath);
StdOutputStream csvStream(csvFileName);
StdOutputStream csvStream(csvFileName.str());
TextWriter csvWriter(&csvStream);
float totalTime = 0;
@ -465,7 +465,7 @@ int main(int argc, char *argv[])
outputFileName.format("%s/%s", outPath, fileNames[i]);
outputFileName.stripExtension();
outputFileName.append(".png");
if (!ImageIO::save(outputFileName, img_out.ptr()))
if (!ImageIO::save(outputFileName.str(), img_out.ptr()))
{
printf("Error saving file '%s'.\n", outputFileName.str());
}

View File

@ -114,7 +114,7 @@ int main(int argc, char *argv[])
for (uint i = 0; i < imageCount; i++)
{
if (!images[i].load(files[i]))
if (!images[i].load(files[i].str()))
{
printf("*** error loading file\n");
return 1;
@ -138,7 +138,7 @@ int main(int argc, char *argv[])
}
nv::StdOutputStream stream(output);
nv::StdOutputStream stream(output.str());
if (stream.isError()) {
printf("Error opening '%s' for writting\n", output.str());
return 1;

View File

@ -295,11 +295,12 @@ int main(int argc, char *argv[])
}
const uint version = nvtt::version();
const uint major = version / 100;
const uint minor = version % 100;
const uint major = version / 100 / 100;
const uint minor = (version / 100) % 100;
const uint rev = version % 100;
printf("NVIDIA Texture Tools %u.%u - Copyright NVIDIA Corporation 2007\n\n", major, minor);
printf("NVIDIA Texture Tools %u.%u.%u - Copyright NVIDIA Corporation 2007\n\n", major, minor, rev);
if (input.isNull())
{
@ -351,7 +352,7 @@ int main(int argc, char *argv[])
if (nv::strCaseCmp(input.extension(), ".dds") == 0)
{
// Load surface.
nv::DirectDrawSurface dds(input);
nv::DirectDrawSurface dds(input.str());
if (!dds.isValid())
{
fprintf(stderr, "The file '%s' is not a valid DDS file.\n", input.str());
@ -400,7 +401,7 @@ int main(int argc, char *argv[])
if (loadAsFloat)
{
nv::AutoPtr<nv::FloatImage> image(nv::ImageIO::loadFloat(input));
nv::AutoPtr<nv::FloatImage> image(nv::ImageIO::loadFloat(input.str()));
if (image == NULL)
{
@ -420,7 +421,7 @@ int main(int argc, char *argv[])
{
// Regular image.
nv::Image image;
if (!image.load(input))
if (!image.load(input.str()))
{
fprintf(stderr, "The file '%s' is not a supported image type.\n", input.str());
return 1;
@ -449,6 +450,9 @@ int main(int argc, char *argv[])
inputOptions.setAlphaMode(nvtt::AlphaMode_None);
}
inputOptions.setRoundMode(nvtt::RoundMode_ToNearestPowerOfTwo);
if (normal)
{
setNormalMap(inputOptions);
@ -524,7 +528,7 @@ int main(int argc, char *argv[])
MyErrorHandler errorHandler;
MyOutputHandler outputHandler(output);
MyOutputHandler outputHandler(output.str());
if (outputHandler.stream->isError())
{
fprintf(stderr, "Error opening '%s' for writting\n", output.str());

View File

@ -112,7 +112,7 @@ int main(int argc, char *argv[])
}
// Load surface.
nv::DirectDrawSurface dds(input);
nv::DirectDrawSurface dds(input.str());
if (!dds.isValid())
{
fprintf(stderr, "The file '%s' is not a valid DDS file.\n", input.str());
@ -179,7 +179,7 @@ int main(int argc, char *argv[])
return 1;
}
nv::ImageIO::save(name, stream, &mipmap);
nv::ImageIO::save(name.str(), stream, &mipmap);
}
}

View File

@ -204,8 +204,8 @@ int main(int argc, char *argv[])
}
nv::Image image0, image1;
if (!loadImage(image0, input0)) return 0;
if (!loadImage(image1, input1)) return 0;
if (!loadImage(image0, input0.str())) return 0;
if (!loadImage(image1, input1.str())) return 0;
const uint w0 = image0.width();
const uint h0 = image0.height();

View File

@ -164,7 +164,7 @@ int main(int argc, char *argv[])
}
nv::Image image;
if (!loadImage(image, input)) return 0;
if (!loadImage(image, input.str())) return 0;
nv::FloatImage fimage(&image);
fimage.toLinear(0, 3, gamma);