From 6dd43cde4f34d19a2dafddd3767f8bd1e8f3f8aa Mon Sep 17 00:00:00 2001 From: Pavel Krajcevski Date: Mon, 11 Nov 2013 18:45:09 -0500 Subject: [PATCH 01/15] Fix compiler problems on MinGW --- CLTool/src/tc.cpp | 4 +-- Core/src/StopWatchWin32.cpp | 39 +++++++++++++++++++++++------ Core/src/ThreadPThread.cpp | 9 ++++++- Core/src/WorkerQueue.cpp | 4 +-- GTest/cmake/internal_utils.cmake | 2 +- GTest/src/gtest-death-test.cc | 4 +++ IO/src/FileStreamWin32.cpp | 43 +++++++++++++++++--------------- 7 files changed, 72 insertions(+), 33 deletions(-) diff --git a/CLTool/src/tc.cpp b/CLTool/src/tc.cpp index 04438b9..402ccf2 100644 --- a/CLTool/src/tc.cpp +++ b/CLTool/src/tc.cpp @@ -98,7 +98,7 @@ void ExtractBasename(const char *filename, char *buf, size_t bufSz) { } } - uint64 numChars = ext - base + 1; + size_t numChars = ext - base + 1; size_t toCopy = ::std::min(numChars, bufSz); memcpy(buf, base, toCopy); buf[toCopy - 1] = '\0'; @@ -323,4 +323,4 @@ int main(int argc, char **argv) { logFile.close(); } return 0; -} \ No newline at end of file +} diff --git a/Core/src/StopWatchWin32.cpp b/Core/src/StopWatchWin32.cpp index 1827701..245fff1 100755 --- a/Core/src/StopWatchWin32.cpp +++ b/Core/src/StopWatchWin32.cpp @@ -68,21 +68,30 @@ #include #include +#include class StopWatchImpl { public: uint64 frequency; uint64 start; uint64 stop; +#ifndef __MINGW32__ uintptr_t affinityMask; +#endif StopWatchImpl() : - start(0), stop(0), affinityMask(0) + start(0), stop(0) +#ifndef __MINGW32__ + , affinityMask(0) +#endif { // Initialize the performance counter frequency. LARGE_INTEGER perfQuery; - BOOL supported = QueryPerformanceFrequency(&perfQuery); - assert(supported == TRUE); +#ifndef NDEBUG + assert(QueryPerformanceFrequency(&perfQuery)); +#else + QueryPerformanceFrequency(&perfQuery); +#endif this->frequency = perfQuery.QuadPart; } }; @@ -110,42 +119,56 @@ StopWatch::~StopWatch() { // Start the stopwatch. void StopWatch::Start() { +#ifndef __MINGW32__ // MSDN recommends setting the thread affinity to avoid bugs in the BIOS and HAL. // Create an affinity mask for the current processor. impl->affinityMask = (DWORD_PTR)1 << GetCurrentProcessorNumber(); HANDLE currThread = GetCurrentThread(); DWORD_PTR prevAffinityMask = SetThreadAffinityMask(currThread, impl->affinityMask); assert(prevAffinityMask != 0); +#endif // Query the performance counter. LARGE_INTEGER perfQuery; - BOOL result = QueryPerformanceCounter(&perfQuery); - assert(result); +#ifndef NDEBUG + assert(QueryPerformanceCounter(&perfQuery)); +#else + QueryPerformanceCounter(&perfQuery); +#endif impl->start = perfQuery.QuadPart; +#ifndef __MINGW32__ // Restore the thread's affinity mask. prevAffinityMask = SetThreadAffinityMask(currThread, prevAffinityMask); assert(prevAffinityMask != 0); +#endif } // Stop the stopwatch. void StopWatch::Stop() { +#ifndef __MINGW32__ // MSDN recommends setting the thread affinity to avoid bugs in the BIOS and HAL. // Use the affinity mask that was created in the Start function. HANDLE currThread = GetCurrentThread(); DWORD_PTR prevAffinityMask = SetThreadAffinityMask(currThread, impl->affinityMask); assert(prevAffinityMask != 0); +#endif // Query the performance counter. LARGE_INTEGER perfQuery; - BOOL result = QueryPerformanceCounter(&perfQuery); - assert(result); +#ifndef NDEBUG + assert(QueryPerformanceCounter(&perfQuery)); +#else + QueryPerformanceCounter(&perfQuery); +#endif impl->stop = perfQuery.QuadPart; +#ifndef __MINGW32__ // Restore the thread's affinity mask. prevAffinityMask = SetThreadAffinityMask(currThread, prevAffinityMask); assert(prevAffinityMask != 0); +#endif } // Reset the stopwatch. @@ -153,7 +176,9 @@ void StopWatch::Reset() { impl->start = 0; impl->stop = 0; +#ifndef __MINGW32__ impl->affinityMask = 0; +#endif } // Get the elapsed time in seconds. diff --git a/Core/src/ThreadPThread.cpp b/Core/src/ThreadPThread.cpp index f4579ce..e55da1c 100644 --- a/Core/src/ThreadPThread.cpp +++ b/Core/src/ThreadPThread.cpp @@ -123,8 +123,11 @@ void TCThread::Join() { ((TCThreadImpl *)m_Impl)->Join(); } +#ifdef WIN32 +#undef Yield +#endif void TCThread::Yield() { -#ifdef __APPLE__ +#if defined(__APPLE__) || defined(__MINGW32__) int result = sched_yield(); #else int result = pthread_yield(); @@ -135,7 +138,11 @@ void TCThread::Yield() { } uint64 TCThread::ThreadID() { +#ifdef __MINGW32__ + return static_cast(pthread_self().x); +#else return static_cast(pthread_self()); +#endif } //////////////////////////////////////////////////////////////////////////////// diff --git a/Core/src/WorkerQueue.cpp b/Core/src/WorkerQueue.cpp index e2df7af..c8b54ca 100644 --- a/Core/src/WorkerQueue.cpp +++ b/Core/src/WorkerQueue.cpp @@ -268,7 +268,7 @@ WorkerThread::EAction WorkerQueue::AcceptThreadData(uint32 threadIdx) { void WorkerQueue::GetStartForThread(const uint32 threadIdx, uint32 (&start)[2]) { assert(threadIdx >= 0); - assert(threadIdx < int(m_NumThreads)); + assert(threadIdx < m_NumThreads); assert(m_Offsets[threadIdx] >= 0); const uint32 blockIdx = m_Offsets[threadIdx]; @@ -277,7 +277,7 @@ void WorkerQueue::GetStartForThread(const uint32 threadIdx, uint32 (&start)[2]) void WorkerQueue::GetEndForThread(const uint32 threadIdx, uint32 (&end)[2]) { assert(threadIdx >= 0); - assert(threadIdx < int(m_NumThreads)); + assert(threadIdx < m_NumThreads); assert(m_Offsets[threadIdx] >= 0); assert(m_NumBlocks[threadIdx] >= 0); diff --git a/GTest/cmake/internal_utils.cmake b/GTest/cmake/internal_utils.cmake index 8cb2189..47ccadb 100644 --- a/GTest/cmake/internal_utils.cmake +++ b/GTest/cmake/internal_utils.cmake @@ -104,7 +104,7 @@ macro(config_compiler_and_linker) set(cxx_no_rtti_flags "") endif() - if (CMAKE_USE_PTHREADS_INIT) # The pthreads library is available and allowed. + if (CMAKE_USE_PTHREADS_INIT AND NOT MINGW) # The pthreads library is available and allowed. set(cxx_base_flags "${cxx_base_flags} -DGTEST_HAS_PTHREAD=1") else() set(cxx_base_flags "${cxx_base_flags} -DGTEST_HAS_PTHREAD=0") diff --git a/GTest/src/gtest-death-test.cc b/GTest/src/gtest-death-test.cc index a6023fc..a5ceb96 100644 --- a/GTest/src/gtest-death-test.cc +++ b/GTest/src/gtest-death-test.cc @@ -120,7 +120,9 @@ namespace internal { // Valid only for fast death tests. Indicates the code is running in the // child process of a fast style death test. +#ifndef GTEST_OS_WINDOWS static bool g_in_fast_death_test_child = false; +#endif // Returns a Boolean value indicating whether the caller is currently // executing in the context of the death test child process. Tools such as @@ -852,7 +854,9 @@ DeathTest::TestRole NoExecDeathTest::AssumeRole() { // Event forwarding to the listeners of event listener API mush be shut // down in death test subprocesses. GetUnitTestImpl()->listeners()->SuppressEventForwarding(); +#ifndef GTEST_OS_WINDOWS g_in_fast_death_test_child = true; +#endif return EXECUTE_TEST; } else { GTEST_DEATH_TEST_CHECK_SYSCALL_(close(pipe_fd[1])); diff --git a/IO/src/FileStreamWin32.cpp b/IO/src/FileStreamWin32.cpp index a9e1581..2fce0f5 100755 --- a/IO/src/FileStreamWin32.cpp +++ b/IO/src/FileStreamWin32.cpp @@ -52,13 +52,16 @@ #include "FileStream.h" +#define _CRT_SECURE_NO_WARNINGS +#define WIN32_LEAN_AND_MEAN #include -#include -#include -#include +#include +#include +#include +#include -void ErrorExit(LPTSTR lpszFunction) +void ErrorExit(LPCSTR lpszFunction) { // Retrieve the system error message for the last-error code @@ -80,10 +83,10 @@ void ErrorExit(LPTSTR lpszFunction) lpDisplayBuf = (LPVOID)LocalAlloc(LMEM_ZEROINIT, (lstrlen((LPCTSTR)lpMsgBuf) + lstrlen((LPCTSTR)lpszFunction) + 40) * sizeof(TCHAR)); - StringCchPrintf((LPTSTR)lpDisplayBuf, - LocalSize(lpDisplayBuf) / sizeof(TCHAR), - TEXT("%s failed with error %d: %s"), - lpszFunction, dw, lpMsgBuf); + snprintf((LPTSTR)lpDisplayBuf, + LocalSize(lpDisplayBuf) / sizeof(CHAR), + "%s failed with error %lu: %s", + lpszFunction, dw, (LPCSTR)lpMsgBuf); MessageBox(NULL, (LPCTSTR)lpDisplayBuf, TEXT("Error"), MB_OK); LocalFree(lpMsgBuf); @@ -150,7 +153,7 @@ FileStream::FileStream(const CHAR *filename, EFileMode mode) : m_Impl(new FileStreamImpl(filename, mode)) , m_Mode(mode) { - strncpy_s(m_Filename, filename, kMaxFilenameSz); + strncpy(m_Filename, filename, kMaxFilenameSz); m_Filename[kMaxFilenameSz - 1] = CHAR('\0'); } @@ -159,7 +162,7 @@ FileStream::FileStream(const FileStream &other) , m_Mode(other.m_Mode) { m_Impl->IncreaseReferenceCount(); - strncpy_s(m_Filename, other.m_Filename, kMaxFilenameSz); + strncpy(m_Filename, other.m_Filename, kMaxFilenameSz); } FileStream &FileStream::operator=(const FileStream &other) { @@ -178,7 +181,7 @@ FileStream &FileStream::operator=(const FileStream &other) { m_Impl->IncreaseReferenceCount(); m_Mode = other.m_Mode; - strncpy_s(m_Filename, other.m_Filename, kMaxFilenameSz); + strncpy(m_Filename, other.m_Filename, kMaxFilenameSz); return *this; } @@ -203,8 +206,8 @@ int32 FileStream::Read(uint8 *buf, uint32 bufSz) { m_Mode == eFileMode_WriteBinaryAppend ) { CHAR errStr[256]; - _sntprintf_s(errStr, 256, "Cannot read from file '%s': File opened for reading.", m_Filename); - OutputDebugString(errStr); + snprintf(errStr, 256, "Cannot read from file '%s': File opened for reading.", m_Filename); + OutputDebugString(errStr); return -2; } @@ -215,7 +218,7 @@ int32 FileStream::Read(uint8 *buf, uint32 bufSz) { DWORD oldPosition = SetFilePointer(fp, 0, NULL, FILE_CURRENT); if(INVALID_SET_FILE_POINTER == oldPosition) { CHAR errStr[256]; - _sntprintf_s(errStr, 256, "Error querying the file position before reading from file '%s'(0x%x).", m_Filename, GetLastError()); + snprintf(errStr, 256, "Error querying the file position before reading from file '%s'(0x%lx).", m_Filename, GetLastError()); OutputDebugString(errStr); return -1; } @@ -224,7 +227,7 @@ int32 FileStream::Read(uint8 *buf, uint32 bufSz) { BOOL success = ReadFile(fp, buf, bufSz, &amtRead, NULL); if(!success) { CHAR errStr[256]; - _sntprintf_s(errStr, 256, "Error reading from file '%s'.", m_Filename); + snprintf(errStr, 256, "Error reading from file '%s'.", m_Filename); OutputDebugString(errStr); return -1; } @@ -232,7 +235,7 @@ int32 FileStream::Read(uint8 *buf, uint32 bufSz) { DWORD newPosition = SetFilePointer(fp, 0, NULL, FILE_CURRENT); if(INVALID_SET_FILE_POINTER == newPosition) { CHAR errStr[256]; - _sntprintf_s(errStr, 256, "Error querying the file position after reading from file '%s'(0x%x).", m_Filename, GetLastError()); + snprintf(errStr, 256, "Error querying the file position after reading from file '%s'(0x%lx).", m_Filename, GetLastError()); OutputDebugString(errStr); return -1; } @@ -246,7 +249,7 @@ int32 FileStream::Write(const uint8 *buf, uint32 bufSz) { m_Mode == eFileMode_ReadBinary ) { CHAR errStr[256]; - _sntprintf_s(errStr, 256, "Cannot write to file '%s': File opened for writing.", m_Filename); + snprintf(errStr, 256, "Cannot write to file '%s': File opened for writing.", m_Filename); OutputDebugString(errStr); return -2; } @@ -265,7 +268,7 @@ int32 FileStream::Write(const uint8 *buf, uint32 bufSz) { if(INVALID_SET_FILE_POINTER == dwPos) { CHAR errStr[256]; - _sntprintf_s(errStr, 256, "Error querying the file position before reading to file '%s'(0x%x).", m_Filename, GetLastError()); + snprintf(errStr, 256, "Error querying the file position before reading to file '%s'(0x%lx).", m_Filename, GetLastError()); OutputDebugString(errStr); return -1; } @@ -279,7 +282,7 @@ int32 FileStream::Write(const uint8 *buf, uint32 bufSz) { if(!success) { CHAR errStr[256]; - _sntprintf_s(errStr, 256, "Error writing to file '%s'.", m_Filename); + snprintf(errStr, 256, "Error writing to file '%s'.", m_Filename); OutputDebugString(errStr); return -1; } @@ -296,7 +299,7 @@ int32 FileStream::Tell() { DWORD pos = SetFilePointer(fp, 0, NULL, FILE_CURRENT); if(INVALID_SET_FILE_POINTER == pos) { CHAR errStr[256]; - _sntprintf_s(errStr, 256, "Error querying the file position before reading to file '%s'(0x%x).", m_Filename, GetLastError()); + snprintf(errStr, 256, "Error querying the file position before reading to file '%s'(0x%lx).", m_Filename, GetLastError()); OutputDebugString(errStr); return -1; } From 9a7813b732497afc4aafb6d125894f10f11a0413 Mon Sep 17 00:00:00 2001 From: Pavel Krajcevski Date: Mon, 11 Nov 2013 18:54:29 -0500 Subject: [PATCH 02/15] Make sure MSVC is still OK with our MINGW changes --- IO/src/FileStreamWin32.cpp | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/IO/src/FileStreamWin32.cpp b/IO/src/FileStreamWin32.cpp index 2fce0f5..5042eb6 100755 --- a/IO/src/FileStreamWin32.cpp +++ b/IO/src/FileStreamWin32.cpp @@ -61,6 +61,11 @@ #include #include +#ifdef _MSC_VER +#define snprintf(out, outSz, fmt, ...) _snprintf_s(out, outSz, _TRUNCATE, fmt, __VA_ARGS__) +#define strncpy(dst, src, dstSz) strncpy_s(dst, dstSz, src, _TRUNCATE) +#endif + void ErrorExit(LPCSTR lpszFunction) { // Retrieve the system error message for the last-error code From 955fe204adf67120edcc66da4b348cf9f5b42f85 Mon Sep 17 00:00:00 2001 From: Pavel Krajcevski Date: Thu, 23 Jan 2014 14:33:37 -0500 Subject: [PATCH 03/15] Add OpenGL discovery to read/write KTX files --- IO/CMakeLists.txt | 5 +++ IO/config/ImageLoader.h.in | 4 ++ IO/config/ImageWriter.h.in | 4 ++ IO/src/GLDefines.h | 84 ++++++++++++++++++++++++++++++++++++++ 4 files changed, 97 insertions(+) create mode 100644 IO/src/GLDefines.h diff --git a/IO/CMakeLists.txt b/IO/CMakeLists.txt index 58b4046..72491a5 100644 --- a/IO/CMakeLists.txt +++ b/IO/CMakeLists.txt @@ -87,6 +87,11 @@ INCLUDE_DIRECTORIES( ${FasTC_SOURCE_DIR}/IO/third_party/tga ) SET( SOURCES ${SOURCES} "src/ImageLoaderTGA.cpp" ) SET( HEADERS ${HEADERS} "src/ImageLoaderTGA.h" ) +FIND_PACKAGE( OpenGL ) +IF(OPENGL_FOUND) + INCLUDE_DIRECTORIES( ${OPENGL_INCLUDE_DIRS} ) +ENDIF(OPENGL_FOUND) + CONFIGURE_FILE( "config/ImageLoader.h.in" "include/ImageLoader.h" diff --git a/IO/config/ImageLoader.h.in b/IO/config/ImageLoader.h.in index 971bb89..3d9e363 100644 --- a/IO/config/ImageLoader.h.in +++ b/IO/config/ImageLoader.h.in @@ -154,4 +154,8 @@ class ImageLoader { #cmakedefine PVRTEXLIB_FOUND #endif // PVRTEXLIB_FOUND +#ifndef OPENGL_FOUND +#cmakedefine OPENGL_FOUND +#endif // OPENGL_FOUND + #endif // _IMAGE_LOADER_H_ diff --git a/IO/config/ImageWriter.h.in b/IO/config/ImageWriter.h.in index 0d609d5..60ea2a4 100644 --- a/IO/config/ImageWriter.h.in +++ b/IO/config/ImageWriter.h.in @@ -95,4 +95,8 @@ class ImageWriter { #cmakedefine PVRTEXLIB_FOUND #endif // PVRTEXLIB_FOUND +#ifndef OPENGL_FOUND +#cmakedefine OPENGL_FOUND +#endif // OPENGL_FOUND + #endif // _IMAGE_LOADER_H_ diff --git a/IO/src/GLDefines.h b/IO/src/GLDefines.h new file mode 100644 index 0000000..03d01c4 --- /dev/null +++ b/IO/src/GLDefines.h @@ -0,0 +1,84 @@ +/* FasTC + * Copyright (c) 2014 University of North Carolina at Chapel Hill. + * All rights reserved. + * + * Permission to use, copy, modify, and distribute this software and its + * documentation for educational, research, and non-profit purposes, without + * fee, and without a written agreement is hereby granted, provided that the + * above copyright notice, this paragraph, and the following four paragraphs + * appear in all copies. + * + * Permission to incorporate this software into commercial products may be + * obtained by contacting the authors or the Office of Technology Development + * at the University of North Carolina at Chapel Hill . + * + * This software program and documentation are copyrighted by the University of + * North Carolina at Chapel Hill. The software program and documentation are + * supplied "as is," without any accompanying services from the University of + * North Carolina at Chapel Hill or the authors. The University of North + * Carolina at Chapel Hill and the authors do not warrant that the operation of + * the program will be uninterrupted or error-free. The end-user understands + * that the program was developed for research purposes and is advised not to + * rely exclusively on the program for any reason. + * + * IN NO EVENT SHALL THE UNIVERSITY OF NORTH CAROLINA AT CHAPEL HILL OR THE + * AUTHORS BE LIABLE TO ANY PARTY FOR DIRECT, INDIRECT, SPECIAL, INCIDENTAL, + * OR CONSEQUENTIAL DAMAGES, INCLUDING LOST PROFITS, ARISING OUT OF THE USE OF + * THIS SOFTWARE AND ITS DOCUMENTATION, EVEN IF THE UNIVERSITY OF NORTH CAROLINA + * AT CHAPEL HILL OR THE AUTHORS HAVE BEEN ADVISED OF THE POSSIBILITY OF SUCH + * DAMAGE. + * + * THE UNIVERSITY OF NORTH CAROLINA AT CHAPEL HILL AND THE AUTHORS SPECIFICALLY + * DISCLAIM ANY WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED + * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE AND ANY + * STATUTORY WARRANTY OF NON-INFRINGEMENT. THE SOFTWARE PROVIDED HEREUNDER IS ON + * AN "AS IS" BASIS, AND THE UNIVERSITY OF NORTH CAROLINA AT CHAPEL HILL AND + * THE AUTHORS HAVE NO OBLIGATIONS TO PROVIDE MAINTENANCE, SUPPORT, UPDATES, + * ENHANCEMENTS, OR MODIFICATIONS. + * + * Please send all BUG REPORTS to . + * + * The authors may be contacted via: + * + * Pavel Krajcevski + * Dept of Computer Science + * 201 S Columbia St + * Frederick P. Brooks, Jr. Computer Science Bldg + * Chapel Hill, NC 27599-3175 + * USA + * + * + */ + +#ifndef _IO_SRC_GL_DEFINES_H_ +#define _IO_SRC_GL_DEFINES_H_ + +#ifdef OPENGL_FOUND +# ifdef __APPLE__ +# include +# else +# include +# endif +#endif + +#ifndef GL_VERSION_1_1 + +#define GL_BYTE 0x1400 +#define GL_UNSIGNED_BYTE 0x1401 +#define GL_SHORT 0x1402 +#define GL_UNSIGNED_SHORT 0x1403 +#define GL_INT 0x1404 +#define GL_UNSIGNED_INT 0x1405 +#define GL_FLOAT 0x1406 +#define GL_DOUBLE 0x140A +#define GL_RGBA8 0x8058 + +#endif // GL_VERSION_1_1 + +#ifndef GL_VERTSION_4_2 + +#define GL_COMPRESSED_RGBA_BPTC_UNORM 0x8E8C + +#endif // GL_VERTSION_4_2 + +#endif // _IO_SRC_GL_DEFINES_H_ From 917c4dc9dd89eb578c8029da054fb8105602b4fd Mon Sep 17 00:00:00 2001 From: Pavel Krajcevski Date: Thu, 23 Jan 2014 14:38:02 -0500 Subject: [PATCH 04/15] Add a scoped allocator in order to deal with errors cleaner --- Base/CMakeLists.txt | 1 + Base/include/ScopedAllocator.h | 94 ++++++++++++++++++++++++++++++++++ 2 files changed, 95 insertions(+) create mode 100644 Base/include/ScopedAllocator.h diff --git a/Base/CMakeLists.txt b/Base/CMakeLists.txt index bee31e9..69ea8d3 100644 --- a/Base/CMakeLists.txt +++ b/Base/CMakeLists.txt @@ -64,6 +64,7 @@ SET( HEADERS "include/CompressionJob.h" "include/Pixel.h" "include/IPixel.h" + "include/ScopedAllocator.h" "include/VectorBase.h" "include/Vector2.h" "include/Vector3.h" diff --git a/Base/include/ScopedAllocator.h b/Base/include/ScopedAllocator.h new file mode 100644 index 0000000..1696b02 --- /dev/null +++ b/Base/include/ScopedAllocator.h @@ -0,0 +1,94 @@ +/* FasTC + * Copyright (c) 2014 University of North Carolina at Chapel Hill. + * All rights reserved. + * + * Permission to use, copy, modify, and distribute this software and its + * documentation for educational, research, and non-profit purposes, without + * fee, and without a written agreement is hereby granted, provided that the + * above copyright notice, this paragraph, and the following four paragraphs + * appear in all copies. + * + * Permission to incorporate this software into commercial products may be + * obtained by contacting the authors or the Office of Technology Development + * at the University of North Carolina at Chapel Hill . + * + * This software program and documentation are copyrighted by the University of + * North Carolina at Chapel Hill. The software program and documentation are + * supplied "as is," without any accompanying services from the University of + * North Carolina at Chapel Hill or the authors. The University of North + * Carolina at Chapel Hill and the authors do not warrant that the operation of + * the program will be uninterrupted or error-free. The end-user understands + * that the program was developed for research purposes and is advised not to + * rely exclusively on the program for any reason. + * + * IN NO EVENT SHALL THE UNIVERSITY OF NORTH CAROLINA AT CHAPEL HILL OR THE + * AUTHORS BE LIABLE TO ANY PARTY FOR DIRECT, INDIRECT, SPECIAL, INCIDENTAL, + * OR CONSEQUENTIAL DAMAGES, INCLUDING LOST PROFITS, ARISING OUT OF THE USE OF + * THIS SOFTWARE AND ITS DOCUMENTATION, EVEN IF THE UNIVERSITY OF NORTH CAROLINA + * AT CHAPEL HILL OR THE AUTHORS HAVE BEEN ADVISED OF THE POSSIBILITY OF SUCH + * DAMAGE. + * + * THE UNIVERSITY OF NORTH CAROLINA AT CHAPEL HILL AND THE AUTHORS SPECIFICALLY + * DISCLAIM ANY WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED + * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE AND ANY + * STATUTORY WARRANTY OF NON-INFRINGEMENT. THE SOFTWARE PROVIDED HEREUNDER IS ON + * AN "AS IS" BASIS, AND THE UNIVERSITY OF NORTH CAROLINA AT CHAPEL HILL AND + * THE AUTHORS HAVE NO OBLIGATIONS TO PROVIDE MAINTENANCE, SUPPORT, UPDATES, + * ENHANCEMENTS, OR MODIFICATIONS. + * + * Please send all BUG REPORTS to . + * + * The authors may be contacted via: + * + * Pavel Krajcevski + * Dept of Computer Science + * 201 S Columbia St + * Frederick P. Brooks, Jr. Computer Science Bldg + * Chapel Hill, NC 27599-3175 + * USA + * + * + */ + +#ifndef BASE_INCLUDE_SCOPEDALLOCATOR_H_ +#define BASE_INCLUDE_SCOPEDALLOCATOR_H_ + +#include "TexCompTypes.h" + +namespace FasTC { + + template + class ScopedAllocator { + private: + T *m_Ptr; + ScopedAllocator() : m_Ptr(NULL) { } + public: + static ScopedAllocator Create(uint32 nBytes) { + ScopedAllocator actr; + actr.m_Ptr = new T[nBytes]; + return actr; + } + + ~ScopedAllocator() { + if(m_Ptr) { + delete m_Ptr; + m_Ptr = NULL; + } + } + + T &operator[](uint32 idx) { + return m_Ptr[idx]; + } + + operator T *() { + return m_Ptr; + } + + operator bool() { + return m_Ptr != NULL; + } + }; + +} // namespace FasTC + +#endif // BASE_INCLUDE_SCOPEDALLOCATOR_H_ From 64747eb8281f6a0b0a803224be37a51cffb3c80d Mon Sep 17 00:00:00 2001 From: Pavel Krajcevski Date: Thu, 23 Jan 2014 14:42:28 -0500 Subject: [PATCH 05/15] Constify --- IO/config/ImageLoader.h.in | 2 +- IO/src/ImageLoader.cpp | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/IO/config/ImageLoader.h.in b/IO/config/ImageLoader.h.in index 3d9e363..b65d23b 100644 --- a/IO/config/ImageLoader.h.in +++ b/IO/config/ImageLoader.h.in @@ -94,7 +94,7 @@ class ImageLoader { uint32 GetChannelForPixel(uint32 x, uint32 y, uint32 ch); - bool LoadFromPixelBuffer(uint32 *data, bool flipY = false); + bool LoadFromPixelBuffer(const uint32 *data, bool flipY = false); public: virtual ~ImageLoader() { diff --git a/IO/src/ImageLoader.cpp b/IO/src/ImageLoader.cpp index 37df083..b65bb94 100644 --- a/IO/src/ImageLoader.cpp +++ b/IO/src/ImageLoader.cpp @@ -137,7 +137,7 @@ unsigned int ImageLoader::GetChannelForPixel(uint32 x, uint32 y, uint32 ch) { return val; } -bool ImageLoader::LoadFromPixelBuffer(uint32 *data, bool flipY) { +bool ImageLoader::LoadFromPixelBuffer(const uint32 *data, bool flipY) { m_RedChannelPrecision = 8; m_GreenChannelPrecision = 8; m_BlueChannelPrecision = 8; From d0ff86155165d3576b79946c1e9a54b98071e5d5 Mon Sep 17 00:00:00 2001 From: Pavel Krajcevski Date: Thu, 23 Jan 2014 14:42:54 -0500 Subject: [PATCH 06/15] Alphabetize --- Base/CMakeLists.txt | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/Base/CMakeLists.txt b/Base/CMakeLists.txt index 69ea8d3..15d1044 100644 --- a/Base/CMakeLists.txt +++ b/Base/CMakeLists.txt @@ -58,20 +58,20 @@ SET( SOURCES ) SET( HEADERS - "include/TexCompTypes.h" - "include/Image.h" "include/Color.h" "include/CompressionJob.h" - "include/Pixel.h" "include/IPixel.h" + "include/Image.h" + "include/MatrixBase.h" + "include/MatrixSquare.h" + "include/Matrix3x3.h" + "include/Pixel.h" "include/ScopedAllocator.h" + "include/TexCompTypes.h" "include/VectorBase.h" "include/Vector2.h" "include/Vector3.h" "include/Vector4.h" - "include/MatrixBase.h" - "include/MatrixSquare.h" - "include/Matrix3x3.h" ) INCLUDE_DIRECTORIES(${FasTC_SOURCE_DIR}/Base/include) From 95e86cbf0dfad2a37f5d8523d6cf755cde579030 Mon Sep 17 00:00:00 2001 From: Pavel Krajcevski Date: Thu, 23 Jan 2014 14:43:05 -0500 Subject: [PATCH 07/15] Add KTX loaders --- IO/CMakeLists.txt | 4 + IO/src/ImageLoaderKTX.cpp | 274 ++++++++++++++++++++++++++++++++++++++ IO/src/ImageLoaderKTX.h | 75 +++++++++++ 3 files changed, 353 insertions(+) create mode 100644 IO/src/ImageLoaderKTX.cpp create mode 100644 IO/src/ImageLoaderKTX.h diff --git a/IO/CMakeLists.txt b/IO/CMakeLists.txt index 72491a5..414a8dc 100644 --- a/IO/CMakeLists.txt +++ b/IO/CMakeLists.txt @@ -87,6 +87,10 @@ INCLUDE_DIRECTORIES( ${FasTC_SOURCE_DIR}/IO/third_party/tga ) SET( SOURCES ${SOURCES} "src/ImageLoaderTGA.cpp" ) SET( HEADERS ${HEADERS} "src/ImageLoaderTGA.h" ) +# Add KTX loaders +SET( SOURCES ${SOURCES} "src/ImageLoaderKTX.cpp" ) +SET( HEADERS ${HEADERS} "src/ImageLoaderKTX.h" ) + FIND_PACKAGE( OpenGL ) IF(OPENGL_FOUND) INCLUDE_DIRECTORIES( ${OPENGL_INCLUDE_DIRS} ) diff --git a/IO/src/ImageLoaderKTX.cpp b/IO/src/ImageLoaderKTX.cpp new file mode 100644 index 0000000..55de436 --- /dev/null +++ b/IO/src/ImageLoaderKTX.cpp @@ -0,0 +1,274 @@ +/* FasTC + * Copyright (c) 2014 University of North Carolina at Chapel Hill. + * All rights reserved. + * + * Permission to use, copy, modify, and distribute this software and its + * documentation for educational, research, and non-profit purposes, without + * fee, and without a written agreement is hereby granted, provided that the + * above copyright notice, this paragraph, and the following four paragraphs + * appear in all copies. + * + * Permission to incorporate this software into commercial products may be + * obtained by contacting the authors or the Office of Technology Development + * at the University of North Carolina at Chapel Hill . + * + * This software program and documentation are copyrighted by the University of + * North Carolina at Chapel Hill. The software program and documentation are + * supplied "as is," without any accompanying services from the University of + * North Carolina at Chapel Hill or the authors. The University of North + * Carolina at Chapel Hill and the authors do not warrant that the operation of + * the program will be uninterrupted or error-free. The end-user understands + * that the program was developed for research purposes and is advised not to + * rely exclusively on the program for any reason. + * + * IN NO EVENT SHALL THE UNIVERSITY OF NORTH CAROLINA AT CHAPEL HILL OR THE + * AUTHORS BE LIABLE TO ANY PARTY FOR DIRECT, INDIRECT, SPECIAL, INCIDENTAL, + * OR CONSEQUENTIAL DAMAGES, INCLUDING LOST PROFITS, ARISING OUT OF THE USE OF + * THIS SOFTWARE AND ITS DOCUMENTATION, EVEN IF THE UNIVERSITY OF NORTH CAROLINA + * AT CHAPEL HILL OR THE AUTHORS HAVE BEEN ADVISED OF THE POSSIBILITY OF SUCH + * DAMAGE. + * + * THE UNIVERSITY OF NORTH CAROLINA AT CHAPEL HILL AND THE AUTHORS SPECIFICALLY + * DISCLAIM ANY WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED + * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE AND ANY + * STATUTORY WARRANTY OF NON-INFRINGEMENT. THE SOFTWARE PROVIDED HEREUNDER IS ON + * AN "AS IS" BASIS, AND THE UNIVERSITY OF NORTH CAROLINA AT CHAPEL HILL AND + * THE AUTHORS HAVE NO OBLIGATIONS TO PROVIDE MAINTENANCE, SUPPORT, UPDATES, + * ENHANCEMENTS, OR MODIFICATIONS. + * + * Please send all BUG REPORTS to . + * + * The authors may be contacted via: + * + * Pavel Krajcevski + * Dept of Computer Science + * 201 S Columbia St + * Frederick P. Brooks, Jr. Computer Science Bldg + * Chapel Hill, NC 27599-3175 + * USA + * + * + */ + +#include "ImageLoaderKTX.h" + +#include +#include +#include +#include +#include + +#include "TexCompTypes.h" +#include "ScopedAllocator.h" + +#include "GLDefines.h" + +class ByteReader { + private: + const uint8 *m_Data; + uint32 m_BytesLeft; + public: + ByteReader(const uint8 *data, uint32 bytesExpected) + : m_Data(data), m_BytesLeft(bytesExpected) + { } + + bool Advance(uint32 nBytes) { + if(nBytes < m_BytesLeft) { + assert(!"Cannot read any more, unexpected bytes!"); + return false; + } + + m_Data += nBytes; + m_BytesLeft -= nBytes; + return true; + } + + operator const uint8 *() { + return m_Data; + } + + const uint8 *GetData() const { return m_Data; } + uint32 GetBytesLeft() const { return m_BytesLeft; } +}; + +class IntLoader { + public: + virtual uint32 ReadInt(const uint8 *data) const = 0; + bool LoadInt(ByteReader &data, uint32 &result) const { + result = ReadInt(data); + data.Advance(4); + return true; + } +}; + +class BigEndianIntLoader : public IntLoader { + public: + virtual uint32 ReadInt(const uint8 *data) const { + uint32 ret = 0; + ret |= data[0]; + for(uint32 i = 1; i < 4; i++) { + ret <<= 8; + ret |= data[i]; + } + return ret; + } +}; +static const BigEndianIntLoader gBEldr; + +class LittleEndianIntLoader : public IntLoader { + public: + virtual uint32 ReadInt(const uint8 *data) const { + uint32 ret = 0; + ret |= data[3]; + for(uint32 i = 3; i >= 0; i--) { + ret <<= 8; + ret |= data[i]; + } + return ret; + } +}; +static const LittleEndianIntLoader gLEldr; + +ImageLoaderKTX::ImageLoaderKTX(const uint8 *rawData, const int32 rawDataSz) + : ImageLoader(rawData, rawDataSz), m_Processor(NULL) +{ } + +ImageLoaderKTX::~ImageLoaderKTX() { } + +bool ImageLoaderKTX::ReadData() { + + ByteReader rdr (m_RawData, m_NumRawDataBytes); + + // First, check to make sure that the identifier is present... + static const uint8 kKTXID[12] = { + 0xAB, 0x4B, 0x54, 0x58, 0x20, 0x31, 0x31, 0xBB, 0x0D, 0x0A, 0x1A, 0x0A + }; + + if(memcmp(rdr.GetData(), kKTXID, 12) == 0) { + rdr.Advance(12); + } else { + return false; + } + + const IntLoader *ldr = NULL; + if(rdr.GetData()[0] == 0x04) { + ldr = &gBEldr; + } else { + ldr = &gLEldr; + } + rdr.Advance(4); + + #define LOAD(x) uint32 x; do { if(!ldr->LoadInt(rdr, x)) { return false; } } while(0) + LOAD(glType); + LOAD(glTypeSize); + LOAD(glFormat); + LOAD(glInternalFormat); + LOAD(glBaseInternalFormat); + LOAD(pixelWidth); + LOAD(pixelHeight); + LOAD(pixelDepth); + LOAD(numberOfArrayElements); + LOAD(numberOfFaces); + LOAD(numberOfMipmapLevels); + LOAD(bytesOfKeyValueData); + + // Do we need to read the data? + if(m_Processor) { + const uint8 *imgData = rdr.GetData() + bytesOfKeyValueData; + while(rdr.GetData() < imgData) { + LOAD(keyAndValueByteSize); + FasTC::ScopedAllocator keyValueData = + FasTC::ScopedAllocator::Create(keyAndValueByteSize); + if(!keyValueData) { + fprintf(stderr, "KTX loader - out of memory.\n"); + return false; + } + + // Read the bytes... + memcpy(keyValueData, rdr.GetData(), keyAndValueByteSize); + const char *key = reinterpret_cast((const uint8 *)keyValueData); + const char *value = key; + while(value != '\0') { + value++; + } + value++; // consume the null byte + + m_Processor(key, value); + rdr.Advance((keyAndValueByteSize + 3) & ~0x3); + } + } else { + rdr.Advance(bytesOfKeyValueData); + } + + // The following code only supports a limited subset of + // image types, the full spec (if we choose to support it) + // is here: + // http://www.khronos.org/opengles/sdk/tools/KTX/file_format_spec + + // Read image data... + if(numberOfMipmapLevels != 1) { + fprintf(stderr, "KTX loader - unsupported mipmap levels: %d\n", numberOfMipmapLevels); + return false; + } + + LOAD(imageSize); + + if(numberOfArrayElements > 1) { + fprintf(stderr, + "KTX loader - unsupported number of array elements: %d\n", + numberOfArrayElements); + return false; + } + + if(numberOfFaces != 1) { + fprintf(stderr, + "KTX loader - unsupported number of faces: %d\n" + "This likely means that we are trying to load a cube map.\n", + numberOfFaces); + return false; + } + + if(pixelDepth != 0) { + fprintf(stderr, "KTX loader - 3D textures not supported\n"); + return false; + } + + if(pixelHeight == 0) { + fprintf(stderr, "KTX loader - 1D textures not supported\n"); + return false; + } + + if(pixelWidth == 0) { + fprintf(stderr, "KTX loader - nonzero pixel width??\n"); + return false; + } + + if(glType == 0 && + glFormat == 0 && + glInternalFormat == GL_COMPRESSED_RGBA_BPTC_UNORM) { + fprintf(stderr, "KTX loader - BPTC compressed textures unsupported!\n"); + return false; + // Load compressed texture... + // rdr.Advance(pixelWidth * pixelHeight); + } else { + + if(glType != GL_BYTE) { + fprintf(stderr, "KTX loader - unsupported OpenGL type: 0x%x\n", glType); + return false; + } + + if(glInternalFormat != GL_RGBA8) { + fprintf(stderr, "KTX loader - unsupported internal format: 0x%x\n", glFormat); + return false; + } + + // We should have RGBA8 data here so we can simply load it + // as we normally would. + m_Width = pixelWidth; + m_Height = pixelHeight; + LoadFromPixelBuffer(reinterpret_cast(rdr.GetData())); + rdr.Advance(pixelWidth * pixelHeight * 4); + } + return rdr.GetBytesLeft() == 0; +} + diff --git a/IO/src/ImageLoaderKTX.h b/IO/src/ImageLoaderKTX.h new file mode 100644 index 0000000..42df221 --- /dev/null +++ b/IO/src/ImageLoaderKTX.h @@ -0,0 +1,75 @@ +/* FasTC + * Copyright (c) 2014 University of North Carolina at Chapel Hill. + * All rights reserved. + * + * Permission to use, copy, modify, and distribute this software and its + * documentation for educational, research, and non-profit purposes, without + * fee, and without a written agreement is hereby granted, provided that the + * above copyright notice, this paragraph, and the following four paragraphs + * appear in all copies. + * + * Permission to incorporate this software into commercial products may be + * obtained by contacting the authors or the Office of Technology Development + * at the University of North Carolina at Chapel Hill . + * + * This software program and documentation are copyrighted by the University of + * North Carolina at Chapel Hill. The software program and documentation are + * supplied "as is," without any accompanying services from the University of + * North Carolina at Chapel Hill or the authors. The University of North + * Carolina at Chapel Hill and the authors do not warrant that the operation of + * the program will be uninterrupted or error-free. The end-user understands + * that the program was developed for research purposes and is advised not to + * rely exclusively on the program for any reason. + * + * IN NO EVENT SHALL THE UNIVERSITY OF NORTH CAROLINA AT CHAPEL HILL OR THE + * AUTHORS BE LIABLE TO ANY PARTY FOR DIRECT, INDIRECT, SPECIAL, INCIDENTAL, + * OR CONSEQUENTIAL DAMAGES, INCLUDING LOST PROFITS, ARISING OUT OF THE USE OF + * THIS SOFTWARE AND ITS DOCUMENTATION, EVEN IF THE UNIVERSITY OF NORTH CAROLINA + * AT CHAPEL HILL OR THE AUTHORS HAVE BEEN ADVISED OF THE POSSIBILITY OF SUCH + * DAMAGE. + * + * THE UNIVERSITY OF NORTH CAROLINA AT CHAPEL HILL AND THE AUTHORS SPECIFICALLY + * DISCLAIM ANY WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED + * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE AND ANY + * STATUTORY WARRANTY OF NON-INFRINGEMENT. THE SOFTWARE PROVIDED HEREUNDER IS ON + * AN "AS IS" BASIS, AND THE UNIVERSITY OF NORTH CAROLINA AT CHAPEL HILL AND + * THE AUTHORS HAVE NO OBLIGATIONS TO PROVIDE MAINTENANCE, SUPPORT, UPDATES, + * ENHANCEMENTS, OR MODIFICATIONS. + * + * Please send all BUG REPORTS to . + * + * The authors may be contacted via: + * + * Pavel Krajcevski + * Dept of Computer Science + * 201 S Columbia St + * Frederick P. Brooks, Jr. Computer Science Bldg + * Chapel Hill, NC 27599-3175 + * USA + * + * + */ + +#ifndef _IO_SRC_IMAGE_LOADER_KTX_H_ +#define _IO_SRC_IMAGE_LOADER_KTX_H_ + +#include "ImageLoader.h" + +class ImageLoaderKTX : public ImageLoader { + public: + typedef void (*KTXKeyValueProcessor)(const char *key, const char *value); + + ImageLoaderKTX(const uint8 *rawData, const int32 rawDataSz); + virtual ~ImageLoaderKTX(); + + virtual bool ReadData(); + + void SetProcessor(KTXKeyValueProcessor proc) { + m_Processor = proc; + } + + private: + KTXKeyValueProcessor m_Processor; +}; + +#endif // _IO_SRC_IMAGE_LOADER_KTX_H_ From 553dc44ca5d063321116370083c1a048a1f42f4a Mon Sep 17 00:00:00 2001 From: Pavel Krajcevski Date: Thu, 23 Jan 2014 18:23:55 -0500 Subject: [PATCH 08/15] Allow access to the compressed data if the user promises not to change it. --- Core/include/CompressedImage.h | 2 ++ 1 file changed, 2 insertions(+) diff --git a/Core/include/CompressedImage.h b/Core/include/CompressedImage.h index 4c10cc2..71f8fbf 100644 --- a/Core/include/CompressedImage.h +++ b/Core/include/CompressedImage.h @@ -94,6 +94,8 @@ class CompressedImage : public FasTC::Image { // size for a given compressed image. bool DecompressImage(uint8 *outBuf, uint32 outBufSz) const; + const uint8 *GetCompressedData() const { return m_CompressedData; } + FasTC::ECompressionFormat GetFormat() const { return m_Format; } }; From 552b8440b17dbc754f3fe854a6e157d3bc13cf84 Mon Sep 17 00:00:00 2001 From: Pavel Krajcevski Date: Thu, 23 Jan 2014 18:24:11 -0500 Subject: [PATCH 09/15] Add KTX writer. --- IO/CMakeLists.txt | 2 + IO/src/ImageWriterKTX.cpp | 148 ++++++++++++++++++++++++++++++++++++++ IO/src/ImageWriterKTX.h | 71 ++++++++++++++++++ 3 files changed, 221 insertions(+) create mode 100644 IO/src/ImageWriterKTX.cpp create mode 100644 IO/src/ImageWriterKTX.h diff --git a/IO/CMakeLists.txt b/IO/CMakeLists.txt index 414a8dc..49bc4de 100644 --- a/IO/CMakeLists.txt +++ b/IO/CMakeLists.txt @@ -90,6 +90,8 @@ SET( HEADERS ${HEADERS} "src/ImageLoaderTGA.h" ) # Add KTX loaders SET( SOURCES ${SOURCES} "src/ImageLoaderKTX.cpp" ) SET( HEADERS ${HEADERS} "src/ImageLoaderKTX.h" ) +SET( SOURCES ${SOURCES} "src/ImageWriterKTX.cpp" ) +SET( HEADERS ${HEADERS} "src/ImageWriterKTX.h" ) FIND_PACKAGE( OpenGL ) IF(OPENGL_FOUND) diff --git a/IO/src/ImageWriterKTX.cpp b/IO/src/ImageWriterKTX.cpp new file mode 100644 index 0000000..1a6a371 --- /dev/null +++ b/IO/src/ImageWriterKTX.cpp @@ -0,0 +1,148 @@ +/* FasTC + * Copyright (c) 2014 University of North Carolina at Chapel Hill. + * All rights reserved. + * + * Permission to use, copy, modify, and distribute this software and its + * documentation for educational, research, and non-profit purposes, without + * fee, and without a written agreement is hereby granted, provided that the + * above copyright notice, this paragraph, and the following four paragraphs + * appear in all copies. + * + * Permission to incorporate this software into commercial products may be + * obtained by contacting the authors or the Office of Technology Development + * at the University of North Carolina at Chapel Hill . + * + * This software program and documentation are copyrighted by the University of + * North Carolina at Chapel Hill. The software program and documentation are + * supplied "as is," without any accompanying services from the University of + * North Carolina at Chapel Hill or the authors. The University of North + * Carolina at Chapel Hill and the authors do not warrant that the operation of + * the program will be uninterrupted or error-free. The end-user understands + * that the program was developed for research purposes and is advised not to + * rely exclusively on the program for any reason. + * + * IN NO EVENT SHALL THE UNIVERSITY OF NORTH CAROLINA AT CHAPEL HILL OR THE + * AUTHORS BE LIABLE TO ANY PARTY FOR DIRECT, INDIRECT, SPECIAL, INCIDENTAL, + * OR CONSEQUENTIAL DAMAGES, INCLUDING LOST PROFITS, ARISING OUT OF THE USE OF + * THIS SOFTWARE AND ITS DOCUMENTATION, EVEN IF THE UNIVERSITY OF NORTH CAROLINA + * AT CHAPEL HILL OR THE AUTHORS HAVE BEEN ADVISED OF THE POSSIBILITY OF SUCH + * DAMAGE. + * + * THE UNIVERSITY OF NORTH CAROLINA AT CHAPEL HILL AND THE AUTHORS SPECIFICALLY + * DISCLAIM ANY WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED + * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE AND ANY + * STATUTORY WARRANTY OF NON-INFRINGEMENT. THE SOFTWARE PROVIDED HEREUNDER IS ON + * AN "AS IS" BASIS, AND THE UNIVERSITY OF NORTH CAROLINA AT CHAPEL HILL AND + * THE AUTHORS HAVE NO OBLIGATIONS TO PROVIDE MAINTENANCE, SUPPORT, UPDATES, + * ENHANCEMENTS, OR MODIFICATIONS. + * + * Please send all BUG REPORTS to . + * + * The authors may be contacted via: + * + * Pavel Krajcevski + * Dept of Computer Science + * 201 S Columbia St + * Frederick P. Brooks, Jr. Computer Science Bldg + * Chapel Hill, NC 27599-3175 + * USA + * + * + */ + +#include "ImageWriterKTX.h" + +#include +#include +#include + +#include "Image.h" +#include "Pixel.h" + +#include "CompressedImage.h" +#include "GLDefines.h" + +ImageWriterKTX::ImageWriterKTX(FasTC::Image<> &im) + : ImageWriter(im.GetWidth(), im.GetHeight(), NULL) + , m_Image(im) +{ } + +class ByteWriter { + private: + uint8 *m_Head; + uint32 m_BytesWritten; + public: + ByteWriter(uint8 *dst) : m_Head(dst), m_BytesWritten(0) { } + + uint32 GetBytesWritten() const { return m_BytesWritten; } + + void Write(const uint32 v) { + memcpy(m_Head, &v, 4); + m_Head += 4; + m_BytesWritten += 4; + } + + void Write(const void *src, const uint32 nBytes) { + memcpy(m_Head, src, nBytes); + m_Head += nBytes; + m_BytesWritten += nBytes; + } +}; + +bool ImageWriterKTX::WriteImage() { + ByteWriter wtr (m_RawFileData); + + const uint8 kIdentifier[12] = { + 0xAB, 0x4B, 0x54, 0x58, 0x20, 0x31, 0x31, 0xBB, 0x0D, 0x0A, 0x1A, 0x0A + }; + wtr.Write(kIdentifier, 12); + wtr.Write(0x04030201); + + const char *orientationKey = "KTXorientation"; + const char *orientationValue = "S=r,T=u"; + const uint32 kvSz = + strlen(orientationKey) + 1 // key + + strlen(orientationValue) + 1; // value + uint32 tkvSz = kvSz + 4; // total kv size + tkvSz = (tkvSz + 3) & ~0x3; // 4-byte aligned + + CompressedImage *ci = dynamic_cast(&m_Image); + if(ci && ci->GetFormat() == FasTC::eCompressionFormat_BPTC) { + wtr.Write(0); // glType + wtr.Write(1); // glTypeSize + wtr.Write(GL_RGBA); // glFormat + wtr.Write(GL_COMPRESSED_RGBA_BPTC_UNORM); // glInternalFormat + wtr.Write(GL_RGBA); // glBaseFormat + } else { + wtr.Write(GL_BYTE); // glType + wtr.Write(1); // glTypeSize + wtr.Write(GL_RGBA); // glFormat + wtr.Write(GL_RGBA8); // glInternalFormat + wtr.Write(GL_RGBA); // glBaseFormat + } + + wtr.Write(m_Width); // pixelWidth + wtr.Write(m_Height); // pixelHeight + wtr.Write(0); // pixelDepth + wtr.Write(0); // numberOfArrayElements + wtr.Write(1); // numberOfFaces + wtr.Write(1); // numberOfMipmapLevels + wtr.Write(tkvSz); // total key value size + wtr.Write(kvSz); // key value size + wtr.Write(orientationKey, strlen(orientationKey) + 1); // key + wtr.Write(orientationValue, strlen(orientationValue) + 1); // value + wtr.Write(orientationKey, tkvSz - kvSz); // padding + + if(ci && ci->GetFormat() == FasTC::eCompressionFormat_BPTC) { + static const uint32 kImageSize = m_Width * m_Height; + wtr.Write(kImageSize); // imageSize + wtr.Write(ci->GetCompressedData(), kImageSize); // imagedata... + } else { + static const uint32 kImageSize = m_Width * m_Height * 4; + wtr.Write(kImageSize); // imageSize + wtr.Write(m_Image.GetPixels(), kImageSize); // imagedata... + } + + m_RawFileDataSz = wtr.GetBytesWritten(); + return true; +} diff --git a/IO/src/ImageWriterKTX.h b/IO/src/ImageWriterKTX.h new file mode 100644 index 0000000..2bc3d37 --- /dev/null +++ b/IO/src/ImageWriterKTX.h @@ -0,0 +1,71 @@ +/* FasTC + * Copyright (c) 2014 University of North Carolina at Chapel Hill. + * All rights reserved. + * + * Permission to use, copy, modify, and distribute this software and its + * documentation for educational, research, and non-profit purposes, without + * fee, and without a written agreement is hereby granted, provided that the + * above copyright notice, this paragraph, and the following four paragraphs + * appear in all copies. + * + * Permission to incorporate this software into commercial products may be + * obtained by contacting the authors or the Office of Technology Development + * at the University of North Carolina at Chapel Hill . + * + * This software program and documentation are copyrighted by the University of + * North Carolina at Chapel Hill. The software program and documentation are + * supplied "as is," without any accompanying services from the University of + * North Carolina at Chapel Hill or the authors. The University of North + * Carolina at Chapel Hill and the authors do not warrant that the operation of + * the program will be uninterrupted or error-free. The end-user understands + * that the program was developed for research purposes and is advised not to + * rely exclusively on the program for any reason. + * + * IN NO EVENT SHALL THE UNIVERSITY OF NORTH CAROLINA AT CHAPEL HILL OR THE + * AUTHORS BE LIABLE TO ANY PARTY FOR DIRECT, INDIRECT, SPECIAL, INCIDENTAL, + * OR CONSEQUENTIAL DAMAGES, INCLUDING LOST PROFITS, ARISING OUT OF THE USE OF + * THIS SOFTWARE AND ITS DOCUMENTATION, EVEN IF THE UNIVERSITY OF NORTH CAROLINA + * AT CHAPEL HILL OR THE AUTHORS HAVE BEEN ADVISED OF THE POSSIBILITY OF SUCH + * DAMAGE. + * + * THE UNIVERSITY OF NORTH CAROLINA AT CHAPEL HILL AND THE AUTHORS SPECIFICALLY + * DISCLAIM ANY WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED + * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE AND ANY + * STATUTORY WARRANTY OF NON-INFRINGEMENT. THE SOFTWARE PROVIDED HEREUNDER IS ON + * AN "AS IS" BASIS, AND THE UNIVERSITY OF NORTH CAROLINA AT CHAPEL HILL AND + * THE AUTHORS HAVE NO OBLIGATIONS TO PROVIDE MAINTENANCE, SUPPORT, UPDATES, + * ENHANCEMENTS, OR MODIFICATIONS. + * + * Please send all BUG REPORTS to . + * + * The authors may be contacted via: + * + * Pavel Krajcevski + * Dept of Computer Science + * 201 S Columbia St + * Frederick P. Brooks, Jr. Computer Science Bldg + * Chapel Hill, NC 27599-3175 + * USA + * + * + */ + +#ifndef _IMAGE_WRITER_KTX_H_ +#define _IMAGE_WRITER_KTX_H_ + +#include "ImageWriter.h" +#include "ImageFwd.h" + +// Forward Declare +class ImageWriterKTX : public ImageWriter { + public: + ImageWriterKTX(FasTC::Image<> &); + virtual ~ImageWriterKTX() { } + + virtual bool WriteImage(); + + private: + FasTC::Image<> &m_Image; +}; + +#endif // _IMAGE_LOADER_H_ From 1b5b8c39006adb7ba2d8e6bd1e22b60922dee4be Mon Sep 17 00:00:00 2001 From: Pavel Krajcevski Date: Fri, 24 Jan 2014 14:00:14 -0500 Subject: [PATCH 10/15] Add hooks to support filenames with .ktx extension --- CLTool/src/tc.cpp | 5 +++-- IO/CMakeLists.txt | 1 + IO/include/ImageFile.h | 2 +- IO/include/ImageFileFormat.h | 1 + IO/src/ImageFile.cpp | 14 ++++++++++++++ PVRTCEncoder/CMakeLists.txt | 1 - 6 files changed, 20 insertions(+), 4 deletions(-) diff --git a/CLTool/src/tc.cpp b/CLTool/src/tc.cpp index fb02d98..e79e66d 100644 --- a/CLTool/src/tc.cpp +++ b/CLTool/src/tc.cpp @@ -77,7 +77,7 @@ void PrintUsage() { fprintf(stderr, "\t-v\t\tVerbose mode: prints out Entropy, Mean Local Entropy, and MSSIM\n"); fprintf(stderr, "\t-f \tFormat to use. Either \"BPTC\", \"ETC1\", \"DXT1\", \"DXT5\", or \"PVRTC\". Default: BPTC\n"); fprintf(stderr, "\t-l\t\tSave an output log.\n"); - fprintf(stderr, "\t-d \tSpecify decompressed output (currently only png files supported, default: basename-.png)\n"); + fprintf(stderr, "\t-d \tSpecify decompressed output (default: basename-.png)\n"); fprintf(stderr, "\t-nd\t\tSuppress decompressed output\n"); fprintf(stderr, "\t-q \tSet compression quality level. Default: 50\n"); fprintf(stderr, "\t-n \tCompress the image num times and give the average time and PSNR. Default: 1\n"); @@ -350,7 +350,8 @@ int main(int argc, char **argv) { strcat(basename, "-etc1.png"); } - ImageFile cImgFile (basename, eFileFormat_PNG, *ci); + EImageFileFormat fmt = ImageFile::DetectFileFormat(basename); + ImageFile cImgFile (basename, fmt, *ci); cImgFile.Write(); } diff --git a/IO/CMakeLists.txt b/IO/CMakeLists.txt index 49bc4de..dc90d3c 100644 --- a/IO/CMakeLists.txt +++ b/IO/CMakeLists.txt @@ -119,6 +119,7 @@ ADD_LIBRARY(FasTCIO ) TARGET_LINK_LIBRARIES( FasTCIO FasTCBase ) +TARGET_LINK_LIBRARIES( FasTCIO FasTCCore ) IF( PNG_FOUND ) TARGET_LINK_LIBRARIES( FasTCIO ${PNG_LIBRARY} ) diff --git a/IO/include/ImageFile.h b/IO/include/ImageFile.h index 5c222f8..2b7e01c 100644 --- a/IO/include/ImageFile.h +++ b/IO/include/ImageFile.h @@ -70,6 +70,7 @@ public: ~ImageFile(); + static EImageFileFormat DetectFileFormat(const CHAR *filename); unsigned int GetWidth() const { return m_Width; } unsigned int GetHeight() const { return m_Height; } FasTC::Image<> *GetImage() const { return m_Image; } @@ -98,7 +99,6 @@ public: bool ReadFileData(const CHAR *filename); static bool WriteImageDataToFile(const uint8 *data, const uint32 dataSz, const CHAR *filename); - static EImageFileFormat DetectFileFormat(const CHAR *filename); FasTC::Image<> *LoadImage() const; }; diff --git a/IO/include/ImageFileFormat.h b/IO/include/ImageFileFormat.h index 6035a81..fc4557e 100644 --- a/IO/include/ImageFileFormat.h +++ b/IO/include/ImageFileFormat.h @@ -48,6 +48,7 @@ enum EImageFileFormat { eFileFormat_PNG, eFileFormat_PVR, eFileFormat_TGA, + eFileFormat_KTX, kNumImageFileFormats }; diff --git a/IO/src/ImageFile.cpp b/IO/src/ImageFile.cpp index 5199cba..e4d767f 100644 --- a/IO/src/ImageFile.cpp +++ b/IO/src/ImageFile.cpp @@ -67,6 +67,9 @@ #include "ImageLoaderTGA.h" +#include "ImageLoaderKTX.h" +#include "ImageWriterKTX.h" + ////////////////////////////////////////////////////////////////////////////////////////// // // Static helper functions @@ -162,6 +165,10 @@ bool ImageFile::Write() { break; #endif // PNG_FOUND + case eFileFormat_KTX: + writer = new ImageWriterKTX(*m_Image); + break; + default: fprintf(stderr, "Unable to write image: unknown file format.\n"); return false; @@ -202,6 +209,10 @@ FasTC::Image<> *ImageFile::LoadImage() const { loader = new ImageLoaderTGA(m_FileData, m_FileDataSz); break; + case eFileFormat_KTX: + loader = new ImageLoaderKTX(m_FileData, m_FileDataSz); + break; + default: fprintf(stderr, "Unable to load image: unknown file format.\n"); return NULL; @@ -265,6 +276,9 @@ EImageFileFormat ImageFile::DetectFileFormat(const CHAR *filename) { else if(strcmp(ext, ".tga") == 0) { return eFileFormat_TGA; } + else if(strcmp(ext, ".ktx") == 0) { + return eFileFormat_KTX; + } return kNumImageFileFormats; } diff --git a/PVRTCEncoder/CMakeLists.txt b/PVRTCEncoder/CMakeLists.txt index 756e63c..2f8845b 100644 --- a/PVRTCEncoder/CMakeLists.txt +++ b/PVRTCEncoder/CMakeLists.txt @@ -86,7 +86,6 @@ ADD_LIBRARY( PVRTCEncoder ) TARGET_LINK_LIBRARIES( PVRTCEncoder FasTCBase ) -TARGET_LINK_LIBRARIES( PVRTCEncoder FasTCCore ) TARGET_LINK_LIBRARIES( PVRTCEncoder FasTCIO ) IF( PVRTEXLIB_FOUND ) From 95ec3073805f4754a4094f8ed649ac2ace2844da Mon Sep 17 00:00:00 2001 From: Pavel Krajcevski Date: Wed, 29 Jan 2014 14:03:34 -0500 Subject: [PATCH 11/15] Fix delete to delete [] --- IO/src/ImageFile.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/IO/src/ImageFile.cpp b/IO/src/ImageFile.cpp index e4d767f..18d7602 100644 --- a/IO/src/ImageFile.cpp +++ b/IO/src/ImageFile.cpp @@ -242,7 +242,7 @@ FasTC::Image<> *ImageFile::LoadImage() const { // Cleanup delete loader; - delete pixelData; + delete [] pixelData; return i; } From aa7e73c4b35154c7948e6b4054bfd2754ae787bd Mon Sep 17 00:00:00 2001 From: Pavel Krajcevski Date: Wed, 29 Jan 2014 14:04:08 -0500 Subject: [PATCH 12/15] Add growable buffer to support dynamic ktx file sizes. --- IO/src/ImageWriterKTX.cpp | 28 ++++++++++++++++++++-------- 1 file changed, 20 insertions(+), 8 deletions(-) diff --git a/IO/src/ImageWriterKTX.cpp b/IO/src/ImageWriterKTX.cpp index 1a6a371..bcf14e4 100644 --- a/IO/src/ImageWriterKTX.cpp +++ b/IO/src/ImageWriterKTX.cpp @@ -69,28 +69,39 @@ ImageWriterKTX::ImageWriterKTX(FasTC::Image<> &im) class ByteWriter { private: + uint8 *m_Base; uint8 *m_Head; uint32 m_BytesWritten; + uint32 m_BufferSz; public: - ByteWriter(uint8 *dst) : m_Head(dst), m_BytesWritten(0) { } + ByteWriter(uint8 *dst, uint32 sz) + : m_Base(dst), m_Head(dst), m_BytesWritten(0), m_BufferSz(dst? sz : 0) { } + uint8 *GetBytes() const { return m_Base; } uint32 GetBytesWritten() const { return m_BytesWritten; } - void Write(const uint32 v) { - memcpy(m_Head, &v, 4); - m_Head += 4; - m_BytesWritten += 4; - } - void Write(const void *src, const uint32 nBytes) { + while(m_BytesWritten + nBytes > m_BufferSz) { + m_BufferSz <<= 1; + uint8 *newBuffer = new uint8[m_BufferSz]; + memcpy(newBuffer, m_Base, m_BytesWritten); + delete m_Base; + m_Base = newBuffer; + m_Head = m_Base + m_BytesWritten; + } + memcpy(m_Head, src, nBytes); m_Head += nBytes; m_BytesWritten += nBytes; } + + void Write(const uint32 v) { + Write(&v, 4); + } }; bool ImageWriterKTX::WriteImage() { - ByteWriter wtr (m_RawFileData); + ByteWriter wtr (m_RawFileData, m_RawFileDataSz); const uint8 kIdentifier[12] = { 0xAB, 0x4B, 0x54, 0x58, 0x20, 0x31, 0x31, 0xBB, 0x0D, 0x0A, 0x1A, 0x0A @@ -143,6 +154,7 @@ bool ImageWriterKTX::WriteImage() { wtr.Write(m_Image.GetPixels(), kImageSize); // imagedata... } + m_RawFileData = wtr.GetBytes(); m_RawFileDataSz = wtr.GetBytesWritten(); return true; } From 754cd3532ac6bcf603dd624572756c385c8821db Mon Sep 17 00:00:00 2001 From: Pavel Krajcevski Date: Wed, 29 Jan 2014 14:36:37 -0500 Subject: [PATCH 13/15] Don't crash if we can't parse the filename --- CLTool/src/tc.cpp | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/CLTool/src/tc.cpp b/CLTool/src/tc.cpp index e79e66d..ae1418f 100644 --- a/CLTool/src/tc.cpp +++ b/CLTool/src/tc.cpp @@ -100,6 +100,11 @@ void ExtractBasename(const char *filename, char *buf, size_t bufSz) { } } + if(!base) { + fprintf(stderr, "Filename (%s) has no extension, we don't know how to deal with it!\n", filename); + exit(1); + } + size_t numChars = ext - base + 1; size_t toCopy = ::std::min(numChars, bufSz); memcpy(buf, base, toCopy); From 4601cf00c7a3e5444438d0d22cbe65f6263e67ce Mon Sep 17 00:00:00 2001 From: Pavel Krajcevski Date: Wed, 29 Jan 2014 14:37:04 -0500 Subject: [PATCH 14/15] Small bugfix --- IO/src/ImageWriterKTX.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/IO/src/ImageWriterKTX.cpp b/IO/src/ImageWriterKTX.cpp index bcf14e4..642896a 100644 --- a/IO/src/ImageWriterKTX.cpp +++ b/IO/src/ImageWriterKTX.cpp @@ -142,7 +142,7 @@ bool ImageWriterKTX::WriteImage() { wtr.Write(kvSz); // key value size wtr.Write(orientationKey, strlen(orientationKey) + 1); // key wtr.Write(orientationValue, strlen(orientationValue) + 1); // value - wtr.Write(orientationKey, tkvSz - kvSz); // padding + wtr.Write(orientationKey, tkvSz - kvSz - 4); // padding if(ci && ci->GetFormat() == FasTC::eCompressionFormat_BPTC) { static const uint32 kImageSize = m_Width * m_Height; From 211bc5aeceb663fad36c73425d50ef6732cfc311 Mon Sep 17 00:00:00 2001 From: Pavel Krajcevski Date: Wed, 29 Jan 2014 14:37:19 -0500 Subject: [PATCH 15/15] Add PVRTC support to KTX writer --- IO/src/GLDefines.h | 17 +++++++++++++++++ IO/src/ImageWriterKTX.cpp | 23 ++++++++++++++++++++--- 2 files changed, 37 insertions(+), 3 deletions(-) diff --git a/IO/src/GLDefines.h b/IO/src/GLDefines.h index 03d01c4..5c086d2 100644 --- a/IO/src/GLDefines.h +++ b/IO/src/GLDefines.h @@ -81,4 +81,21 @@ #endif // GL_VERTSION_4_2 + +#ifndef COMPRESSED_RGB_PVRTC_4BPPV1_IMG +#define COMPRESSED_RGB_PVRTC_4BPPV1_IMG 0x8C00 +#endif // COMPRESSED_RGB_PVRTC_4BPPV1_IMG + +#ifndef COMPRESSED_RGB_PVRTC_2BPPV1_IMG +#define COMPRESSED_RGB_PVRTC_2BPPV1_IMG 0x8C01 +#endif // COMPRESSED_RGB_PVRTC_2BPPV1_IMG + +#ifndef COMPRESSED_RGBA_PVRTC_4BPPV1_IMG +#define COMPRESSED_RGBA_PVRTC_4BPPV1_IMG 0x8C02 +#endif // COMPRESSED_RGBA_PVRTC_4BPPV1_IMG + +#ifndef COMPRESSED_RGBA_PVRTC_2BPPV1_IMG +#define COMPRESSED_RGBA_PVRTC_2BPPV1_IMG 0x8C03 +#endif // COMPRESSED_RGBA_PVRTC_2BPPV1_IMG + #endif // _IO_SRC_GL_DEFINES_H_ diff --git a/IO/src/ImageWriterKTX.cpp b/IO/src/ImageWriterKTX.cpp index 642896a..8c29972 100644 --- a/IO/src/ImageWriterKTX.cpp +++ b/IO/src/ImageWriterKTX.cpp @@ -118,12 +118,25 @@ bool ImageWriterKTX::WriteImage() { tkvSz = (tkvSz + 3) & ~0x3; // 4-byte aligned CompressedImage *ci = dynamic_cast(&m_Image); - if(ci && ci->GetFormat() == FasTC::eCompressionFormat_BPTC) { + if(ci) { wtr.Write(0); // glType wtr.Write(1); // glTypeSize wtr.Write(GL_RGBA); // glFormat - wtr.Write(GL_COMPRESSED_RGBA_BPTC_UNORM); // glInternalFormat - wtr.Write(GL_RGBA); // glBaseFormat + switch(ci->GetFormat()) { + case FasTC::eCompressionFormat_BPTC: + wtr.Write(GL_COMPRESSED_RGBA_BPTC_UNORM); // glInternalFormat + wtr.Write(GL_RGBA); // glBaseFormat + break; + + case FasTC::eCompressionFormat_PVRTC: + wtr.Write(COMPRESSED_RGBA_PVRTC_4BPPV1_IMG); // glInternalFormat + wtr.Write(GL_RGBA); // glBaseFormat + break; + + default: + fprintf(stderr, "Unsupported KTX compressed format: %d\n", ci->GetFormat()); + return false; + } } else { wtr.Write(GL_BYTE); // glType wtr.Write(1); // glTypeSize @@ -148,6 +161,10 @@ bool ImageWriterKTX::WriteImage() { static const uint32 kImageSize = m_Width * m_Height; wtr.Write(kImageSize); // imageSize wtr.Write(ci->GetCompressedData(), kImageSize); // imagedata... + } else if(ci && ci->GetFormat() == FasTC::eCompressionFormat_PVRTC) { + static const uint32 kImageSize = m_Width * m_Height >> 1; + wtr.Write(kImageSize); // imageSize + wtr.Write(ci->GetCompressedData(), kImageSize); // imagedata... } else { static const uint32 kImageSize = m_Width * m_Height * 4; wtr.Write(kImageSize); // imageSize