From ab095a0a50b3cecd29bfda48bbdbafafc0c04234 Mon Sep 17 00:00:00 2001 From: Pavel Krajcevski Date: Mon, 11 Nov 2013 19:00:40 -0500 Subject: [PATCH 01/20] Catch up windows libs to their non-boost counterpart --- Windows | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Windows b/Windows index 326dfcc..4feeeb6 160000 --- a/Windows +++ b/Windows @@ -1 +1 @@ -Subproject commit 326dfccf36295f9ae43822a4d3fe3f21d87fbf94 +Subproject commit 4feeeb6550851ba3541c3f9505c76018e665667e From 956a5dcd9dc59b292362281dc0538c7b088079ad Mon Sep 17 00:00:00 2001 From: Pavel Krajcevski Date: Tue, 12 Nov 2013 11:41:27 -0500 Subject: [PATCH 02/20] Update README.md - Remove boost dependency and mentions - Update command line flags - Put links to different compression formats supported, and give credit where credit is due. --- README.md | 61 +++++++++++++++++++++++++++++++++++++++++++------------ 1 file changed, 48 insertions(+), 13 deletions(-) diff --git a/README.md b/README.md index 8c981b1..bdecfb0 100644 --- a/README.md +++ b/README.md @@ -1,8 +1,9 @@ FasTC ======= -A **Fas**t **T**exture **C**ompressor for the BPTC (a.k.a. BC7) format. This compressor -supports multi-threading through Boost's threading API and runs on Windows, OS X, and Linux +A **Fas**t **T**exture **C**ompressor for a variety of formats. This compressor +supports multi-threading via native Win32 threads on Windows and pthreads on other +operating systems. It has been tested on Windows, OS X, and Ubuntu Linux. --- @@ -10,7 +11,6 @@ Requirements: -------------- [CMake](http://www.cmake.org) (2.8.8)
-[Boost](http://www.boost.org) (tested with v1.50 and higher)
[libpng](http://www.libpng.org/pub/png/libpng.html) (1.5.13)
[zlib](http://www.zlib.net) (1.2.5) @@ -33,7 +33,7 @@ Once you do this you will be able to run some examples. #### Using Visual Studio on Windows #### Due to the C/C++ runtime requirements in Visual Studio, you must have a compiled version of each library that you wish to link to. In order to save time, I have uploaded various versions -of Boost, libpng, and zlib to a submodule in the source directory. Before running the steps above, +of libpng, and zlib to a submodule in the source directory. Before running the steps above, make sure to instantiate the submodule in git: cd FasTC/src @@ -41,30 +41,57 @@ make sure to instantiate the submodule in git: git submodule update This will download all of the Release versions of the necessary libraries (which means there will -be linker errors during the build process). I have compiled versions for Visual Studio 2008, 2010, -and 2012. +be linker warnings during the build process under the Debug configuration). I have compiled +versions for Visual Studio 2008, 2010, and 2012. Testing: -------------- Once the compressor is built, you may test it against any images you wish as long as their dimensions -are multiples of four and they are in the png file format. If you'd like to convert from one format to -another, I suggest taking a look at [ImageMagick](http://www.imagemagick.org/script/index.php) +are supported by the compression format and they are in the png file format. If you'd like to convert +from one format to another, I suggest taking a look at [ImageMagick](http://www.imagemagick.org/script/index.php) The quickest test will be to simply run the compressor on a PNG image: cd FasTC/build make CLTool/tc path/to/image.png + +This will compress `image.png` into the BPTC (BC7) format using 50 steps of simulated annealing without +SIMD optimization or multithreading. There are various run-time options available: -* `-t`: Specifies the number of threads to use for compression. The default is one. -* `-l`: Save an output log of various statistics during compression. This is mostly only useful for debugging. -* `-q `: Use `num` steps of simulated annealing during each endpoint compression. Default is 50 +* `-v`: Enabled verbosity, which reports Entropy, Mean Local Entropy, and MSSIM in addition to +compression time and PSNR. +* `-f `: Specifies the format use for compression. `fmt` can be any one of the following: + * [BPTC](http://www.opengl.org/registry/specs/ARB/texture_compression_bptc.txt) (**Default**) + * [ETC1](http://www.khronos.org/registry/gles/extensions/OES/OES_compressed_ETC1_RGB8_texture.txt) [1] + * [DXT1](http://www.opengl.org/registry/specs/EXT/texture_compression_s3tc.txt) [2] + * [DXT5](http://www.opengl.org/registry/specs/EXT/texture_compression_s3tc.txt) [2] + * [PVRTC](http://web.onetel.net.uk/~simonnihal/assorted3d/fenney03texcomp.pdf) +* `-t`: Specifies the number of threads to use for compression. + * **Default**: 1 + * **Formats**: BPTC, ETC1, DXT1, DXT5 +* `-l`: Save an output log of various statistics during compression. This is mostly only useful for +debugging. + * **Formats**: BPTC +* `-q `: Use `num` steps of simulated annealing during each endpoint compression. Default is 50. +Available only for BPTC. + * **Default**: 50 + * **Formats**: BPTC * `-n `: Perform `num` compressions in a row. This is good for testing metrics. -* `-a`: Use a parallel algorithm that uses Fetch-And-Add and Test-And-Set to perform mutual exclusion and avoid synchronization primitives. This algorithm is very useful when compressing a list of textures. Cannot be used with the `-j` option. -* `-j `: This specifies the number of 4x4 blocks that the compressor will crunch per thread. The default is to split the image up so that each thread compresses an equal share of the image. However, for many images, certain blocks compress faster than others, and you might want a more fine grained control over how to switch between compressing different blocks. + * **Default**: 1 + * **Formats**: All +* `-a`: Use a parallel algorithm that uses Fetch-And-Add and Test-And-Set to perform mutual exclusion +and avoid synchronization primitives. This algorithm is very useful when compressing a list of textures. +Cannot be used with the `-j` option. + * **Formats**: BPTC +* `-j `: This specifies the number of blocks that the compressor will request to crunch per thread. If this +flag is not specified or set to zero, the image will be split up so that each thread compresses an +equal share. However, for many images, certain blocks compress faster than others, and you might want +a more fine grained control over how to switch between compressing different blocks. + * **Formats**: BPTC, ETC1, DXT1, DXT5 As an example, if I wanted to test compressing a texture using no simulated annealing, 4 threads, and 32 blocks per job, I would invoke the following command: @@ -76,3 +103,11 @@ with atomic synchronization primitives, I would invoke the following command: CLTool/tc -n 100 -a path/to/image.png + +If I wanted to compress a texture into PVRTC, I would invoke the following command: + + CLTool/tc -f PVRTC path/to/image.png + +[1] Compression code courtesy of [Rich Geldreich](https://code.google.com/p/rg-etc1/)
+[2] Compression code courtesy of [Intel](http://software.intel.com/en-us/vcsource/samples/fast-texture-compression). +The idea implemented in this compressor was originally designed by [J. M. P. Van Waveren](http://www.gamedev.no/projects/MegatextureCompression/324337_324337.pdf) From bfce1c8b9dd8449f1cd540ee98778f1825d2d3b0 Mon Sep 17 00:00:00 2001 From: Pavel Krajcevski Date: Sun, 17 Nov 2013 14:16:45 -0500 Subject: [PATCH 03/20] Change windows submodule to point to https url --- .gitmodules | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.gitmodules b/.gitmodules index 1321102..1dce683 100644 --- a/.gitmodules +++ b/.gitmodules @@ -1,3 +1,3 @@ [submodule "Windows"] path = Windows - url = git@github.com:Mokosha/FasTC-MSVCLibs.git + url = https://github.com/Mokosha/FasTC-MSVCLibs.git From 86741f7a8944c14dfdfd35af2b60e28b723c5e5e Mon Sep 17 00:00:00 2001 From: Pavel Krajcevski Date: Sun, 17 Nov 2013 14:17:00 -0500 Subject: [PATCH 04/20] Fix some configuration issues with VS2012 --- Base/test/CMakeLists.txt | 6 ++++++ CLTool/src/tc.cpp | 2 +- GTest/cmake/internal_utils.cmake | 1 + PVRTCEncoder/test/CMakeLists.txt | 11 +++++++++++ 4 files changed, 19 insertions(+), 1 deletion(-) diff --git a/Base/test/CMakeLists.txt b/Base/test/CMakeLists.txt index 42caebd..ff349c8 100644 --- a/Base/test/CMakeLists.txt +++ b/Base/test/CMakeLists.txt @@ -59,6 +59,12 @@ SET(TESTS FOREACH(TEST ${TESTS}) SET(TEST_NAME Test_Base_${TEST}) SET(TEST_MODULE Test${TEST}.cpp) + + # HACK for MSVC 2012... + IF(MSVC) + ADD_DEFINITIONS(-D_VARIADIC_MAX=10) + ENDIF() + ADD_EXECUTABLE(${TEST_NAME} ${TEST_MODULE}) TARGET_LINK_LIBRARIES(${TEST_NAME} FasTCBase) TARGET_LINK_LIBRARIES(${TEST_NAME} gtest_main) diff --git a/CLTool/src/tc.cpp b/CLTool/src/tc.cpp index 04438b9..d562901 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'; diff --git a/GTest/cmake/internal_utils.cmake b/GTest/cmake/internal_utils.cmake index 8cb2189..f0ad219 100644 --- a/GTest/cmake/internal_utils.cmake +++ b/GTest/cmake/internal_utils.cmake @@ -71,6 +71,7 @@ macro(config_compiler_and_linker) set(cxx_exception_flags "-EHsc -D_HAS_EXCEPTIONS=1") set(cxx_no_exception_flags "-D_HAS_EXCEPTIONS=0") set(cxx_no_rtti_flags "-GR-") + add_definitions(-D_VARIADIC_MAX=10) elseif (CMAKE_COMPILER_IS_GNUCXX) set(cxx_base_flags "-Wall -Wshadow") set(cxx_exception_flags "-fexceptions") diff --git a/PVRTCEncoder/test/CMakeLists.txt b/PVRTCEncoder/test/CMakeLists.txt index 4ca9ee6..57de2e6 100644 --- a/PVRTCEncoder/test/CMakeLists.txt +++ b/PVRTCEncoder/test/CMakeLists.txt @@ -63,6 +63,12 @@ SET(TESTS FOREACH(TEST ${TESTS}) SET(TEST_NAME Test_PVRTCEncoder_${TEST}) SET(TEST_MODULE ${TEST}Test.cpp) + + # HACK for MSVC 2012... + IF(MSVC) + ADD_DEFINITIONS(-D_VARIADIC_MAX=10) + ENDIF() + ADD_EXECUTABLE(${TEST_NAME} ${TEST_MODULE}) TARGET_LINK_LIBRARIES(${TEST_NAME} PVRTCEncoder) TARGET_LINK_LIBRARIES(${TEST_NAME} gtest_main) @@ -91,6 +97,11 @@ IF(PVRTEXLIB_FOUND) INCLUDE_DIRECTORIES( ${PVRTEXLIB_INCLUDE_DIRS} ) INCLUDE_DIRECTORIES( ${FasTC_SOURCE_DIR}/Core/include ) + # HACK for MSVC 2012... + IF(MSVC) + ADD_DEFINITIONS(-D_VARIADIC_MAX=10) + ENDIF() + # The cpp file to compile for the test ADD_EXECUTABLE(${TEST_NAME} DecompTestPVR.cpp) From ba202c6ce9849c12592abc097e05074d5247ccfd Mon Sep 17 00:00:00 2001 From: Pavel Krajcevski Date: Tue, 19 Nov 2013 12:00:12 -0500 Subject: [PATCH 05/20] Fix assert to not cause warning in release and do some sane things... --- IO/src/ImageLoaderPNG.cpp | 8 +++++++- 1 file changed, 7 insertions(+), 1 deletion(-) diff --git a/IO/src/ImageLoaderPNG.cpp b/IO/src/ImageLoaderPNG.cpp index 332279d..f8310c0 100644 --- a/IO/src/ImageLoaderPNG.cpp +++ b/IO/src/ImageLoaderPNG.cpp @@ -156,7 +156,13 @@ bool ImageLoaderPNG::ReadData() { png_colorp palette; int nPaletteEntries; png_uint_32 ret = png_get_PLTE(png_ptr, info_ptr, &palette, &nPaletteEntries); - assert(ret == PNG_INFO_PLTE); + if(ret != PNG_INFO_PLTE) { + memset(m_BlueData, 0, numPixels); + memset(m_RedData, 0, numPixels); + memset(m_GreenData, 0, numPixels); + assert(!"Couldn't find PLTE chunk"); + break; + } for(uint32 i = 0; i < m_Height; i++) { png_read_row(png_ptr, rowData, NULL); From 6794a0fffb8803f7b963e2753a10b9b8356790ef Mon Sep 17 00:00:00 2001 From: Pavel Krajcevski Date: Tue, 19 Nov 2013 12:03:03 -0500 Subject: [PATCH 06/20] Add hooks to NVTT bc7_export library if present on the users machine. Assumes that all of the cross platform problems are fixed for incorporation into FasTC... Otherwise the options to use NVTT are ignored. --- BPTCEncoder/CMakeLists.txt | 16 ++ BPTCEncoder/config/BC7Config.h.in | 2 + BPTCEncoder/include/BC7Compressor.h | 8 + BPTCEncoder/src/CompressNVTT.cpp | 207 +++++++++++++++++++++++++ CLTool/src/tc.cpp | 7 +- CMakeLists.txt | 1 + CMakeModules/FindBC7Export.cmake | 71 +++++++++ CMakeModules/bc7_export/CMakeLists.txt | 104 +++++++++++++ Core/include/TexComp.h | 5 + Core/src/TexComp.cpp | 13 +- 10 files changed, 432 insertions(+), 2 deletions(-) create mode 100644 BPTCEncoder/src/CompressNVTT.cpp create mode 100644 CMakeModules/FindBC7Export.cmake create mode 100644 CMakeModules/bc7_export/CMakeLists.txt diff --git a/BPTCEncoder/CMakeLists.txt b/BPTCEncoder/CMakeLists.txt index e841b89..6b1b125 100644 --- a/BPTCEncoder/CMakeLists.txt +++ b/BPTCEncoder/CMakeLists.txt @@ -45,6 +45,11 @@ INCLUDE_DIRECTORIES(${FasTC_SOURCE_DIR}/Base/include) INCLUDE_DIRECTORIES(${FasTC_SOURCE_DIR}/BPTCEncoder/include) INCLUDE_DIRECTORIES(${FasTC_BINARY_DIR}/BPTCEncoder/include) +IF(NOT "" STREQUAL "${AVPCLLIB_ROOT}") + INCLUDE_DIRECTORIES(${AVPCLLIB_INCLUDE_DIR}) + SET(FOUND_NVTT_BC7_EXPORT TRUE) +ENDIF() + INCLUDE(CheckCXXSourceRuns) IF( NOT HAS_INLINE_ASSEMBLY AND NOT HAS_INLINE_ASSEMBLY_WITH_FLAGS ) @@ -145,9 +150,20 @@ IF( HAS_INLINE_ASSEMBLY_WITH_FLAGS ) ENDIF() ENDIF() +IF(NOT "" STREQUAL "${AVPCLLIB_ROOT}") + SET( SOURCES + ${SOURCES} + src/CompressNVTT.cpp + ) +ENDIF() + ADD_LIBRARY( BPTCEncoder ${HEADERS} ${SOURCES} ) TARGET_LINK_LIBRARIES( BPTCEncoder FasTCBase ) + +IF(NOT "" STREQUAL "${AVPCLLIB_ROOT}") + TARGET_LINK_LIBRARIES( BPTCEncoder avpcl ) +ENDIF() diff --git a/BPTCEncoder/config/BC7Config.h.in b/BPTCEncoder/config/BC7Config.h.in index 0bdce7b..5a3ae81 100644 --- a/BPTCEncoder/config/BC7Config.h.in +++ b/BPTCEncoder/config/BC7Config.h.in @@ -52,3 +52,5 @@ #cmakedefine HAS_ATOMICS #cmakedefine HAS_GCC_ATOMICS #cmakedefine HAS_MSVC_ATOMICS + +#cmakedefine FOUND_NVTT_BC7_EXPORT diff --git a/BPTCEncoder/include/BC7Compressor.h b/BPTCEncoder/include/BC7Compressor.h index 96cf94c..4eb43fc 100755 --- a/BPTCEncoder/include/BC7Compressor.h +++ b/BPTCEncoder/include/BC7Compressor.h @@ -138,6 +138,14 @@ namespace BC7C { void CompressAtomic(FasTC::CompressionJobList &); #endif +#ifdef FOUND_NVTT_BC7_EXPORT + // These functions take the same arguments as Compress and CompressWithStats, + // but they use the NVTT compressor if it was supplied to CMake. + void CompressNVTT(const FasTC::CompressionJob &); + void CompressNVTTWithStats(const FasTC::CompressionJob &, + std::ostream *logStream); +#endif + // Decompress the image given as BC7 data to R8G8B8A8 format. Width and Height // are the dimensions of the image in pixels. void Decompress(const FasTC::DecompressionJob &); diff --git a/BPTCEncoder/src/CompressNVTT.cpp b/BPTCEncoder/src/CompressNVTT.cpp new file mode 100644 index 0000000..096ee3d --- /dev/null +++ b/BPTCEncoder/src/CompressNVTT.cpp @@ -0,0 +1,207 @@ +/* FasTC + * Copyright (c) 2013 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 "BC7Compressor.h" +#include "BC7CompressionMode.h" +#undef DBL_MAX +#include "BitStream.h" +#include "TexCompTypes.h" + +#include +#include +#include + +#include "avpcl.h" + +namespace BC7C { + + void GetBlock(uint32 x, uint32 y, uint32 width, const uint32 *pixels, Tile &t) { + for(uint32 j = 0; j < 4; j++) + for(uint32 i = 0; i < 4; i++) { + uint32 pixel = pixels[(y+j)*width + (x+i)]; + t.data[j][i].X() = pixel & 0xFF; + t.data[j][i].Y() = (pixel >> 8) & 0xFF; + t.data[j][i].Z() = (pixel >> 16) & 0xFF; + t.data[j][i].W() = (pixel >> 24) & 0xFF; + } + } + + class BlockLogger { + public: + BlockLogger(uint64 blockIdx, std::ostream &os) + : m_BlockIdx(blockIdx), m_Stream(os) { } + + template + friend std::ostream &operator<<(const BlockLogger &bl, const T &v); + + uint64 m_BlockIdx; + std::ostream &m_Stream; + }; + + template + std::ostream &operator<<(const BlockLogger &bl, const T &v) { + std::stringstream ss; + ss << bl.m_BlockIdx << ": " << v; + return bl.m_Stream << ss.str(); + } + + template + static void PrintStat(const BlockLogger &lgr, const char *stat, const T &v) { + std::stringstream ss; + ss << stat << " -- " << v << std::endl; + lgr << ss.str(); + } + + // Compress an image using BC7 compression. Use the inBuf parameter to point + // to an image in 4-byte RGBA format. The width and height parameters specify + // the size of the image in pixels. The buffer pointed to by outBuf should be + // large enough to store the compressed image. This implementation has an 4:1 + // compression ratio. + void CompressNVTT(const FasTC::CompressionJob &cj) { + const uint32 *inPixels = reinterpret_cast(cj.InBuf()); + const uint32 kBlockSz = GetBlockSize(FasTC::eCompressionFormat_BPTC); + uint8 *outBuf = cj.OutBuf() + cj.CoordsToBlockIdx(cj.XStart(), cj.YStart()) * kBlockSz; + + uint32 startX = cj.XStart(); + bool done = false; + + for(uint32 j = cj.YStart(); !done; j += 4) { + for(uint32 i = startX; !done && i < cj.Width(); i += 4) { + + Tile block(4, 4); + GetBlock(i, j, cj.Width(), inPixels, block); + AVPCL::compress(block, reinterpret_cast(outBuf), NULL); + + outBuf += kBlockSz; + done = i+4 >= cj.XEnd() && j+(i+4 == cj.Width()? 4 : 0) >= cj.YEnd(); + } + startX = 0; + } + } + + typedef double (*ModeCompressFunc)(const Tile &, char* out); + static ModeCompressFunc kModeFuncs[8] = { + AVPCL::compress_mode0, + AVPCL::compress_mode1, + AVPCL::compress_mode2, + AVPCL::compress_mode3, + AVPCL::compress_mode4, + AVPCL::compress_mode5, + AVPCL::compress_mode6, + AVPCL::compress_mode7 + }; + + double CompressMode(uint32 mode, const Tile &t, char *out, BlockLogger &log) { + std::stringstream ss; + ss << "Mode_" << mode << "_error"; + double mse = kModeFuncs[mode](t, out); + PrintStat(log, ss.str().c_str(), mse); + + BitStreamReadOnly strm(reinterpret_cast(out)); + while(!strm.ReadBit()); + + const BC7CompressionMode::Attributes *attrs = + BC7CompressionMode::GetAttributesForMode(mode); + const uint32 nSubsets = attrs->numSubsets; + + ss.str(""); + ss << "Mode_" << mode << "_shape"; + + uint32 shapeIdx = 0; + if ( nSubsets > 1 ) { + shapeIdx = strm.ReadBits(mode == 0? 4 : 6); + PrintStat(log, ss.str().c_str(), shapeIdx); + } else { + PrintStat(log, ss.str().c_str(), -1); + } + + return mse; + } + + void CompressNVTTWithStats(const FasTC::CompressionJob &cj, std::ostream *logStream) { + const uint32 *inPixels = reinterpret_cast(cj.InBuf()); + const uint32 kBlockSz = GetBlockSize(FasTC::eCompressionFormat_BPTC); + uint8 *outBuf = cj.OutBuf() + cj.CoordsToBlockIdx(cj.XStart(), cj.YStart()) * kBlockSz; + + uint32 startX = cj.XStart(); + bool done = false; + for(uint32 j = cj.YStart(); !done; j += 4) { + for(uint32 i = startX; !done && i < cj.Width(); i += 4) { + + Tile block(4, 4); + GetBlock(i, j, cj.Width(), inPixels, block); + + if(logStream) { + BlockLogger logger(cj.CoordsToBlockIdx(i, j), *logStream); + + char tempblock[16]; + double msebest = 1e30; + for(uint32 mode = 0; mode < 8; mode++) { + double mse_mode = CompressMode(mode, block, tempblock, logger); + if(mse_mode < msebest) { + msebest = mse_mode; + memcpy(outBuf, tempblock, AVPCL::BLOCKSIZE); + } + } + } else { + AVPCL::compress(block, reinterpret_cast(outBuf), NULL); + } + + outBuf += 16; + done = i+4 >= cj.XEnd() && j+(i+4 == cj.Width()? 4 : 0) >= cj.YEnd(); + } + + startX = 0; + } + } + +} // namespace BC7C diff --git a/CLTool/src/tc.cpp b/CLTool/src/tc.cpp index 04438b9..9a78599 100644 --- a/CLTool/src/tc.cpp +++ b/CLTool/src/tc.cpp @@ -121,6 +121,7 @@ int main(int argc, char **argv) { bool bSaveLog = false; bool bUseAtomics = false; bool bUsePVRTexLib = false; + bool bUseNVTT = false; bool bVerbose = false; FasTC::ECompressionFormat format = FasTC::eCompressionFormat_BPTC; @@ -153,6 +154,9 @@ int main(int argc, char **argv) { } else if(!strcmp(argv[fileArg], "PVRTCLib")) { format = FasTC::eCompressionFormat_PVRTC; bUsePVRTexLib = true; + } else if(!strcmp(argv[fileArg], "BPTCLib")) { + format = FasTC::eCompressionFormat_BPTC; + bUseNVTT = true; } else if(!strcmp(argv[fileArg], "ETC1")) { format = FasTC::eCompressionFormat_ETC1; } else if(!strcmp(argv[fileArg], "DXT1")) { @@ -275,6 +279,7 @@ int main(int argc, char **argv) { settings.iNumCompressions = numCompressions; settings.iJobSize = numJobs; settings.bUsePVRTexLib = bUsePVRTexLib; + settings.bUseNVTT = bUseNVTT; if(bSaveLog) { settings.logStream = &logStream; } else { @@ -323,4 +328,4 @@ int main(int argc, char **argv) { logFile.close(); } return 0; -} \ No newline at end of file +} diff --git a/CMakeLists.txt b/CMakeLists.txt index f28f909..574333e 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -91,6 +91,7 @@ ENDIF(TREAT_WARNINGS_AS_ERRORS) SET(CMAKE_MODULE_PATH "${FasTC_SOURCE_DIR}/CMakeModules" ${CMAKE_MODULE_PATH}) FIND_PACKAGE(PVRTexLib) +FIND_PACKAGE(BC7Export) SET(FASTC_DIRECTORIES Base Core IO BPTCEncoder PVRTCEncoder DXTEncoder ETCEncoder diff --git a/CMakeModules/FindBC7Export.cmake b/CMakeModules/FindBC7Export.cmake new file mode 100644 index 0000000..94474f0 --- /dev/null +++ b/CMakeModules/FindBC7Export.cmake @@ -0,0 +1,71 @@ +# FasTC +# Copyright (c) 2013 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 +# +# + +# - Try to find libPVRTexLib +# Once done this will define +# PVRTEXLIB_FOUND - System has PVRTexLib +# PVRTEXLIB_INCLUDE_DIRS - The PVRTexLib include directories +# PVRTEXLIB_LIBRARIES - The libraries needed to use PVRTexLib + +SET(AVPCLLIB_ROOT "" CACHE STRING "Location of the BC7 Export library from NVTT") + +IF(NOT AVPCLLIB_ROOT STREQUAL "") + IF(NOT EXISTS "${AVPCLLIB_ROOT}/src/CMakeLists.txt") + CONFIGURE_FILE( + "${CMAKE_CURRENT_LIST_DIR}/bc7_export/CMakeLists.txt" + "${AVPCLLIB_ROOT}/src" + COPYONLY) + ENDIF() + ADD_SUBDIRECTORY(${AVPCLLIB_ROOT}/src ${CMAKE_CURRENT_BINARY_DIR}/bc7_export) + set(AVPCLLIB_INCLUDE_DIR ${AVPCLLIB_ROOT}/src ) +ENDIF() + +mark_as_advanced( FORCE AVPCLLIB_ROOT AVPCLLIB_INCLUDE_DIR ) diff --git a/CMakeModules/bc7_export/CMakeLists.txt b/CMakeModules/bc7_export/CMakeLists.txt new file mode 100644 index 0000000..c5fd822 --- /dev/null +++ b/CMakeModules/bc7_export/CMakeLists.txt @@ -0,0 +1,104 @@ +# FasTC +# Copyright (c) 2012 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_DIRECTORIES(${CMAKE_CURRENT_LIST_DIR}) +INCLUDE_DIRECTORIES(${CMAKE_CURRENT_LIST_DIR}/arvo) + +SET( HEADERS + avpcl.h + bits.h + endpts.h + ImfArray.h + rgba.h + shapes_three.h + shapes_two.h + targa.h + tile.h + utils.h + arvo/ArvoMath.h + arvo/Char.h + arvo/Complex.h + arvo/form.h + arvo/Matrix.h + arvo/Perm.h + arvo/Rand.h + arvo/SI_units.h + arvo/SphTri.h + arvo/SVD.h + arvo/Token.h + arvo/Vec2.h + arvo/Vec3.h + arvo/Vec4.h + arvo/Vector.h +) + +SET( SOURCES + avpcl.cpp + avpcl_mode0.cpp + avpcl_mode1.cpp + avpcl_mode2.cpp + avpcl_mode3.cpp + avpcl_mode4.cpp + avpcl_mode5.cpp + avpcl_mode6.cpp + avpcl_mode7.cpp + targa.cpp + utils.cpp + arvo/ArvoMath.cpp + arvo/Char.cpp + arvo/Complex.cpp + arvo/Matrix.cpp + arvo/Perm.cpp + arvo/Rand.cpp + arvo/SphTri.cpp + arvo/SVD.cpp + arvo/Token.cpp + arvo/Vec2.cpp + arvo/Vec3.cpp + arvo/Vec4.cpp + arvo/Vector.cpp +) + +ADD_LIBRARY( avpcl + ${HEADERS} + ${SOURCES} +) diff --git a/Core/include/TexComp.h b/Core/include/TexComp.h index 5c02327..7eede5e 100644 --- a/Core/include/TexComp.h +++ b/Core/include/TexComp.h @@ -91,6 +91,11 @@ struct SCompressionSettings { // ignored. The quality being used is the fastest compression quality. bool bUsePVRTexLib; + // This flag instructs the infrastructure to use the compression routine from + // NVidia Texture Tools. If no such lib is found during configuration then this + // flag is ignored. + bool bUseNVTT; + // This is the output stream with which we should output the logs for the // compression functions. std::ostream *logStream; diff --git a/Core/src/TexComp.cpp b/Core/src/TexComp.cpp index 6b820f2..96f5158 100644 --- a/Core/src/TexComp.cpp +++ b/Core/src/TexComp.cpp @@ -104,6 +104,11 @@ static CompressionFuncWithStats ChooseFuncFromSettingsWithStats(const SCompress case FasTC::eCompressionFormat_BPTC: { +#ifdef FOUND_NVTT_BC7_EXPORT + if(s.bUseNVTT) + return BC7C::CompressNVTTWithStats; + else +#endif return BC7C::CompressWithStats; } break; @@ -136,7 +141,13 @@ static CompressionFunc ChooseFuncFromSettings(const SCompressionSettings &s) { return BC7C::CompressImageBC7SIMD; } #endif - return BC7C::Compress; + +#ifdef FOUND_NVTT_BC7_EXPORT + if(s.bUseNVTT) + return BC7C::CompressNVTT; + else +#endif + return BC7C::Compress; } break; From 56259e28614a2812df2f631f20ca809ce0f69795 Mon Sep 17 00:00:00 2001 From: Pavel Krajcevski Date: Tue, 19 Nov 2013 12:04:06 -0500 Subject: [PATCH 07/20] Add third party files for reading/writing TGA files. --- IO/CMakeLists.txt | 5 + IO/third_party/tga/targa.c | 643 +++++++++++++++++++++++++++++++++++++ IO/third_party/tga/targa.h | 227 +++++++++++++ 3 files changed, 875 insertions(+) create mode 100755 IO/third_party/tga/targa.c create mode 100755 IO/third_party/tga/targa.h diff --git a/IO/CMakeLists.txt b/IO/CMakeLists.txt index 28754bc..520539b 100644 --- a/IO/CMakeLists.txt +++ b/IO/CMakeLists.txt @@ -78,6 +78,11 @@ IF( PVRTEXLIB_FOUND ) SET( HEADERS ${HEADERS} "src/ImageLoaderPVR.h" ) ENDIF( PVRTEXLIB_FOUND ) +# Add third-party TGA library... +SET( SOURCES ${SOURCES} "third_party/tga/targa.c" ) +SET( HEADERS ${HEADERS} "third_party/tga/targa.h" ) +INCLUDE_DIRECTORIES( ${FasTC_SOURCE_DIR}/IO/third_party/tga ) + CONFIGURE_FILE( "config/ImageLoader.h.in" "include/ImageLoader.h" diff --git a/IO/third_party/tga/targa.c b/IO/third_party/tga/targa.c new file mode 100755 index 0000000..36313e2 --- /dev/null +++ b/IO/third_party/tga/targa.c @@ -0,0 +1,643 @@ +/* + * targa.c + * + * Copyright (C) 2006 - 2009 by Joshua S. English. + * + * This software is the intellectual property of Joshua S. English. This + * software is provided 'as-is', without any express or implied warranty. In no + * event will the author be held liable for any damages arising from the use of + * this software. + * + * Permission is granted to anyone to use this software for any purpose, + * including commercial applications, and to alter it and redistribute it + * freely, subject to the following restrictions: + * + * 1. The origin of this software must not be misrepresented; you must not + * claim that you wrote the original software. If you use this software in + * a product, an acknowledgment in the product documentation would be + * appreciated but is not required. + * + * 2. Altered source version must be plainly marked as such, and must not be + * misrepresented as being original software. + * + * 3. This notice may not be removed or altered from any source distribution. + * + * + * Notes: + * + * A plugin to read targa (TGA) image files into an OpenGL-compatible RGBA + * format. + * + * Written by Joshua S. English. + */ + +// preprocessor directives + +#include +#include +#include +#include +#include "targa.h" + + +// define targa private constants + +#define TGA_COLOR_MAP_NONE 0 + +#define TGA_IMAGE_TYPE_NONE 0 +#define TGA_IMAGE_TYPE_CM 1 +#define TGA_IMAGE_TYPE_BGR 2 +#define TGA_IMAGE_TYPE_BW 3 +#define TGA_IMAGE_TYPE_RLE_CM 9 +#define TGA_IMAGE_TYPE_RLE_BGR 10 +#define TGA_IMAGE_TYPE_RLE_BW 11 + +#define TGA_R 0 +#define TGA_G 1 +#define TGA_B 2 +#define TGA_A 3 + + +// declare targa private functions + +static int handleTargaError(FILE *fh, int errorCode, const char *function, + size_t line); + +static int ctoi(char value); + +static char *localStrndup(char *string, int length); + + +// define targa private macros + +#define targaErrorf() \ + handleTargaError(fh, rc, __FUNCTION__, __LINE__) + + +// define targa private functions + +static int handleTargaError(FILE *fh, int errorCode, const char *function, + size_t line) +{ + char *errorMessage = NULL; + + if((errorMessage = strerror(errno)) == NULL) { + errorMessage = "uknown error"; + } + + fprintf(stderr, "[%s():%i] error(%i) - #%i, '%s'.\n", + (char *)function, (int)line, errorCode, (int)errno, errorMessage); + + if(fh != NULL) { + fclose(fh); + } + + return -1; +} + +static int ctoi(char value) +{ + return (int)((unsigned char)value); +} + +static char *localStrndup(char *string, int length) +{ + char *result = NULL; + + if((string == NULL) || (length < 1)) { + fprintf(stderr, "[%s():%i] error - invalid or missing argument(s).\n", + __FUNCTION__, __LINE__); + return NULL; + } + +#if defined(_GNU_SOURCE) + result = strndup(string, length); +#else // !_GNU_SOURCE + result = (char *)malloc(sizeof(char) * (length + 1)); + memset(result, 0, (sizeof(char) * (length + 1))); + memcpy(result, string, length); +#endif // _GNU_SOURCE + + return result; +} + + +// define targa public functions + +int targa_init(Targa *targa) +{ + if(targa == NULL) { + fprintf(stderr, "[%s():%i] error - invalid or missing argument(s).\n", + __FUNCTION__, __LINE__); + return -1; + } + + memset((void *)targa, 0, sizeof(Targa)); + + targa->width = 0; + targa->height = 0; + targa->imageLength = 0; + targa->image = NULL; + + return 0; +} + +int targa_free(Targa *targa) +{ + if(targa == NULL) { + fprintf(stderr, "[%s():%i] error - invalid or missing argument(s).\n", + __FUNCTION__, __LINE__); + return -1; + } + + if(targa->image != NULL) { + free(targa->image); + } + + memset((void *)targa, 0, sizeof(Targa)); + + return 0; +} + +int targa_getDimensions(Targa *targa, int *width, int *height) +{ + if((targa == NULL) || (width == NULL) || (height == NULL)) { + fprintf(stderr, "[%s():%i] error - invalid or missing argument(s).\n", + __FUNCTION__, __LINE__); + return -1; + } + + *width = targa->width; + *height = targa->height; + + return 0; +} + +int targa_getImageLength(Targa *targa, int *imageLength) +{ + if((targa == NULL) || (imageLength == NULL)) { + fprintf(stderr, "[%s():%i] error - invalid or missing argument(s).\n", + __FUNCTION__, __LINE__); + return -1; + } + + *imageLength = targa->imageLength; + + return 0; +} + +int targa_getRgbaTexture(Targa *targa, char **texture, int *textureLength) +{ + if((targa == NULL) || (texture == NULL) || (textureLength == NULL)) { + fprintf(stderr, "[%s():%i] error - invalid or missing argument(s).\n", + __FUNCTION__, __LINE__); + return -1; + } + + *texture = (char *)targa->image; + *textureLength = targa->imageLength; + + return 0; +} + +int targa_loadFromFile(Targa *targa, char *filename) +{ + int rc = 0; + int fileLength = 0; + unsigned char *buffer = NULL; + + FILE *fh = NULL; + + if((targa == NULL) || (filename == NULL)) { + fprintf(stderr, "[%s():%i] error - invalid or missing argument(s).\n", + __FUNCTION__, __LINE__); + return -1; + } + + if((fh = fopen(filename, "r+b")) == NULL) { + return targaErrorf(); + } + + if((rc = fseek(fh, 0, SEEK_END)) != 0) { + return targaErrorf(); + } + + if((fileLength = ftell(fh)) < 0) { + return targaErrorf(); + } + + if((rc = fseek(fh, 0, SEEK_SET)) != 0) { + return targaErrorf(); + } + + if(fileLength < 18) { + fprintf(stderr, "error - TGA file '%s' length %i invalid.\n", + filename, fileLength); + fclose(fh); + return -1; + } + + buffer = (unsigned char *)malloc(sizeof(unsigned char) * fileLength); + memset(buffer, 0, (sizeof(unsigned char) * fileLength)); + + rc = (int)fread((char *)buffer, sizeof(char), fileLength, fh); + if(rc != fileLength) { + return targaErrorf(); + } + + fclose(fh); + + rc = targa_loadFromData(targa, buffer, fileLength); + + free(buffer); + + return rc; +} + +int targa_loadFromData(Targa *targa, unsigned char *data, int dataLength) +{ + short sNumber = 0; + int ii = 0; + int nn = 0; + int imageIdLength = 0; + int colorMap = 0; + int imageType = 0; + int bitLength = 0; + int colorMode = 0; + int length = 0; + int rleId = 0; + int pixel[4]; + unsigned char *imageId = NULL; + unsigned char *ptr = NULL; + + if((targa == NULL) || (data == NULL) || (dataLength < 18)) { + fprintf(stderr, "[%s():%i] error - invalid or missing argument(s).\n", + __FUNCTION__, __LINE__); + return -1; + } + + ptr = data; + + // determine image ID length + + imageIdLength = (int)ptr[0]; + ptr++; + if((int)(ptr - data) > dataLength) { + fprintf(stderr, "[%s():%i] error - detected data overrun with %i vs " + "%i.\n", __FUNCTION__, __LINE__, (int)(ptr - data), + dataLength); + return -1; + } + + // check for color map + + colorMap = (int)ptr[0]; + ptr++; + if((int)(ptr - data) > dataLength) { + fprintf(stderr, "[%s():%i] error - detected data overrun with %i vs " + "%i.\n", __FUNCTION__, __LINE__, (int)(ptr - data), + dataLength); + return -1; + } + if(colorMap != TGA_COLOR_MAP_NONE) { + fprintf(stderr, "[%s():%i] error - unable to read TARGA color map " + "%i.\n", __FUNCTION__, __LINE__, colorMap); + return -1; + } + + // obtain image type + + imageType = (int)ptr[0]; + ptr++; + if((int)(ptr - data) > dataLength) { + fprintf(stderr, "[%s():%i] error - detected data overrun with %i vs " + "%i.\n", __FUNCTION__, __LINE__, (int)(ptr - data), + dataLength); + return -1; + } + if((imageType == TGA_IMAGE_TYPE_NONE) || + (imageType == TGA_IMAGE_TYPE_CM) || + (imageType == TGA_IMAGE_TYPE_RLE_CM)) { + fprintf(stderr, "[%s():%i] error - unsupported image type %i.\n", + __FUNCTION__, __LINE__, imageType); + return -1; + } + + // skip 9 bytes (color-map information and x & y origins) + + ptr += 9; + if((int)(ptr - data) > dataLength) { + fprintf(stderr, "[%s():%i] error - detected data overrun with %i vs " + "%i.\n", __FUNCTION__, __LINE__, (int)(ptr - data), + dataLength); + return -1; + } + + // obtain image width + + memcpy((char *)&sNumber, ptr, sizeof(short)); + ptr += sizeof(short); + if((int)(ptr - data) > dataLength) { + fprintf(stderr, "[%s():%i] error - detected data overrun with %i vs " + "%i.\n", __FUNCTION__, __LINE__, (int)(ptr - data), + dataLength); + return -1; + } + if(sNumber < 1) { + fprintf(stderr, "[%s():%i] error - invalid image width %i.\n", + __FUNCTION__, __LINE__, (int)sNumber); + return -1; + } + + targa->width = (int)sNumber; + + // obtain image height + + memcpy((char *)&sNumber, ptr, sizeof(short)); + ptr += sizeof(short); + if((int)(ptr - data) > dataLength) { + fprintf(stderr, "[%s():%i] error - detected data overrun with %i vs " + "%i.\n", __FUNCTION__, __LINE__, (int)(ptr - data), + dataLength); + return -1; + } + if(sNumber < 1) { + fprintf(stderr, "[%s():%i] error - invalid image height %i.\n", + __FUNCTION__, __LINE__, (int)sNumber); + return -1; + } + + targa->height = (int)sNumber; + + // determine pixel depth + + bitLength = (int)ptr[0]; + ptr++; + if((int)(ptr - data) > dataLength) { + fprintf(stderr, "[%s():%i] error - detected data overrun with %i vs " + "%i.\n", __FUNCTION__, __LINE__, (int)(ptr - data), + dataLength); + return -1; + } + if((bitLength != 16) && (bitLength != 24) && (bitLength != 32)) { + fprintf(stderr, "[%s():%i] error - unknown pixel depth of %i-bits.\n", + __FUNCTION__, __LINE__, bitLength); + return -1; + } + if((bitLength == 16) && + ((imageType != TGA_IMAGE_TYPE_BGR) && + (imageType != TGA_IMAGE_TYPE_BW))) { + fprintf(stderr, "[%s():%i] error - unable to RLE-decode pixel depth " + "of %i-bits.\n", __FUNCTION__, __LINE__, bitLength); + return -1; + } + + // skip 1 byte (image descriptor) + + ptr++; + if((int)(ptr - data) > dataLength) { + fprintf(stderr, "[%s():%i] error - detected data overrun with %i vs " + "%i.\n", __FUNCTION__, __LINE__, (int)(ptr - data), + dataLength); + return -1; + } + + // obtain the image ID + + if(imageIdLength > 0) { + if(((int)(ptr - data) + imageIdLength) > dataLength) { + fprintf(stderr, "[%s():%i] error - detected data overrun at %i " + "(image ID) by %i bytes.\n", __FUNCTION__, __LINE__, + (int)(ptr - data), + (((int)(ptr - data) + imageIdLength) - dataLength)); + return -1; + } + imageId = (unsigned char *)localStrndup((char *)ptr, imageIdLength); + ptr += imageIdLength; + if((int)(ptr - data) > dataLength) { + fprintf(stderr, "[%s():%i] error - detected data overrun with %i " + "vs %i.\n", __FUNCTION__, __LINE__, (int)(ptr - data), + dataLength); + return -1; + } + } + + // process the image + + targa->imageLength = (long int)(targa->width * targa->height * 4); + targa->image = (unsigned char *)malloc(sizeof(unsigned char) * + targa->imageLength); + + if((imageType == TGA_IMAGE_TYPE_BGR) || (imageType == TGA_IMAGE_TYPE_BW)) { + if(bitLength == 16) { + colorMode = 2; + } + else { + colorMode = (bitLength / 8); + } + length = (targa->width * targa->height * colorMode); + if(((int)(ptr - data) + length) > dataLength) { + fprintf(stderr, "[%s():%i] error - detected data overrun at %i " + "(image pixels) by %i bytes.\n", __FUNCTION__, __LINE__, + (int)(ptr - data), + (((int)(ptr - data) + length) - dataLength)); + return -1; + } + for(ii = 0, nn = 0; ((ii < length) && (nn < targa->imageLength)); + ii += colorMode, nn += 4) { + if(colorMode == 2) { + memcpy((char *)&sNumber, ptr, sizeof(short)); + pixel[TGA_R] = ctoi((sNumber & 0x1f) << 3); + pixel[TGA_G] = ctoi(((sNumber >> 5) & 0x1f) << 3); + pixel[TGA_B] = ctoi(((sNumber >> 10) & 0x1f) << 3); + pixel[TGA_A] = 255; + } + else { + pixel[TGA_R] = ctoi(ptr[2]); + pixel[TGA_G] = ctoi(ptr[1]); + pixel[TGA_B] = ctoi(ptr[0]); + if(colorMode == 3) { + pixel[TGA_A] = 255; + } + else { + pixel[TGA_A] = ctoi(ptr[3]); + } + } + + targa->image[(nn + 0)] = (unsigned char)pixel[TGA_R]; + targa->image[(nn + 1)] = (unsigned char)pixel[TGA_G]; + targa->image[(nn + 2)] = (unsigned char)pixel[TGA_B]; + targa->image[(nn + 3)] = (unsigned char)pixel[TGA_A]; + + ptr += colorMode; + } + } + else { // RLE image + ii = 0; + nn = 0; + rleId = 0; + colorMode = (bitLength / 8); + length = (targa->width * targa->height); + while(ii < length) { + rleId = (int)ptr[0]; + ptr++; + if((int)(ptr - data) > dataLength) { + fprintf(stderr, "[%s():%i] error - detected data overrun with " + "%i vs %i.\n", __FUNCTION__, __LINE__, + (int)(ptr - data), dataLength); + return -1; + } + + if(rleId < 128) { + rleId++; + while(rleId > 0) { + pixel[TGA_R] = ctoi(ptr[2]); + pixel[TGA_G] = ctoi(ptr[1]); + pixel[TGA_B] = ctoi(ptr[0]); + if(colorMode == 3) { + pixel[TGA_A] = 255; + } + else { + pixel[TGA_A] = ctoi(ptr[3]); + } + + targa->image[(nn + 0)] = (unsigned char)pixel[TGA_R]; + targa->image[(nn + 1)] = (unsigned char)pixel[TGA_G]; + targa->image[(nn + 2)] = (unsigned char)pixel[TGA_B]; + targa->image[(nn + 3)] = (unsigned char)pixel[TGA_A]; + + rleId--; + ii++; + nn += 4; + if(nn >= targa->imageLength) { + break; + } + ptr += colorMode; + if((int)(ptr - data) > dataLength) { + fprintf(stderr, "[%s():%i] error - detected data " + "overrun with %i vs %i.\n", __FUNCTION__, + __LINE__, (int)(ptr - data), dataLength); + return -1; + } + } + } + else { + pixel[TGA_R] = ctoi(ptr[2]); + pixel[TGA_G] = ctoi(ptr[1]); + pixel[TGA_B] = ctoi(ptr[0]); + if(colorMode == 3) { + pixel[TGA_A] = 255; + } + else { + pixel[TGA_A] = ctoi(ptr[3]); + } + ptr += colorMode; + if((int)(ptr - data) > dataLength) { + fprintf(stderr, "[%s():%i] error - detected data overrun " + "with %i vs %i.\n", __FUNCTION__, __LINE__, + (int)(ptr - data), dataLength); + return -1; + } + + rleId -= 127; + while(rleId > 0) { + targa->image[(nn + 0)] = (unsigned char)pixel[TGA_R]; + targa->image[(nn + 1)] = (unsigned char)pixel[TGA_G]; + targa->image[(nn + 2)] = (unsigned char)pixel[TGA_B]; + targa->image[(nn + 3)] = (unsigned char)pixel[TGA_A]; + + rleId--; + ii++; + nn += 4; + if(nn >= targa->imageLength) { + break; + } + } + } + if(nn >= targa->imageLength) { + break; + } + } + } + + if(imageId != NULL) { + free(imageId); + } + + return 0; +} + +int targa_applyRgbaMask(Targa *targa, int colorType, unsigned char value) +{ + int ii = 0; + int startPosition = 0; + + if((targa == NULL) || + ((colorType != TARGA_COLOR_RED) && + (colorType != TARGA_COLOR_GREEN) && + (colorType != TARGA_COLOR_BLUE) && + (colorType != TARGA_COLOR_ALPHA))) { + fprintf(stderr, "[%s():%i] error - invalid or missing argument(s).\n", + __FUNCTION__, __LINE__); + return -1; + } + + switch(colorType) { + case TARGA_COLOR_RED: + startPosition = 0; + break; + case TARGA_COLOR_GREEN: + startPosition = 1; + break; + case TARGA_COLOR_BLUE: + startPosition = 2; + break; + case TARGA_COLOR_ALPHA: + startPosition = 3; + break; + } + + for(ii = startPosition; ii < targa->imageLength; ii += 4) { + targa->image[ii] += value; + } + + return 0; +} + +int targa_setRgbaChannel(Targa *targa, int colorType, unsigned char value) +{ + int ii = 0; + int startPosition = 0; + + if((targa == NULL) || + ((colorType != TARGA_COLOR_RED) && + (colorType != TARGA_COLOR_GREEN) && + (colorType != TARGA_COLOR_BLUE) && + (colorType != TARGA_COLOR_ALPHA))) { + fprintf(stderr, "[%s():%i] error - invalid or missing argument(s).\n", + __FUNCTION__, __LINE__); + return -1; + } + + switch(colorType) { + case TARGA_COLOR_RED: + startPosition = 0; + break; + case TARGA_COLOR_GREEN: + startPosition = 1; + break; + case TARGA_COLOR_BLUE: + startPosition = 2; + break; + case TARGA_COLOR_ALPHA: + startPosition = 3; + break; + } + + for(ii = startPosition; ii < targa->imageLength; ii += 4) { + targa->image[ii] = value; + } + + return 0; +} + diff --git a/IO/third_party/tga/targa.h b/IO/third_party/tga/targa.h new file mode 100755 index 0000000..dffea51 --- /dev/null +++ b/IO/third_party/tga/targa.h @@ -0,0 +1,227 @@ +/* + * targa.h + * + * Copyright (C) 2006 - 2009 by Joshua S. English. + * + * This software is the intellectual property of Joshua S. English. This + * software is provided 'as-is', without any express or implied warranty. In no + * event will the author be held liable for any damages arising from the use of + * this software. + * + * Permission is granted to anyone to use this software for any purpose, + * including commercial applications, and to alter it and redistribute it + * freely, subject to the following restrictions: + * + * 1. The origin of this software must not be misrepresented; you must not + * claim that you wrote the original software. If you use this software in + * a product, an acknowledgment in the product documentation would be + * appreciated but is not required. + * + * 2. Altered source version must be plainly marked as such, and must not be + * misrepresented as being original software. + * + * 3. This notice may not be removed or altered from any source distribution. + * + * + * Notes: + * + * A plugin to read targa (TGA) image files into an OpenGL-compatible RGBA + * format, header file. + * + * Written by Joshua S. English. + * + * + * The TARGA Specification: + * + * Position: Length: Description: + * -------- ------ ----------- + * 0 1 length of the image ID + * 1 1 type of color map included (if any) + * 0 => no color map + * 1 => has color map + * 2 1 image type + * 0 => no image data + * 1 => color-mapped image + * 2 => true-color image + * 3 => black & white image + * 9 => RLE color-mapped image + * 10 => RLE true-color image + * 11 => RLE black & white image + * 3 2 index of the first color-map entry as an offest + * into the color-map table + * 5 2 color-map length (number of entries) + * 7 1 color-map entry length - (number of bits per entry) + * 8 2 x-origin of image + * 10 2 y-origin of image + * 12 2 image width in pixels + * 14 2 image height in pixels + * 16 1 pixel depth - the number of bits per pixel + * 17 1 image descriptor + * n var image id - only exists if non-zero + * n var color-map data - only exists if non-zero + * n var image data + */ + +#if !defined(_TARGA_H) + +#define _TARGA_H + + +// define targa public constants + +#define TARGA_COLOR_RED 1 +#define TARGA_COLOR_GREEN 2 +#define TARGA_COLOR_BLUE 3 +#define TARGA_COLOR_ALPHA 4 + + +// define targa public data types + +typedef struct _Targa { + int width; + int height; + int imageLength; + unsigned char *image; +} Targa; + + +// declare targa public functions + +/** + * targa_init() + * + * Initilize the Targa structure for utilization. + * + * @param targa(in) The Targa struct to initialize. + * + * @return An integer where zero is pass, less than zero is failure. + */ +int targa_init(Targa *targa); + + +/** + * targa_free() + * + * Free the Targa structure. + * + * @param targa(in) The Targa struct to free. + * + * @return An integer where zero is pass, less than zero is failure. + */ +int targa_free(Targa *targa); + + +/** + * targa_getDimensions() + * + * Obtain the width and height in pixels of a loaded Targa image. + * + * @param targa(in) The Targa struct of a loaded image. + * + * @param width(out) The width in pixels of a loaded Targa image. + * + * @param height(out) The height in pixels of a loaded Targa image. + * + * @return An integer where zero is pass, less than zero is failure. + */ +int targa_getDimensions(Targa *targa, int *width, int *height); + + +/** + * targa_getImageLength() + * + * Obtain the length in bytes of the serialized RGBA image. + * + * @param targa(in) The Targa struct of a loaded image. + * + * @param imageLength(out) The length in bytes of the RGBA image. + * + * @return An integer where zero is pass, less than zero is failure. + */ +int targa_getImageLength(Targa *targa, int *imageLength); + + +/** + * targa_getRgbaTexture() + * + * Obtain the serialized RGBA texture and its' length from a Targa image. + * + * @param targa(in) The Targa struct of a loaded image. + * + * @param texture(out) The serialized RGBA image pointer. + * + * @param textureLength(out) The serialized RGBA image length in bytes. + * + * @return An integer where zero is pass, less than zero is failure. + */ +int targa_getRgbaTexture(Targa *targa, char **texture, int *textureLength); + + +/** + * targa_loadFromFile() + * + * Load a targa file and decode it into a 32-bit RGBA serialized image. + * + * @param targa(in) The Targa struct of an image to load. + * + * @param filename(in) The filename of the image to load. + * + * @return An integer where zero is pass, less than zero is failure. + */ +int targa_loadFromFile(Targa *targa, char *filename); + + +/** + * targa_loadFromData() + * + * Load the targa from an in-memory location and decode it into a 32-bit RGBA + * serialize image. + * + * @param targa(in) The Targa struct an image to load. + * + * @param data(in) A pointer to an in-memory location containing a + * Targa image. + * + * @param dataLength(in) The length of the Targa in-memory image. + * + * @return An integer where zero is pass, less than zero is failure. + */ +int targa_loadFromData(Targa *targa, unsigned char *data, int dataLength); + + +/** + * targa_applyRgbaMask() + * + * Apply a red, green, blue or alpha-channel additive color-mask to a loaded + * Targa image. + * + * @param targa(in) The Targa struct of a loaded image. + * + * @param colorType(in) The color channel to mask. + * + * @param value(in) The color code (0 - 255) to mask. + * + * @return An integer where zero is pass, less than zero is failure. + */ +int targa_applyRgbaMask(Targa *targa, int colorType, unsigned char value); + + +/** + * targa_setRgbaChannel() + * + * Apply a red, green, blue or alpha-channel additive color-channel + * replacement to a loaded Targa image. + * + * @param targa(in) The Targa struct of a loaded image. + * + * @param colorType(in) The color channel to replace. + * + * @param value(in) The color code (0 - 255) to replace. + * + * @return An integer where zero is pass, less than zero is failure. + */ +int targa_setRgbaChannel(Targa *targa, int colorType, unsigned char value); + + +#endif // _TARGA_H + From eeb4a995fcae8d35eed65e627a35ee349660f091 Mon Sep 17 00:00:00 2001 From: Pavel Krajcevski Date: Tue, 19 Nov 2013 13:55:21 -0500 Subject: [PATCH 08/20] Hold on to the raw file data once its been loaded. --- IO/include/ImageFile.h | 7 +++++-- IO/src/ImageFile.cpp | 40 +++++++++++++++++++++++++++------------- 2 files changed, 32 insertions(+), 15 deletions(-) diff --git a/IO/include/ImageFile.h b/IO/include/ImageFile.h index 6c2bbfe..5c222f8 100644 --- a/IO/include/ImageFile.h +++ b/IO/include/ImageFile.h @@ -91,12 +91,15 @@ public: const EImageFileFormat m_FileFormat; + uint8 *m_FileData; + int32 m_FileDataSz; + FasTC::Image<> *m_Image; - static unsigned char *ReadFileData(const CHAR *filename); + 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 unsigned char *rawImageData) const; + FasTC::Image<> *LoadImage() const; }; #endif // _IMAGE_FILE_H_ diff --git a/IO/src/ImageFile.cpp b/IO/src/ImageFile.cpp index c38cc6c..6c3adfd 100644 --- a/IO/src/ImageFile.cpp +++ b/IO/src/ImageFile.cpp @@ -93,6 +93,8 @@ static inline T abs(const T &a) { ImageFile::ImageFile(const CHAR *filename) : m_FileFormat( DetectFileFormat(filename) ) + , m_FileData(NULL) + , m_FileDataSz(-1) , m_Image(NULL) { strncpy(m_Filename, filename, kMaxFilenameSz); @@ -100,6 +102,8 @@ ImageFile::ImageFile(const CHAR *filename) ImageFile::ImageFile(const CHAR *filename, EImageFileFormat format) : m_FileFormat(format) + , m_FileData(NULL) + , m_FileDataSz(-1) , m_Image(NULL) { strncpy(m_Filename, filename, kMaxFilenameSz); @@ -107,6 +111,8 @@ ImageFile::ImageFile(const CHAR *filename, EImageFileFormat format) ImageFile::ImageFile(const char *filename, EImageFileFormat format, const FasTC::Image<> &image) : m_FileFormat(format) + , m_FileData(NULL) + , m_FileDataSz(-1) , m_Image(image.Clone()) { strncpy(m_Filename, filename, kMaxFilenameSz); @@ -117,6 +123,11 @@ ImageFile::~ImageFile() { delete m_Image; m_Image = NULL; } + + if(m_FileData) { + delete m_FileData; + m_FileData = NULL; + } } bool ImageFile::Load() { @@ -126,10 +137,13 @@ bool ImageFile::Load() { m_Image = NULL; } - unsigned char *rawData = ReadFileData(m_Filename); - if(rawData) { - m_Image = LoadImage(rawData); - delete [] rawData; + if(m_FileData) { + delete m_FileData; + m_FileData = NULL; + } + + if(ReadFileData(m_Filename)) { + m_Image = LoadImage(); } return m_Image != NULL; @@ -165,20 +179,20 @@ bool ImageFile::Write() { return true; } -FasTC::Image<> *ImageFile::LoadImage(const unsigned char *rawImageData) const { +FasTC::Image<> *ImageFile::LoadImage() const { ImageLoader *loader = NULL; switch(m_FileFormat) { #ifdef PNG_FOUND case eFileFormat_PNG: - loader = new ImageLoaderPNG(rawImageData); + loader = new ImageLoaderPNG(m_FileData); break; #endif // PNG_FOUND #ifdef PVRTEXLIB_FOUND case eFileFormat_PVR: - loader = new ImageLoaderPVR(rawImageData); + loader = new ImageLoaderPVR(m_FileData); break; #endif // PVRTEXLIB_FOUND @@ -246,7 +260,7 @@ EImageFileFormat ImageFile::DetectFileFormat(const CHAR *filename) { return kNumImageFileFormats; } -unsigned char *ImageFile::ReadFileData(const CHAR *filename) { +bool ImageFile::ReadFileData(const CHAR *filename) { FileStream fstr (filename, eFileMode_ReadBinary); if(fstr.Tell() < 0) { fprintf(stderr, "Error opening file for reading: %s\n", filename); @@ -258,7 +272,7 @@ unsigned char *ImageFile::ReadFileData(const CHAR *filename) { uint32 fileSize = fstr.Tell(); // Allocate data for file contents - unsigned char *rawData = new unsigned char[fileSize]; + m_FileData = new unsigned char[fileSize]; // Return stream to beginning of file fstr.Seek(0, FileStream::eSeekPosition_Beginning); @@ -268,7 +282,7 @@ unsigned char *ImageFile::ReadFileData(const CHAR *filename) { uint64 totalBytesRead = 0; uint64 totalBytesLeft = fileSize; int32 bytesRead; - while((bytesRead = fstr.Read(rawData, uint32(fileSize))) > 0) { + while((bytesRead = fstr.Read(m_FileData, uint32(fileSize))) > 0) { totalBytesRead += bytesRead; totalBytesLeft -= bytesRead; } @@ -276,11 +290,11 @@ unsigned char *ImageFile::ReadFileData(const CHAR *filename) { if(totalBytesRead != fileSize) { assert(!"We didn't read as much data as we thought we had!"); fprintf(stderr, "Internal error: Incorrect file size assumption\n"); - return 0; + return false; } - // Return the data.. - return rawData; + m_FileDataSz = fileSize; + return true; } bool ImageFile::WriteImageDataToFile(const uint8 *data, From 4fc8bf916f4703f0f702c8db2302a779aba79650 Mon Sep 17 00:00:00 2001 From: Pavel Krajcevski Date: Tue, 19 Nov 2013 14:07:45 -0500 Subject: [PATCH 09/20] Add extern C --- IO/third_party/tga/targa.h | 7 ++++++- 1 file changed, 6 insertions(+), 1 deletion(-) diff --git a/IO/third_party/tga/targa.h b/IO/third_party/tga/targa.h index dffea51..5feed67 100755 --- a/IO/third_party/tga/targa.h +++ b/IO/third_party/tga/targa.h @@ -74,7 +74,6 @@ #define TARGA_COLOR_BLUE 3 #define TARGA_COLOR_ALPHA 4 - // define targa public data types typedef struct _Targa { @@ -84,6 +83,9 @@ typedef struct _Targa { unsigned char *image; } Targa; +#ifdef __cplusplus +extern "C" { +#endif // declare targa public functions @@ -222,6 +224,9 @@ int targa_applyRgbaMask(Targa *targa, int colorType, unsigned char value); */ int targa_setRgbaChannel(Targa *targa, int colorType, unsigned char value); +#ifdef __cplusplus +} // extern "C" +#endif #endif // _TARGA_H From 5b165e7d7bfc8f3ca2f2f2f92cf554a53251e040 Mon Sep 17 00:00:00 2001 From: Pavel Krajcevski Date: Tue, 19 Nov 2013 14:08:59 -0500 Subject: [PATCH 10/20] Create imageloader constructor that keeps track of filesize. --- IO/config/ImageLoader.h.in | 13 +++++++++++++ 1 file changed, 13 insertions(+) diff --git a/IO/config/ImageLoader.h.in b/IO/config/ImageLoader.h.in index 5654af1..1a50c37 100644 --- a/IO/config/ImageLoader.h.in +++ b/IO/config/ImageLoader.h.in @@ -52,6 +52,7 @@ class ImageLoader { protected: const uint8 *const m_RawData; + const int32 m_NumRawDataBytes; uint8 *m_PixelData; uint32 m_Width; @@ -71,6 +72,18 @@ class ImageLoader { ImageLoader(const uint8 *rawData) : m_RawData(rawData) + , m_NumRawDataBytes(-1) + , m_PixelData(0) + , m_Width(0), m_Height(0) + , m_RedChannelPrecision(0), m_RedData(0) + , m_GreenChannelPrecision(0), m_GreenData(0) + , m_BlueChannelPrecision(0), m_BlueData(0) + , m_AlphaChannelPrecision(0), m_AlphaData(0) + { } + + ImageLoader(const uint8 *rawData, const int32 numBytes) + : m_RawData(rawData) + , m_NumRawDataBytes(numBytes) , m_PixelData(0) , m_Width(0), m_Height(0) , m_RedChannelPrecision(0), m_RedData(0) From 958c8909a4a0b59d91542aeb6e09b8deea690b79 Mon Sep 17 00:00:00 2001 From: Pavel Krajcevski Date: Tue, 19 Nov 2013 14:20:37 -0500 Subject: [PATCH 11/20] const-guard a few functions --- IO/third_party/tga/targa.c | 4 ++-- IO/third_party/tga/targa.h | 2 +- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/IO/third_party/tga/targa.c b/IO/third_party/tga/targa.c index 36313e2..a4c66c9 100755 --- a/IO/third_party/tga/targa.c +++ b/IO/third_party/tga/targa.c @@ -254,7 +254,7 @@ int targa_loadFromFile(Targa *targa, char *filename) return rc; } -int targa_loadFromData(Targa *targa, unsigned char *data, int dataLength) +int targa_loadFromData(Targa *targa, const unsigned char *data, int dataLength) { short sNumber = 0; int ii = 0; @@ -268,7 +268,7 @@ int targa_loadFromData(Targa *targa, unsigned char *data, int dataLength) int rleId = 0; int pixel[4]; unsigned char *imageId = NULL; - unsigned char *ptr = NULL; + const unsigned char *ptr = NULL; if((targa == NULL) || (data == NULL) || (dataLength < 18)) { fprintf(stderr, "[%s():%i] error - invalid or missing argument(s).\n", diff --git a/IO/third_party/tga/targa.h b/IO/third_party/tga/targa.h index 5feed67..20da7a4 100755 --- a/IO/third_party/tga/targa.h +++ b/IO/third_party/tga/targa.h @@ -188,7 +188,7 @@ int targa_loadFromFile(Targa *targa, char *filename); * * @return An integer where zero is pass, less than zero is failure. */ -int targa_loadFromData(Targa *targa, unsigned char *data, int dataLength); +int targa_loadFromData(Targa *targa, const unsigned char *data, int dataLength); /** From cf4868fdb1e9b90771d5e8be330119badcb527ba Mon Sep 17 00:00:00 2001 From: Pavel Krajcevski Date: Tue, 19 Nov 2013 14:21:54 -0500 Subject: [PATCH 12/20] Abstract away generic function to read from 32-bit pixel buffer. --- IO/config/ImageLoader.h.in | 2 ++ IO/src/ImageLoader.cpp | 21 +++++++++++++++++++++ IO/src/ImageLoaderPVR.cpp | 20 +------------------- 3 files changed, 24 insertions(+), 19 deletions(-) diff --git a/IO/config/ImageLoader.h.in b/IO/config/ImageLoader.h.in index 1a50c37..6250e0f 100644 --- a/IO/config/ImageLoader.h.in +++ b/IO/config/ImageLoader.h.in @@ -94,6 +94,8 @@ class ImageLoader { uint32 GetChannelForPixel(uint32 x, uint32 y, uint32 ch); + bool LoadFromPixelBuffer(uint32 *data); + public: virtual ~ImageLoader() { if(m_RedData) { diff --git a/IO/src/ImageLoader.cpp b/IO/src/ImageLoader.cpp index d2a2155..f2bbed0 100644 --- a/IO/src/ImageLoader.cpp +++ b/IO/src/ImageLoader.cpp @@ -137,6 +137,27 @@ unsigned int ImageLoader::GetChannelForPixel(uint32 x, uint32 y, uint32 ch) { return val; } +bool ImageLoader::LoadFromPixelBuffer(uint32 *data) { + const int nPixels = m_Width * m_Height; + m_RedData = new uint8[nPixels]; + m_GreenData = new uint8[nPixels]; + m_BlueData = new uint8[nPixels]; + m_AlphaData = new uint8[nPixels]; + + for (uint32 i = 0; i < m_Width; i++) { + for (uint32 j = 0; j < m_Height; j++) { + uint32 idx = j*m_Height + i; + uint32 pixel = data[idx]; + m_RedData[idx] = pixel & 0xFF; + m_GreenData[idx] = (pixel >> 8) & 0xFF; + m_BlueData[idx] = (pixel >> 16) & 0xFF; + m_AlphaData[idx] = (pixel >> 24) & 0xFF; + } + } + + return true; +} + bool ImageLoader::LoadImage() { // Do we already have pixel data? diff --git a/IO/src/ImageLoaderPVR.cpp b/IO/src/ImageLoaderPVR.cpp index ee34e0e..765c9b4 100644 --- a/IO/src/ImageLoaderPVR.cpp +++ b/IO/src/ImageLoaderPVR.cpp @@ -84,24 +84,6 @@ bool ImageLoaderPVR::ReadData() { m_Width = hdr.getWidth(); m_Height = hdr.getHeight(); - const int nPixels = m_Width * m_Height; - m_RedData = new uint8[nPixels]; - m_GreenData = new uint8[nPixels]; - m_BlueData = new uint8[nPixels]; - m_AlphaData = new uint8[nPixels]; - - uint32 *data = (uint32 *)(pvrTex.getDataPtr()); - for (uint32 i = 0; i < m_Width; i++) { - for (uint32 j = 0; j < m_Height; j++) { - uint32 idx = j*m_Height + i; - uint32 pixel = data[idx]; - m_RedData[idx] = pixel & 0xFF; - m_GreenData[idx] = (pixel >> 8) & 0xFF; - m_BlueData[idx] = (pixel >> 16) & 0xFF; - m_AlphaData[idx] = (pixel >> 24) & 0xFF; - } - } - - return true; + return LoadFromPixelBuffer(reinterpret_cast(pvrTex.getDataPtr())); } From b6fde9c3f516046d41810f4ac2a0e7bf95877f26 Mon Sep 17 00:00:00 2001 From: Pavel Krajcevski Date: Tue, 19 Nov 2013 14:22:26 -0500 Subject: [PATCH 13/20] Add TGA image loaders --- IO/CMakeLists.txt | 4 ++ IO/include/ImageFileFormat.h | 1 + IO/src/ImageFile.cpp | 6 +++ IO/src/ImageLoaderTGA.cpp | 85 ++++++++++++++++++++++++++++++++++++ IO/src/ImageLoaderTGA.h | 66 ++++++++++++++++++++++++++++ 5 files changed, 162 insertions(+) create mode 100644 IO/src/ImageLoaderTGA.cpp create mode 100644 IO/src/ImageLoaderTGA.h diff --git a/IO/CMakeLists.txt b/IO/CMakeLists.txt index 520539b..58b4046 100644 --- a/IO/CMakeLists.txt +++ b/IO/CMakeLists.txt @@ -83,6 +83,10 @@ SET( SOURCES ${SOURCES} "third_party/tga/targa.c" ) SET( HEADERS ${HEADERS} "third_party/tga/targa.h" ) INCLUDE_DIRECTORIES( ${FasTC_SOURCE_DIR}/IO/third_party/tga ) +# Add TGA loaders +SET( SOURCES ${SOURCES} "src/ImageLoaderTGA.cpp" ) +SET( HEADERS ${HEADERS} "src/ImageLoaderTGA.h" ) + CONFIGURE_FILE( "config/ImageLoader.h.in" "include/ImageLoader.h" diff --git a/IO/include/ImageFileFormat.h b/IO/include/ImageFileFormat.h index 48b262b..6035a81 100644 --- a/IO/include/ImageFileFormat.h +++ b/IO/include/ImageFileFormat.h @@ -47,6 +47,7 @@ enum EImageFileFormat { eFileFormat_PNG, eFileFormat_PVR, + eFileFormat_TGA, kNumImageFileFormats }; diff --git a/IO/src/ImageFile.cpp b/IO/src/ImageFile.cpp index 6c3adfd..6b62043 100644 --- a/IO/src/ImageFile.cpp +++ b/IO/src/ImageFile.cpp @@ -65,6 +65,8 @@ # include "ImageLoaderPVR.h" #endif +#include "ImageLoaderTGA.h" + ////////////////////////////////////////////////////////////////////////////////////////// // // Static helper functions @@ -196,6 +198,10 @@ FasTC::Image<> *ImageFile::LoadImage() const { break; #endif // PVRTEXLIB_FOUND + case eFileFormat_TGA: + loader = new ImageLoaderTGA(m_FileData, m_FileDataSz); + break; + default: fprintf(stderr, "Unable to load image: unknown file format.\n"); return NULL; diff --git a/IO/src/ImageLoaderTGA.cpp b/IO/src/ImageLoaderTGA.cpp new file mode 100644 index 0000000..b50c2fb --- /dev/null +++ b/IO/src/ImageLoaderTGA.cpp @@ -0,0 +1,85 @@ +/* FasTC + * Copyright (c) 2013 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 "ImageLoaderTGA.h" + +#include +#include +#include +#include + +#include "TexCompTypes.h" + +#include "targa.h" + +static void ReportError(const char *msg) { + fprintf(stderr, "ERROR: ImageLoaderTGA -- %s\n", msg); +} + +ImageLoaderTGA::ImageLoaderTGA(const uint8 *rawData, const int32 rawDataSz) + : ImageLoader(rawData, rawDataSz) +{ } + +ImageLoaderTGA::~ImageLoaderTGA() { } + +bool ImageLoaderTGA::ReadData() { + Targa tga; + targa_loadFromData(&tga, m_RawData, m_NumRawDataBytes); + + m_Width = tga.width; + m_Height = tga.height; + + assert(tga.imagelength == m_Width * m_Height * 4); + + return LoadFromPixelBuffer(reinterpret_cast(tga.image)); +} + diff --git a/IO/src/ImageLoaderTGA.h b/IO/src/ImageLoaderTGA.h new file mode 100644 index 0000000..df68db0 --- /dev/null +++ b/IO/src/ImageLoaderTGA.h @@ -0,0 +1,66 @@ +/* FasTC + * Copyright (c) 2013 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_IMAGELOADERTGA_H_ +#define IO_SRC_IMAGELOADERTGA_H_ + +#include "ImageLoader.h" + +class ImageLoaderTGA : public ImageLoader { + public: + ImageLoaderTGA(const uint8 *rawData, const int32 rawDataSz); + virtual ~ImageLoaderTGA(); + + virtual bool ReadData(); +}; + +#endif // IO_SRC_IMAGELOADERTGA_H_ From 7359f9e7581f64f29c592663f114b2c5a888ef4b Mon Sep 17 00:00:00 2001 From: Pavel Krajcevski Date: Tue, 19 Nov 2013 14:54:59 -0500 Subject: [PATCH 14/20] Some compilers treat hex literals as unsigned, which causes problems --- BPTCEncoder/src/BC7Compressor.cpp | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/BPTCEncoder/src/BC7Compressor.cpp b/BPTCEncoder/src/BC7Compressor.cpp index 9586f98..9219118 100755 --- a/BPTCEncoder/src/BC7Compressor.cpp +++ b/BPTCEncoder/src/BC7Compressor.cpp @@ -1016,10 +1016,11 @@ double BC7CompressionMode::CompressCluster( a2 = std::min(255.0f, std::max(0.0f, a2)); // Quantize + const int8 maskSeed = 0x80; const uint8 a1b = ::QuantizeChannel( - uint8(a1), (0x80 >> (GetAlphaChannelPrecision() - 1))); + uint8(a1), (maskSeed >> (GetAlphaChannelPrecision() - 1))); const uint8 a2b = ::QuantizeChannel( - uint8(a2), (0x80 >> (GetAlphaChannelPrecision() - 1))); + uint8(a2), (maskSeed >> (GetAlphaChannelPrecision() - 1))); // Compute error alphaError = 0.0; From e780560d1e038eaf69b15598ae7d6f76966482d3 Mon Sep 17 00:00:00 2001 From: Pavel Krajcevski Date: Tue, 19 Nov 2013 14:55:41 -0500 Subject: [PATCH 15/20] Move default bit depth definitions to abstracted pixel buffer loading function. --- IO/src/ImageLoader.cpp | 5 +++++ IO/src/ImageLoaderPVR.cpp | 5 ----- 2 files changed, 5 insertions(+), 5 deletions(-) diff --git a/IO/src/ImageLoader.cpp b/IO/src/ImageLoader.cpp index f2bbed0..8208ebc 100644 --- a/IO/src/ImageLoader.cpp +++ b/IO/src/ImageLoader.cpp @@ -138,6 +138,11 @@ unsigned int ImageLoader::GetChannelForPixel(uint32 x, uint32 y, uint32 ch) { } bool ImageLoader::LoadFromPixelBuffer(uint32 *data) { + m_RedChannelPrecision = 8; + m_GreenChannelPrecision = 8; + m_BlueChannelPrecision = 8; + m_AlphaChannelPrecision = 8; + const int nPixels = m_Width * m_Height; m_RedData = new uint8[nPixels]; m_GreenData = new uint8[nPixels]; diff --git a/IO/src/ImageLoaderPVR.cpp b/IO/src/ImageLoaderPVR.cpp index 765c9b4..5ec9e98 100644 --- a/IO/src/ImageLoaderPVR.cpp +++ b/IO/src/ImageLoaderPVR.cpp @@ -74,11 +74,6 @@ bool ImageLoaderPVR::ReadData() { return false; } - m_RedChannelPrecision = 8; - m_GreenChannelPrecision = 8; - m_BlueChannelPrecision = 8; - m_AlphaChannelPrecision = 8; - const pvrtexture::CPVRTextureHeader &hdr = pvrTex.getHeader(); m_Width = hdr.getWidth(); From 325b04847e11dcbd62dc8290163a8c8d1db70ef9 Mon Sep 17 00:00:00 2001 From: Pavel Krajcevski Date: Tue, 19 Nov 2013 14:56:10 -0500 Subject: [PATCH 16/20] Remove some compiler cruft with our TGA loader. --- IO/src/ImageLoaderTGA.cpp | 6 +----- 1 file changed, 1 insertion(+), 5 deletions(-) diff --git a/IO/src/ImageLoaderTGA.cpp b/IO/src/ImageLoaderTGA.cpp index b50c2fb..5f04421 100644 --- a/IO/src/ImageLoaderTGA.cpp +++ b/IO/src/ImageLoaderTGA.cpp @@ -61,10 +61,6 @@ #include "targa.h" -static void ReportError(const char *msg) { - fprintf(stderr, "ERROR: ImageLoaderTGA -- %s\n", msg); -} - ImageLoaderTGA::ImageLoaderTGA(const uint8 *rawData, const int32 rawDataSz) : ImageLoader(rawData, rawDataSz) { } @@ -78,7 +74,7 @@ bool ImageLoaderTGA::ReadData() { m_Width = tga.width; m_Height = tga.height; - assert(tga.imagelength == m_Width * m_Height * 4); + assert(static_cast(tga.imageLength) == m_Width * m_Height * 4); return LoadFromPixelBuffer(reinterpret_cast(tga.image)); } From baced12633ebe5eaa5bfa9508b8f981546a7b99e Mon Sep 17 00:00:00 2001 From: Pavel Krajcevski Date: Tue, 19 Nov 2013 14:56:21 -0500 Subject: [PATCH 17/20] Add tga filename detection. --- IO/src/ImageFile.cpp | 3 +++ 1 file changed, 3 insertions(+) diff --git a/IO/src/ImageFile.cpp b/IO/src/ImageFile.cpp index 6b62043..5199cba 100644 --- a/IO/src/ImageFile.cpp +++ b/IO/src/ImageFile.cpp @@ -262,6 +262,9 @@ EImageFileFormat ImageFile::DetectFileFormat(const CHAR *filename) { else if(strcmp(ext, ".pvr") == 0) { return eFileFormat_PVR; } + else if(strcmp(ext, ".tga") == 0) { + return eFileFormat_TGA; + } return kNumImageFileFormats; } From 5d93d4d7e9d618a02a9cd535202ba3abdc337b84 Mon Sep 17 00:00:00 2001 From: Pavel Krajcevski Date: Tue, 19 Nov 2013 15:01:54 -0500 Subject: [PATCH 18/20] Add option to flip image along Y-axis to accomodate different image formats. --- IO/config/ImageLoader.h.in | 2 +- IO/src/ImageLoader.cpp | 13 ++++++++----- IO/src/ImageLoaderTGA.cpp | 2 +- 3 files changed, 10 insertions(+), 7 deletions(-) diff --git a/IO/config/ImageLoader.h.in b/IO/config/ImageLoader.h.in index 6250e0f..971bb89 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 LoadFromPixelBuffer(uint32 *data, bool flipY = false); public: virtual ~ImageLoader() { diff --git a/IO/src/ImageLoader.cpp b/IO/src/ImageLoader.cpp index 8208ebc..37df083 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 ImageLoader::LoadFromPixelBuffer(uint32 *data, bool flipY) { m_RedChannelPrecision = 8; m_GreenChannelPrecision = 8; m_BlueChannelPrecision = 8; @@ -152,11 +152,14 @@ bool ImageLoader::LoadFromPixelBuffer(uint32 *data) { for (uint32 i = 0; i < m_Width; i++) { for (uint32 j = 0; j < m_Height; j++) { uint32 idx = j*m_Height + i; + uint32 pIdx = idx; + if(flipY) + idx = (m_Height - j - 1)*m_Height + i; uint32 pixel = data[idx]; - m_RedData[idx] = pixel & 0xFF; - m_GreenData[idx] = (pixel >> 8) & 0xFF; - m_BlueData[idx] = (pixel >> 16) & 0xFF; - m_AlphaData[idx] = (pixel >> 24) & 0xFF; + m_RedData[pIdx] = pixel & 0xFF; + m_GreenData[pIdx] = (pixel >> 8) & 0xFF; + m_BlueData[pIdx] = (pixel >> 16) & 0xFF; + m_AlphaData[pIdx] = (pixel >> 24) & 0xFF; } } diff --git a/IO/src/ImageLoaderTGA.cpp b/IO/src/ImageLoaderTGA.cpp index 5f04421..4f0ab09 100644 --- a/IO/src/ImageLoaderTGA.cpp +++ b/IO/src/ImageLoaderTGA.cpp @@ -76,6 +76,6 @@ bool ImageLoaderTGA::ReadData() { assert(static_cast(tga.imageLength) == m_Width * m_Height * 4); - return LoadFromPixelBuffer(reinterpret_cast(tga.image)); + return LoadFromPixelBuffer(reinterpret_cast(tga.image), true); } From 3734d643a65f452e74d7f97ace7b0a2c47d3022c Mon Sep 17 00:00:00 2001 From: Pavel Krajcevski Date: Mon, 2 Dec 2013 12:52:44 -0500 Subject: [PATCH 19/20] Fix some compiler warnings on MSVC --- BPTCEncoder/src/BC7Compressor.cpp | 2 +- IO/third_party/tga/targa.c | 5 +++++ 2 files changed, 6 insertions(+), 1 deletion(-) diff --git a/BPTCEncoder/src/BC7Compressor.cpp b/BPTCEncoder/src/BC7Compressor.cpp index 9219118..1332cc4 100755 --- a/BPTCEncoder/src/BC7Compressor.cpp +++ b/BPTCEncoder/src/BC7Compressor.cpp @@ -1016,7 +1016,7 @@ double BC7CompressionMode::CompressCluster( a2 = std::min(255.0f, std::max(0.0f, a2)); // Quantize - const int8 maskSeed = 0x80; + const int8 maskSeed = -0x7F; const uint8 a1b = ::QuantizeChannel( uint8(a1), (maskSeed >> (GetAlphaChannelPrecision() - 1))); const uint8 a2b = ::QuantizeChannel( diff --git a/IO/third_party/tga/targa.c b/IO/third_party/tga/targa.c index a4c66c9..04f0a7c 100755 --- a/IO/third_party/tga/targa.c +++ b/IO/third_party/tga/targa.c @@ -33,6 +33,11 @@ // preprocessor directives +#ifdef _MSC_VER +# define WIN32_LEAN_AND_MEAN +# define _CRT_SECURE_NO_WARNINGS +#endif + #include #include #include From f2c153febadcaab272f7cfa323c3c5edbd170fe1 Mon Sep 17 00:00:00 2001 From: Pavel Krajcevski Date: Mon, 9 Dec 2013 11:45:57 -0500 Subject: [PATCH 20/20] Add a command line switch to not produce decompressed output --- CLTool/src/tc.cpp | 56 +++++++++++++++++++++++++++++++++++++---------- 1 file changed, 44 insertions(+), 12 deletions(-) diff --git a/CLTool/src/tc.cpp b/CLTool/src/tc.cpp index 234e931..fb02d98 100644 --- a/CLTool/src/tc.cpp +++ b/CLTool/src/tc.cpp @@ -75,8 +75,10 @@ void PrintUsage() { fprintf(stderr, "Usage: tc [OPTIONS] imagefile\n"); fprintf(stderr, "\n"); fprintf(stderr, "\t-v\t\tVerbose mode: prints out Entropy, Mean Local Entropy, and MSSIM\n"); - fprintf(stderr, "\t-f\t\tFormat to use. Either \"BPTC\", \"ETC1\", \"DXT1\", \"DXT5\", or \"PVRTC\". Default: BPTC\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-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"); fprintf(stderr, "\t-simd\t\tUse SIMD compression path\n"); @@ -113,6 +115,8 @@ int main(int argc, char **argv) { exit(1); } + char decompressedOutput[256]; decompressedOutput[0] = '\0'; + bool bNoDecompress = false; int numJobs = 0; int quality = 50; int numThreads = 1; @@ -171,6 +175,30 @@ int main(int argc, char **argv) { continue; } + if(strcmp(argv[fileArg], "-d") == 0) { + fileArg++; + + if(fileArg == argc) { + PrintUsage(); + exit(1); + } else { + size_t sz = 255; + sz = ::std::min(sz, static_cast(strlen(argv[fileArg]))); + memcpy(decompressedOutput, argv[fileArg], sz + 1); + } + + fileArg++; + knowArg = true; + continue; + } + + if(strcmp(argv[fileArg], "-nd") == 0) { + fileArg++; + bNoDecompress = true; + knowArg = true; + continue; + } + if(strcmp(argv[fileArg], "-l") == 0) { fileArg++; bSaveLog = true; @@ -309,18 +337,22 @@ int main(int argc, char **argv) { } } - if(format == FasTC::eCompressionFormat_BPTC) { - strcat(basename, "-bc7.png"); - } else if(format == FasTC::eCompressionFormat_PVRTC) { - strcat(basename, "-pvrtc.png"); - } else if(format == FasTC::eCompressionFormat_DXT1) { - strcat(basename, "-dxt1.png"); - } else if(format == FasTC::eCompressionFormat_ETC1) { - strcat(basename, "-etc1.png"); - } + if(!bNoDecompress) { + if(decompressedOutput[0] != '\0') { + memcpy(basename, decompressedOutput, 256); + } else if(format == FasTC::eCompressionFormat_BPTC) { + strcat(basename, "-bc7.png"); + } else if(format == FasTC::eCompressionFormat_PVRTC) { + strcat(basename, "-pvrtc.png"); + } else if(format == FasTC::eCompressionFormat_DXT1) { + strcat(basename, "-dxt1.png"); + } else if(format == FasTC::eCompressionFormat_ETC1) { + strcat(basename, "-etc1.png"); + } - ImageFile cImgFile (basename, eFileFormat_PNG, *ci); - cImgFile.Write(); + ImageFile cImgFile (basename, eFileFormat_PNG, *ci); + cImgFile.Write(); + } // Cleanup delete ci;