diff --git a/.travis.yml b/.travis.yml new file mode 100644 index 0000000..22474a8 --- /dev/null +++ b/.travis.yml @@ -0,0 +1,16 @@ +language: cpp +git: + submodules: false + +compiler: + - gcc + - clang + +before_script: + - mkdir build + - cd build + - cmake .. -DCMAKE_BUILD_TYPE=Release + +script: make && make test + +after_failure: if [ -d Testing ]; then cat Testing/Temporary/LastTest.log; fi \ No newline at end of file diff --git a/Base/include/MatrixSquare.h b/Base/include/MatrixSquare.h index df887b0..99edeca 100644 --- a/Base/include/MatrixSquare.h +++ b/Base/include/MatrixSquare.h @@ -73,7 +73,7 @@ namespace FasTC { // principal eigenvector. However, that may be due to // poor initialization of the random vector, so rerandomize // and try again. - const float newBlen = newB.Length(); + const T newBlen = newB.Length(); if(newBlen < 1e-10) { if(badEigenValue) { eigVec = b; diff --git a/Base/include/VectorBase.h b/Base/include/VectorBase.h index e313b90..945e176 100644 --- a/Base/include/VectorBase.h +++ b/Base/include/VectorBase.h @@ -94,7 +94,8 @@ namespace FasTC { } T LengthSq() const { return this->Dot(*this); } - T Length() const { return sqrt(LengthSq()); } + T Length() const { return static_cast( + sqrt(static_cast(LengthSq())));} void Normalize() { T len = Length(); @@ -110,7 +111,7 @@ namespace FasTC { const VectorTypeTwo &v2) { VectorTypeOne a(v1); for(int i = 0; i < VectorTypeOne::Size; i++) { - a(i) += v2[i]; + a(i) += static_cast(v2[i]); } return a; } @@ -132,7 +133,7 @@ namespace FasTC { const VectorTypeTwo &v2) { VectorTypeOne a(v1); for(int i = 0; i < VectorTypeOne::Size; i++) { - a(i) -= v2[i]; + a(i) -= static_cast(v2[i]); } return a; } @@ -183,9 +184,10 @@ namespace FasTC { return a; } + // !WTF! MSVC bug with enums in template parameters =( template< - EVectorType kVectorTypeOne, - EVectorType kVectorTypeTwo, + /* EVectorType */unsigned kVectorTypeOne, + /* EVectorType */unsigned kVectorTypeTwo, typename TypeOne, typename TypeTwo> class MultSwitch { diff --git a/Base/test/TestMatrix.cpp b/Base/test/TestMatrix.cpp index 55a4aa9..089c3a0 100644 --- a/Base/test/TestMatrix.cpp +++ b/Base/test/TestMatrix.cpp @@ -53,13 +53,28 @@ #include "gtest/gtest.h" #include "MatrixBase.h" -static const float kEpsilon = 1e-6; +static const float kEpsilon = 1e-6f; TEST(MatrixBase, Constructors) { FasTC::MatrixBase m3f; + for(int j = 0; j < 3; j++) + for(int i = 0; i < 4; i++) + m3f[j*4+i] = static_cast(i) / static_cast(j+1); + FasTC::MatrixBase m1d; + for(int j = 0; j < 1; j++) + for(int i = 0; i < 1; i++) + m1d[j*1+i] = 0.0; + FasTC::MatrixBase m7i; + for(int j = 0; j < 7; j++) + for(int i = 0; i < 200; i++) + m7i[j*200+i] = i*j; + FasTC::MatrixBase m16u; + for(int j = 0; j < 16; j++) + for(int i = 0; i < 16; i++) + m16u[j*16+i] = j-i; #define TEST_VECTOR_COPY_CONS(mat, t, n, m) \ do { \ @@ -123,7 +138,7 @@ TEST(MatrixBase, PointerConversion) { } TEST(MatrixBase, CastVector) { - srand(time(NULL)); + srand(static_cast(time(NULL))); FasTC::MatrixBase v3f; for(int i = 0; i < 6; i++) { @@ -239,8 +254,8 @@ TEST(MatrixSquare, PowerMethod) { FasTC::VectorBase x; A.PowerMethod(x, &e, 20, 200); - EXPECT_NEAR(x[0], 0.83205f, 0.0001); - EXPECT_NEAR(x[1], 0.5547f, 0.0001); + EXPECT_NEAR(x[0], 0.83205f, 0.0002); + EXPECT_NEAR(x[1], 0.5547f, 0.0002); EXPECT_NEAR(e, 1.f, 0.0001); } diff --git a/Base/test/TestVector.cpp b/Base/test/TestVector.cpp index 7735fdc..b3d2176 100644 --- a/Base/test/TestVector.cpp +++ b/Base/test/TestVector.cpp @@ -53,13 +53,19 @@ #include "gtest/gtest.h" #include "VectorBase.h" -static const float kEpsilon = 1e-6; +static const float kEpsilon = 1e-6f; TEST(VectorBase, Constructors) { FasTC::VectorBase v3f; + v3f[0] = 1.1f; v3f[1] = 1.2f; v3f[2] = 1.3f; FasTC::VectorBase v1d; + v1d[0] = 1.1; FasTC::VectorBase v7i; + for(int i = 0; i < 7; i++) + v7i[i] = -i; FasTC::VectorBase v16u; + for(int i = 0; i < 7; i++) + v16u[i] = i; #define TEST_VECTOR_COPY_CONS(v, t, n) \ do { \ @@ -118,6 +124,10 @@ TEST(VectorBase, PointerConversion) { TEST(VectorBase, CastVector) { FasTC::VectorBase v3f; + v3f[0] = 1000000.0f; + v3f[1] = -2.0f; + v3f[2] = -1.1f; + FasTC::VectorBase v3d = v3f; FasTC::VectorBase v3i = v3f; for(int i = 0; i < 3; i++) { @@ -133,11 +143,11 @@ TEST(VectorBase, DotProduct) { unsigned uv[5] = { 1, 2, 3, 4, 5 }; FasTC::VectorBase v5u(uv); - EXPECT_EQ(v5i.Dot(v5u), 10); - EXPECT_EQ(v5u.Dot(v5i), 10); + EXPECT_EQ(v5i.Dot(v5u), static_cast(10)); + EXPECT_EQ(v5u.Dot(v5i), static_cast(10)); - EXPECT_EQ(v5i * v5u, 10); - EXPECT_EQ(v5u * v5i, 10); + EXPECT_EQ(v5i * v5u, static_cast(10)); + EXPECT_EQ(v5u * v5i, static_cast(10)); } TEST(VectorBase, Length) { @@ -166,10 +176,10 @@ TEST(VectorBase, Normalization) { unsigned uv[2] = {2, 2}; FasTC::VectorBase v2u (uv); v2u.Normalize(); - EXPECT_EQ(v2u[0], 1); - EXPECT_EQ(v2u[1], 1); + EXPECT_EQ(v2u[0], static_cast(1)); + EXPECT_EQ(v2u[1], static_cast(1)); - const float sqrt2 = sqrt(2)/2.0f; + const double sqrt2 = sqrt(2.0f)/2.0f; for(int i = 2; i < 10; i++) { v2f[0] = static_cast(i); v2f[1] = static_cast(i); @@ -197,12 +207,12 @@ TEST(VectorBase, Scaling) { unsigned uv[2] = {1, 3}; FasTC::VectorBase v2u (uv); FasTC::VectorBase v2ud = v2u * 0.5; - EXPECT_EQ(v2ud[0], 0); - EXPECT_EQ(v2ud[1], 1); + EXPECT_EQ(v2ud[0], static_cast(0)); + EXPECT_EQ(v2ud[1], static_cast(1)); v2ud = v2u / 0.5f; - EXPECT_EQ(v2ud[0], 2); - EXPECT_EQ(v2ud[1], 6); + EXPECT_EQ(v2ud[0], static_cast(2)); + EXPECT_EQ(v2ud[1], static_cast(6)); } TEST(VectorBase, Addition) { @@ -225,7 +235,7 @@ TEST(VectorBase, Addition) { EXPECT_NEAR(af[1], 5.2f, kEpsilon); au = v2u - v2f; - EXPECT_EQ(au[0], 3); + EXPECT_EQ(au[0], 4); EXPECT_EQ(au[1], -1); af = v2f - v2u; @@ -244,10 +254,12 @@ TEST(VectorBase, Addition) { TEST(Vector2, BaseFunctionality) { FasTC::Vec2f v2f; FasTC::Vec2d v2d; + v2d.X() = 3.0; + v2d.Y() = -10.0; v2f = v2d; - EXPECT_NEAR(v2f[0], v2d[0], kEpsilon); - EXPECT_NEAR(v2f[1], v2d[1], kEpsilon); + EXPECT_EQ(v2f[0], v2d[0]); + EXPECT_EQ(v2f[1], v2d[1]); } TEST(Vector2, Accessors) { @@ -300,10 +312,13 @@ TEST(Vector2, Swizzle) { TEST(Vector3, BaseFunctionality) { FasTC::Vec3f vf; FasTC::Vec3d vd; + vd.X() = 3.0; + vd.Y() = -10.0; + vd.Z() = 0.0; vf = vd; for(int i = 0; i < 3; i++) { - EXPECT_NEAR(vf[i], vd[i], kEpsilon); + EXPECT_EQ(vf[i], vd[i]); } } @@ -383,10 +398,14 @@ TEST(Vector3, CrossProduct) { TEST(Vector4, BaseFunctionality) { FasTC::Vec4f vf; FasTC::Vec4d vd; + vd.X() = 3.0; + vd.Y() = -10.0; + vd.Z() = 0.0; + vd.W() = 100000000.0; vf = vd; for(int i = 0; i < 4; i++) { - EXPECT_NEAR(vf[i], vd[i], kEpsilon); + EXPECT_EQ(vf[i], vd[i]); } } diff --git a/CLTool/src/compare.cpp b/CLTool/src/compare.cpp index c9982c4..46c91db 100644 --- a/CLTool/src/compare.cpp +++ b/CLTool/src/compare.cpp @@ -59,12 +59,7 @@ #include "TexComp.h" #include "ThreadSafeStreambuf.h" -#ifdef _MSC_VER -int _tmain(int argc, _TCHAR* argv[]) { -#else int main(int argc, char **argv) { -#endif - if(argc != 3) { fprintf(stderr, "Usage: compare \n"); return 1; @@ -82,8 +77,8 @@ int main(int argc, char **argv) { return 1; } - FasTC::Image<> img1(*img1f.GetImage()); - FasTC::Image<> img2(*img2f.GetImage()); + FasTC::Image<> &img1 = *img1f.GetImage(); + FasTC::Image<> &img2 = *img2f.GetImage(); double PSNR = img1.ComputePSNR(&img2); if(PSNR > 0.0) { diff --git a/IO/config/ImageLoader.h.in b/IO/config/ImageLoader.h.in index b65d23b..dd06cc1 100644 --- a/IO/config/ImageLoader.h.in +++ b/IO/config/ImageLoader.h.in @@ -46,6 +46,7 @@ #include "ImageFileFormat.h" #include "TexCompTypes.h" +#include "ImageFwd.h" class ImageLoader { @@ -142,7 +143,7 @@ class ImageLoader { uint32 GetHeight() const { return m_Height; } uint32 GetImageDataSz() const { return m_Width * m_Height * 4; } - bool LoadImage(); + virtual FasTC::Image<> *LoadImage(); const uint8 *GetImageData() const { return m_PixelData; } }; diff --git a/IO/src/GLDefines.h b/IO/src/GLDefines.h index b2a0662..2570a88 100644 --- a/IO/src/GLDefines.h +++ b/IO/src/GLDefines.h @@ -57,6 +57,11 @@ # ifdef __APPLE__ # include # else +# ifdef _MSC_VER +# define WIN32_LEAN_AND_MEAN +# include "Windows.h" +# undef LoadImage +# endif # include # endif #endif diff --git a/IO/src/ImageFile.cpp b/IO/src/ImageFile.cpp index 18d7602..60e4479 100644 --- a/IO/src/ImageFile.cpp +++ b/IO/src/ImageFile.cpp @@ -221,28 +221,13 @@ FasTC::Image<> *ImageFile::LoadImage() const { if(!loader) return NULL; - if(!(loader->LoadImage())) { + FasTC::Image<> *i = loader->LoadImage(); + if(i == NULL) { fprintf(stderr, "Unable to load image!\n"); - delete loader; - return NULL; } - uint8 *pixelData = NULL; - if(loader->GetImageData()) { - pixelData = new uint8[ loader->GetImageDataSz() ]; - if(!pixelData) { fprintf(stderr, "%s\n", "Out of memory!"); exit(1); } - memcpy(pixelData, loader->GetImageData(), loader->GetImageDataSz()); - } - else { - fprintf(stderr, "%s\n", "Failed to get data from image loader!"); - } - - uint32 *pixels = reinterpret_cast(pixelData); - FasTC::Image<> *i = new FasTC::Image<>(loader->GetWidth(), loader->GetHeight(), pixels); - // Cleanup delete loader; - delete [] pixelData; return i; } diff --git a/IO/src/ImageLoader.cpp b/IO/src/ImageLoader.cpp index b65bb94..1bed8e5 100644 --- a/IO/src/ImageLoader.cpp +++ b/IO/src/ImageLoader.cpp @@ -48,6 +48,7 @@ #include #include +#include "Image.h" /////////////////////////////////////////////////////////////////////////////// // // Static helper functions @@ -166,15 +167,17 @@ bool ImageLoader::LoadFromPixelBuffer(const uint32 *data, bool flipY) { return true; } -bool ImageLoader::LoadImage() { +FasTC::Image<> *ImageLoader::LoadImage() { // Do we already have pixel data? - if(m_PixelData) - return true; + if(m_PixelData) { + uint32 *pixels = reinterpret_cast(m_PixelData); + return new FasTC::Image<>(m_Width, m_Height, pixels); + } // Read the image data! if(!ReadData()) - return false; + return NULL; m_Width = GetWidth(); m_Height = GetHeight(); @@ -201,7 +204,7 @@ bool ImageLoader::LoadImage() { unsigned int redVal = GetChannelForPixel(i, j, 0); if(redVal == INT_MAX) - return false; + return NULL; unsigned int greenVal = redVal; unsigned int blueVal = redVal; @@ -209,20 +212,20 @@ bool ImageLoader::LoadImage() { if(GetGreenChannelPrecision() > 0) { greenVal = GetChannelForPixel(i, j, 1); if(greenVal == INT_MAX) - return false; + return NULL; } if(GetBlueChannelPrecision() > 0) { blueVal = GetChannelForPixel(i, j, 2); if(blueVal == INT_MAX) - return false; + return NULL; } unsigned int alphaVal = 0xFF; if(GetAlphaChannelPrecision() > 0) { alphaVal = GetChannelForPixel(i, j, 3); if(alphaVal == INT_MAX) - return false; + return NULL; } // Red channel @@ -239,5 +242,6 @@ bool ImageLoader::LoadImage() { } } - return true; + uint32 *pixels = reinterpret_cast(m_PixelData); + return new FasTC::Image<>(m_Width, m_Height, pixels); } diff --git a/IO/src/ImageLoaderKTX.cpp b/IO/src/ImageLoaderKTX.cpp index d1f1bd0..50f3511 100644 --- a/IO/src/ImageLoaderKTX.cpp +++ b/IO/src/ImageLoaderKTX.cpp @@ -62,6 +62,8 @@ #include "ScopedAllocator.h" #include "GLDefines.h" +#include "Image.h" +#include "CompressedImage.h" class ByteReader { private: @@ -73,7 +75,7 @@ class ByteReader { { } bool Advance(uint32 nBytes) { - if(nBytes < m_BytesLeft) { + if(nBytes > m_BytesLeft) { assert(!"Cannot read any more, unexpected bytes!"); return false; } @@ -99,6 +101,7 @@ class IntLoader { data.Advance(4); return true; } + virtual ~IntLoader() { } }; class BigEndianIntLoader : public IntLoader { @@ -137,8 +140,31 @@ ImageLoaderKTX::ImageLoaderKTX(const uint8 *rawData, const int32 rawDataSz) ImageLoaderKTX::~ImageLoaderKTX() { } +FasTC::Image<> *ImageLoaderKTX::LoadImage() { + + // Get rid of the pixel data if it exists... + if(m_PixelData) { + delete m_PixelData; + m_PixelData = NULL; + } + + if(!ReadData()) { + return NULL; + } + + if(!m_bIsCompressed) { + uint32 *pixels = reinterpret_cast(m_PixelData); + return new FasTC::Image<>(m_Width, m_Height, pixels); + } + + return new CompressedImage(m_Width, m_Height, m_Format, m_PixelData); +} + bool ImageLoaderKTX::ReadData() { + // Default is uncompressed + m_bIsCompressed = false; + ByteReader rdr (m_RawData, m_NumRawDataBytes); // First, check to make sure that the identifier is present... @@ -245,13 +271,25 @@ bool ImageLoaderKTX::ReadData() { 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); + m_Width = pixelWidth; + m_Height = pixelHeight; + + if(glType == 0 && glFormat == 0) { + switch(glInternalFormat) { + case GL_COMPRESSED_RGBA_BPTC_UNORM: + m_Format = FasTC::eCompressionFormat_BPTC; + break; + default: + fprintf(stderr, "KTX loader - texture format (0x%x) unsupported!\n", glInternalFormat); + return false; + } + + uint32 dataSize = CompressedImage::GetCompressedSize(pixelWidth * pixelHeight * 4, m_Format); + m_PixelData = new uint8[dataSize]; + memcpy(m_PixelData, rdr.GetData(), dataSize); + rdr.Advance(dataSize); + + m_bIsCompressed = true; } else { if(glType != GL_BYTE) { @@ -266,10 +304,10 @@ bool ImageLoaderKTX::ReadData() { // 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); + uint32 pixelDataSz = m_Width * m_Height * 4; + m_PixelData = new uint8[pixelDataSz]; + memcpy(m_PixelData, rdr.GetData(), pixelDataSz); + rdr.Advance(pixelDataSz); } return rdr.GetBytesLeft() == 0; } diff --git a/IO/src/ImageLoaderKTX.h b/IO/src/ImageLoaderKTX.h index 42df221..64dc74a 100644 --- a/IO/src/ImageLoaderKTX.h +++ b/IO/src/ImageLoaderKTX.h @@ -54,6 +54,7 @@ #define _IO_SRC_IMAGE_LOADER_KTX_H_ #include "ImageLoader.h" +#include "CompressionFormat.h" class ImageLoaderKTX : public ImageLoader { public: @@ -68,8 +69,12 @@ class ImageLoaderKTX : public ImageLoader { m_Processor = proc; } + virtual FasTC::Image<> *LoadImage(); private: KTXKeyValueProcessor m_Processor; + + bool m_bIsCompressed; + FasTC::ECompressionFormat m_Format; }; #endif // _IO_SRC_IMAGE_LOADER_KTX_H_ diff --git a/IO/src/ImageWriterKTX.cpp b/IO/src/ImageWriterKTX.cpp index 8c29972..e9aa7e1 100644 --- a/IO/src/ImageWriterKTX.cpp +++ b/IO/src/ImageWriterKTX.cpp @@ -110,10 +110,12 @@ bool ImageWriterKTX::WriteImage() { 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 oKeyLen = static_cast(strlen(orientationKey)); + + const char *orientationValue = "S=r,T=d"; + uint32 oValLen = static_cast(strlen(orientationValue)); + + const uint32 kvSz = oKeyLen + 1 + oValLen + 1; uint32 tkvSz = kvSz + 4; // total kv size tkvSz = (tkvSz + 3) & ~0x3; // 4-byte aligned @@ -121,7 +123,7 @@ bool ImageWriterKTX::WriteImage() { if(ci) { wtr.Write(0); // glType wtr.Write(1); // glTypeSize - wtr.Write(GL_RGBA); // glFormat + wtr.Write(0); // glFormat must be zero for compressed images... switch(ci->GetFormat()) { case FasTC::eCompressionFormat_BPTC: wtr.Write(GL_COMPRESSED_RGBA_BPTC_UNORM); // glInternalFormat @@ -153,8 +155,8 @@ bool ImageWriterKTX::WriteImage() { 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, oKeyLen + 1); // key + wtr.Write(orientationValue, oValLen + 1); // value wtr.Write(orientationKey, tkvSz - kvSz - 4); // padding if(ci && ci->GetFormat() == FasTC::eCompressionFormat_BPTC) { diff --git a/PVRTCEncoder/src/Compressor.cpp b/PVRTCEncoder/src/Compressor.cpp index 4b36bf6..e67c4e8 100644 --- a/PVRTCEncoder/src/Compressor.cpp +++ b/PVRTCEncoder/src/Compressor.cpp @@ -465,9 +465,11 @@ namespace PVRTCC { } #if 0 - static void DilateImage(CompressionLabel *labels, uint32 w, uint32 h) { + static void DilateImage(CompressionLabel *labels, const uint8 *inBuf, uint32 w, uint32 h) { for(uint32 j = 0; j < h; j++) for(uint32 i = 0; i < w; i++) { + ComputeLocalExtrema(labels, inBuf, i, j, w, h); + uint32 idx = j*w + i; uint32 minLowDist = labels[idx].lowLabel.distance == 0? 5 : labels[idx].lowLabel.distance - 1; @@ -484,11 +486,11 @@ namespace PVRTCC { minHighDist = ::std::min(minHighDist, labels[cidx].highLabel.distance); } - if(minLowDist != labels[idx].lowLabel.distance - 1) { + if(static_cast(minLowDist) != labels[idx].lowLabel.distance - 1) { labels[idx].lowLabel.nLabels = 0; } - if(minHighDist != labels[idx].highLabel.distance - 1) { + if(static_cast(minHighDist) != labels[idx].highLabel.distance - 1) { labels[idx].highLabel.nLabels = 0; } @@ -963,6 +965,27 @@ namespace PVRTCC { DebugOutputImage("HighImg", labels, width, height, HighPixel); DebugOutputImage("LowImg", labels, width, height, LowPixel); + + Image outputHigh(width, height); + Image outputLow(width, height); + for(uint32 j = 0; j < height; j++) + for(uint32 i = 0; i < width; i++) { + uint32 idx = j*width + i; + if(labels[idx].highLabel.distance == 1) { + outputHigh(i, j).Unpack(gDbgPixels[idx]); + } else { + outputHigh(i, j).Unpack(0xFF000000U); + } + + if(labels[idx].lowLabel.distance == 1) { + outputLow(i, j).Unpack(gDbgPixels[idx]); + } else { + outputLow(i, j).Unpack(0xFF000000U); + } + } + + outputHigh.DebugOutput("HighPixels"); + outputLow.DebugOutput("LowPixels"); #endif // Then combine everything... diff --git a/README.md b/README.md index adf612b..098b235 100644 --- a/README.md +++ b/README.md @@ -1,4 +1,4 @@ -FasTC +FasTC [![Build Status](https://travis-ci.org/Mokosha/FasTC.png)](https://travis-ci.org/Mokosha/FasTC) ======= A **Fas**t **T**exture **C**ompressor for a variety of formats. This compressor