diff options
Diffstat (limited to '')
29 files changed, 3315 insertions, 0 deletions
diff --git a/tools/depends/native/TexturePacker/CMakeLists.txt b/tools/depends/native/TexturePacker/CMakeLists.txt new file mode 100644 index 0000000..97dc1d3 --- /dev/null +++ b/tools/depends/native/TexturePacker/CMakeLists.txt @@ -0,0 +1,54 @@ +list(APPEND CMAKE_MODULE_PATH ${CMAKE_SOURCE_DIR}/cmake/modules) + +if(APPLE) + set(CMAKE_FIND_ROOT_PATH ${NATIVEPREFIX}) +endif() + +find_package(Lzo2 REQUIRED) +find_package(PNG REQUIRED) +find_package(GIF REQUIRED) +find_package(JPEG REQUIRED) + +if(GIF_VERSION LESS 4) + message(FATAL_ERROR "giflib < 4 not supported") +else() + file(STRINGS ${GIF_INCLUDE_DIR}/gif_lib.h GIFSTRINGS) + string(REGEX MATCH "GIFLIB_MAJOR ([0-9])" GIFLIB_MAJOR ${GIFSTRINGS}) + if(GIFLIB_MAJOR) + string(REPLACE " " ";" GIFLIB_MAJOR ${GIFLIB_MAJOR}) + list(GET GIFLIB_MAJOR 1 GIFLIB_MAJOR) + else() + set(GIFLIB_MAJOR ${GIF_VERSION}) + endif() + if(NOT GIFLIB_MAJOR OR GIFLIB_MAJOR LESS 5) + message(WARNING "giflib${GIFLIB_MAJOR} support is experimental. Consider updating to giflib5") + endif() +endif() + +set(SOURCES src/md5.cpp + src/DecoderManager.cpp + src/TexturePacker.cpp + src/XBTFWriter.cpp + src/decoder/GIFDecoder.cpp + src/decoder/GifHelper.cpp + src/decoder/JPGDecoder.cpp + src/decoder/PNGDecoder.cpp + ${CMAKE_SOURCE_DIR}/xbmc/guilib/XBTF.cpp) + +set(CMAKE_POSITITION_INDEPENDENT_CODE 1) + +add_executable(TexturePacker ${SOURCES}) +target_include_directories(TexturePacker + PRIVATE ${PNG_INCLUDE_DIRS} + ${JPEG_INCLUDE_DIR} + ${GIF_INCLUDE_DIR} + ${CMAKE_SOURCE_DIR}/xbmc + ${CMAKE_CURRENT_SOURCE_DIR}/src + ${CMAKE_CURRENT_SOURCE_DIR}/src/decoder) +target_link_libraries(TexturePacker + PRIVATE ${SYSTEM_LDFLAGS} + ${GIF_LIBRARIES} + ${PNG_LIBRARIES} + ${JPEG_LIBRARIES} + ${LZO2_LIBRARIES}) +target_compile_options(TexturePacker PRIVATE ${ARCH_DEFINES} ${SYSTEM_DEFINES}) diff --git a/tools/depends/native/TexturePacker/Makefile b/tools/depends/native/TexturePacker/Makefile new file mode 100644 index 0000000..f50dc87 --- /dev/null +++ b/tools/depends/native/TexturePacker/Makefile @@ -0,0 +1,62 @@ +ROOT_DIR := $(shell dirname $(realpath $(lastword $(MAKEFILE_LIST)))) +-include ../../Makefile.include +DEPS=Makefile + +ifeq ($(NATIVEPREFIX),) + PREFIX = $(ROOT_DIR) +else + PREFIX = $(NATIVEPREFIX) +endif + +ifeq ($(NATIVEPLATFORM),) + PLATFORM = native + EXTRA_CONFIGURE = --enable-static +else + PLATFORM = $(NATIVEPLATFORM) + DEPS += ../../Makefile.include +endif + +ifeq ($(NATIVE_OS), linux) + EXTRA_CONFIGURE = --enable-static +endif +ifeq ($(NATIVE_OS), android) + EXTRA_CONFIGURE = --enable-static +endif + +ifeq ($(CMAKE_SOURCE_DIR),) + CMAKE_SOURCE_DIR = $(ROOT_DIR)/../../../.. +endif + +SOURCE=$(ROOT_DIR)/src + +APP=$(PLATFORM)/TexturePacker +APPBIN=$(PREFIX)/bin/TexturePacker + +all: .installed-$(PLATFORM) + +$(PLATFORM): $(DEPS) + -rm -rf $(PLATFORM)/*; mkdir -p $(PLATFORM) + cd $(PLATFORM); cp -a $(SOURCE)/* . + cd $(PLATFORM); ./autogen.sh + cd $(PLATFORM); ./configure --prefix=$(PREFIX) $(EXTRA_CONFIGURE) EXTRA_DEFINES="$(NATIVE_ARCH_DEFINES)" + + +$(APP): $(PLATFORM) + $(MAKE) -C $(PLATFORM) + +.installed-$(PLATFORM): $(APP) + $(MAKE) -C $(PLATFORM) install + touch $@ + #TEMP workaround for skins: create legacy link. Remove me when skins are fixed + @mkdir -p $(CMAKE_SOURCE_DIR)/tools/TexturePacker + @[ -f $(CMAKE_SOURCE_DIR)/tools/TexturePacker/TexturePacker ] && rm $(CMAKE_SOURCE_DIR)/tools/TexturePacker/TexturePacker || : + @ln -sf $(APPBIN) $(CMAKE_SOURCE_DIR)/tools/TexturePacker/TexturePacker + @echo "all:" > $(CMAKE_SOURCE_DIR)/tools/TexturePacker/Makefile + @echo "\t@echo "WARNING: use of tools/TexturePacker/TexturePacker is deprecated, please update your skins Makefile"" >> $(CMAKE_SOURCE_DIR)/tools/TexturePacker/Makefile + +clean: + $(MAKE) -C $(PLATFORM) clean + +distclean:: + rm -rf $(PLATFORM) .installed-$(PLATFORM) + -rm -rf bin diff --git a/tools/depends/native/TexturePacker/src/DecoderManager.cpp b/tools/depends/native/TexturePacker/src/DecoderManager.cpp new file mode 100644 index 0000000..8f6a904 --- /dev/null +++ b/tools/depends/native/TexturePacker/src/DecoderManager.cpp @@ -0,0 +1,88 @@ +/* + * Copyright (C) 2014 Team Kodi + * http://kodi.tv + * + * This Program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2, or (at your option) + * any later version. + * + * This Program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with XBMC; see the file COPYING. If not, see + * <http://www.gnu.org/licenses/>. + * + */ +#include <cstdio> +#include "DecoderManager.h" + +bool DecoderManager::verbose; +std::vector<IDecoder *> DecoderManager::m_decoders; + +// ADD new decoders here +// include decoders +#include "PNGDecoder.h" +#include "JPGDecoder.h" +#include "GIFDecoder.h" + +void DecoderManager::InstantiateDecoders() +{ + m_decoders.push_back(new PNGDecoder()); + m_decoders.push_back(new JPGDecoder()); + m_decoders.push_back(new GIFDecoder()); +} + +void DecoderManager::FreeDecoders() +{ + for (unsigned int i = 0; i < m_decoders.size(); i++) + { + delete m_decoders[i]; + } + m_decoders.clear(); +} + +// returns true for png, bmp, tga, jpg and dds files, otherwise returns false +bool DecoderManager::IsSupportedGraphicsFile(char *strFileName) +{ + std::string filename = strFileName; + if (filename.length() < 4) + return false; + + for (unsigned int i = 0; i < m_decoders.size(); i++) + { + const std::vector<std::string> extensions = m_decoders[i]->GetSupportedExtensions(); + for (unsigned int n = 0; n < extensions.size(); n++) + { + int extLen = extensions[n].length(); + if (std::string::npos != filename.rfind(extensions[n].c_str(), filename.length() - extLen, extLen)) + { + return true; + } + } + } + return false; +} + +bool DecoderManager::LoadFile(const std::string &filename, DecodedFrames &frames) +{ + for (unsigned int i = 0; i < m_decoders.size(); i++) + { + if (m_decoders[i]->CanDecode(filename)) + { + if (verbose) + fprintf(stdout, "This is a %s - lets load it via %s...\n", + m_decoders[i]->GetImageFormatName(), m_decoders[i]->GetDecoderName()); + return m_decoders[i]->LoadFile(filename, frames); + } + } + return false; +} + +void DecoderManager::FreeDecodedFrames(DecodedFrames &frames) +{ + frames.clear(); +} diff --git a/tools/depends/native/TexturePacker/src/DecoderManager.h b/tools/depends/native/TexturePacker/src/DecoderManager.h new file mode 100644 index 0000000..2c59aa2 --- /dev/null +++ b/tools/depends/native/TexturePacker/src/DecoderManager.h @@ -0,0 +1,37 @@ +/* + * Copyright (C) 2014 Team Kodi + * http://kodi.tv + * + * This Program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2, or (at your option) + * any later version. + * + * This Program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with XBMC; see the file COPYING. If not, see + * <http://www.gnu.org/licenses/>. + * + */ + +#pragma once + +#include "IDecoder.h" + +class DecoderManager +{ + public: + static void InstantiateDecoders(); + static void FreeDecoders(); + static bool IsSupportedGraphicsFile(char *strFileName); + static bool LoadFile(const std::string &filename, DecodedFrames &frames); + static void FreeDecodedFrames(DecodedFrames &frames); + static bool verbose; + + private: + static std::vector<IDecoder *> m_decoders; +}; diff --git a/tools/depends/native/TexturePacker/src/Makefile.am b/tools/depends/native/TexturePacker/src/Makefile.am new file mode 100644 index 0000000..d6b676f --- /dev/null +++ b/tools/depends/native/TexturePacker/src/Makefile.am @@ -0,0 +1,29 @@ +AUTOMAKE_OPTIONS = subdir-objects + +AM_CFLAGS = -DTARGET_POSIX +AM_CFLAGS += @EXTRA_DEFINES@ +AM_CXXFLAGS = $(AM_CFLAGS) -std=c++0x + +AM_CPPFLAGS = \ + -I. \ + -I./decoder \ + -I@KODI_SRC_DIR@/xbmc \ + -I@KODI_SRC_DIR@/xbmc/guilib \ + @CPPFLAGS@ + +AM_LDFLAGS = @LIBS@ @STATIC_FLAG@ + + +bin_PROGRAMS = TexturePacker +TexturePacker_SOURCES = md5.cpp \ + XBTFWriter.cpp \ + TexturePacker.cpp \ + DecoderManager.cpp \ + decoder/PNGDecoder.cpp \ + decoder/JPGDecoder.cpp \ + decoder/GifHelper.cpp \ + decoder/GIFDecoder.cpp \ + XBTF.cpp + +XBTF.cpp: + @cp @KODI_SRC_DIR@/xbmc/guilib/XBTF.cpp . diff --git a/tools/depends/native/TexturePacker/src/SimpleFS.h b/tools/depends/native/TexturePacker/src/SimpleFS.h new file mode 100644 index 0000000..69d3342 --- /dev/null +++ b/tools/depends/native/TexturePacker/src/SimpleFS.h @@ -0,0 +1,107 @@ +/* + * Copyright (C) 2005-2013 Team XBMC + * http://kodi.tv + * + * This Program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2, or (at your option) + * any later version. + * + * This Program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with XBMC; see the file COPYING. If not, see + * <http://www.gnu.org/licenses/>. + * + */ + +#pragma once + +#include <cstdint> +#include <cstdio> +#include <string> + +class CFile +{ +public: + CFile() + { + m_file = NULL; + } + + ~CFile() + { + Close(); + } + + bool Open(const std::string &file) + { + Close(); + m_file = fopen(file.c_str(), "rb"); + return NULL != m_file; + } + + bool OpenForWrite(const std::string &file, bool overwrite) + { + Close(); + m_file = fopen(file.c_str(), "wb"); + return NULL != m_file; + } + void Close() + { + if (m_file) + fclose(m_file); + m_file = NULL; + } + + uint64_t Read(void *data, uint64_t size) + { + if (fread(data, (size_t)size, 1, m_file) == 1) + return size; + return 0; + } + + uint64_t Write(const void *data, uint64_t size) + { + if (fwrite(data, (size_t)size, 1, m_file) == 1) + return size; + return 0; + } + + FILE *getFP() + { + return m_file; + } + + uint64_t GetFileSize() + { + long curPos = ftell(m_file); + uint64_t fileSize = 0; + if (fseek(m_file, 0, SEEK_END) == 0) + { + long size = ftell(m_file); + if (size >= 0) + fileSize = (uint64_t)size; + } + + // restore fileptr + Seek(curPos); + + return fileSize; + } + + uint64_t Seek(uint64_t offset) + { + uint64_t seekedBytes = 0; + int seekRet = fseek(m_file, offset, SEEK_SET); + if (seekRet == 0) + seekedBytes = offset; + return seekedBytes; + } + +private: + FILE* m_file; +}; diff --git a/tools/depends/native/TexturePacker/src/TexturePacker.cpp b/tools/depends/native/TexturePacker/src/TexturePacker.cpp new file mode 100644 index 0000000..a6fd428 --- /dev/null +++ b/tools/depends/native/TexturePacker/src/TexturePacker.cpp @@ -0,0 +1,420 @@ +/* + * Copyright (C) 2005-2014 Team XBMC + * http://kodi.tv + * + * This Program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2, or (at your option) + * any later version. + * + * This Program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with XBMC; see the file COPYING. If not, see + * <http://www.gnu.org/licenses/>. + * + */ + +#ifdef TARGET_WINDOWS +#include <sys/types.h> +#define __STDC_FORMAT_MACROS +#include <cinttypes> +#define platform_stricmp _stricmp +#else +#include <inttypes.h> +#define platform_stricmp strcasecmp +#endif +#include <cerrno> +#include <dirent.h> +#include <map> + +#include "guilib/XBTF.h" +#include "guilib/XBTFReader.h" + +#include "DecoderManager.h" + +#include "XBTFWriter.h" +#include "md5.h" +#include "cmdlineargs.h" + +#ifdef TARGET_WINDOWS +#define strncasecmp _strnicmp +#endif + +#include <lzo/lzo1x.h> +#include <sys/stat.h> + +#define FLAGS_USE_LZO 1 + +#define DIR_SEPARATOR '/' + +const char *GetFormatString(unsigned int format) +{ + switch (format) + { + case XB_FMT_DXT1: + return "DXT1 "; + case XB_FMT_DXT3: + return "DXT3 "; + case XB_FMT_DXT5: + return "DXT5 "; + case XB_FMT_DXT5_YCoCg: + return "YCoCg"; + case XB_FMT_A8R8G8B8: + return "ARGB "; + case XB_FMT_A8: + return "A8 "; + default: + return "?????"; + } +} + +void CreateSkeletonHeaderImpl(CXBTFWriter& xbtfWriter, + const std::string& fullPath, + const std::string& relativePath) +{ + struct dirent* dp; + struct stat stat_p; + DIR *dirp = opendir(fullPath.c_str()); + + if (dirp) + { + for (errno = 0; (dp = readdir(dirp)); errno = 0) + { + if (strcmp(dp->d_name, ".") == 0 || strcmp(dp->d_name, "..") == 0) + { + continue; + } + + //stat to check for dir type (reiserfs fix) + std::string fileN = fullPath + "/" + dp->d_name; + if (stat(fileN.c_str(), &stat_p) == 0) + { + if (dp->d_type == DT_DIR || stat_p.st_mode & S_IFDIR) + { + std::string tmpPath = relativePath; + if (tmpPath.size() > 0) + { + tmpPath += "/"; + } + + CreateSkeletonHeaderImpl(xbtfWriter, fullPath + DIR_SEPARATOR + dp->d_name, tmpPath + dp->d_name); + } + else if (DecoderManager::IsSupportedGraphicsFile(dp->d_name)) + { + std::string fileName = ""; + if (relativePath.size() > 0) + { + fileName += relativePath; + fileName += "/"; + } + + fileName += dp->d_name; + + CXBTFFile file; + file.SetPath(fileName); + xbtfWriter.AddFile(file); + } + } + } + if (errno) + fprintf(stderr, "Error reading directory %s (%s)\n", fullPath.c_str(), strerror(errno)); + + closedir(dirp); + } + else + { + fprintf(stderr, "Error opening %s (%s)\n", fullPath.c_str(), strerror(errno)); + } +} + +void CreateSkeletonHeader(CXBTFWriter& xbtfWriter, const std::string& fullPath) +{ + std::string temp; + CreateSkeletonHeaderImpl(xbtfWriter, fullPath, temp); +} + +CXBTFFrame appendContent(CXBTFWriter &writer, int width, int height, unsigned char *data, unsigned int size, unsigned int format, bool hasAlpha, unsigned int flags) +{ + CXBTFFrame frame; + lzo_uint packedSize = size; + + if ((flags & FLAGS_USE_LZO) == FLAGS_USE_LZO) + { + // grab a temporary buffer for unpacking into + packedSize = size + size / 16 + 64 + 3; // see simple.c in lzo + unsigned char *packed = new unsigned char[packedSize]; + unsigned char *working = new unsigned char[LZO1X_999_MEM_COMPRESS]; + if (packed && working) + { + if (lzo1x_999_compress(data, size, packed, &packedSize, working) != LZO_E_OK || packedSize > size) + { + // compression failed, or compressed size is bigger than uncompressed, so store as uncompressed + packedSize = size; + writer.AppendContent(data, size); + } + else + { // success + lzo_uint optimSize = size; + if (lzo1x_optimize(packed, packedSize, data, &optimSize, NULL) != LZO_E_OK || optimSize != size) + { //optimisation failed + packedSize = size; + writer.AppendContent(data, size); + } + else + { // success + writer.AppendContent(packed, packedSize); + } + } + delete[] working; + delete[] packed; + } + } + else + { + writer.AppendContent(data, size); + } + frame.SetPackedSize(packedSize); + frame.SetUnpackedSize(size); + frame.SetWidth(width); + frame.SetHeight(height); + frame.SetFormat(hasAlpha ? format : format | XB_FMT_OPAQUE); + frame.SetDuration(0); + return frame; +} + +bool HasAlpha(unsigned char *argb, unsigned int width, unsigned int height) +{ + unsigned char *p = argb + 3; // offset of alpha + for (unsigned int i = 0; i < 4*width*height; i += 4) + { + if (p[i] != 0xff) + return true; + } + return false; +} + +CXBTFFrame createXBTFFrame(RGBAImage &image, CXBTFWriter& writer, double maxMSE, unsigned int flags) +{ + + int width, height; + unsigned int format = 0; + unsigned char* argb = (unsigned char*)image.pixels; + + width = image.width; + height = image.height; + bool hasAlpha = HasAlpha(argb, width, height); + + CXBTFFrame frame; + format = XB_FMT_A8R8G8B8; + frame = appendContent(writer, width, height, argb, (width * height * 4), format, hasAlpha, flags); + + return frame; +} + +void Usage() +{ + puts("Usage:"); + puts(" -help Show this screen."); + puts(" -input <dir> Input directory. Default: current dir"); + puts(" -output <dir> Output directory/filename. Default: Textures.xbt"); + puts(" -dupecheck Enable duplicate file detection. Reduces output file size. Default: off"); +} + +static bool checkDupe(struct MD5Context* ctx, + std::map<std::string, unsigned int>& hashes, + std::vector<unsigned int>& dupes, unsigned int pos) +{ + unsigned char digest[17]; + MD5Final(digest,ctx); + digest[16] = 0; + char hex[33]; + sprintf(hex, "%02X%02X%02X%02X%02X%02X%02X%02X"\ + "%02X%02X%02X%02X%02X%02X%02X%02X", digest[0], digest[1], digest[2], + digest[3], digest[4], digest[5], digest[6], digest[7], digest[8], + digest[9], digest[10], digest[11], digest[12], digest[13], digest[14], + digest[15]); + hex[32] = 0; + std::map<std::string, unsigned int>::iterator it = hashes.find(hex); + if (it != hashes.end()) + { + dupes[pos] = it->second; + return true; + } + + hashes.insert(std::make_pair(hex,pos)); + dupes[pos] = pos; + + return false; +} + +int createBundle(const std::string& InputDir, const std::string& OutputFile, double maxMSE, unsigned int flags, bool dupecheck) +{ + CXBTFWriter writer(OutputFile); + if (!writer.Create()) + { + fprintf(stderr, "Error creating file\n"); + return 1; + } + + std::map<std::string, unsigned int> hashes; + std::vector<unsigned int> dupes; + CreateSkeletonHeader(writer, InputDir); + + std::vector<CXBTFFile> files = writer.GetFiles(); + dupes.resize(files.size()); + if (!dupecheck) + { + for (unsigned int i=0;i<dupes.size();++i) + dupes[i] = i; + } + + for (size_t i = 0; i < files.size(); i++) + { + struct MD5Context ctx; + MD5Init(&ctx); + CXBTFFile& file = files[i]; + + std::string fullPath = InputDir; + fullPath += file.GetPath(); + + std::string output = file.GetPath(); + output = output.substr(0, 40); + while (output.size() < 46) + output += ' '; + + DecodedFrames frames; + bool loaded = DecoderManager::LoadFile(fullPath, frames); + + if (!loaded) + { + fprintf(stderr, "...unable to load image %s\n", file.GetPath().c_str()); + continue; + } + + printf("%s\n", output.c_str()); + bool skip=false; + if (dupecheck) + { + for (unsigned int j = 0; j < frames.frameList.size(); j++) + MD5Update(&ctx, + (const uint8_t*)frames.frameList[j].rgbaImage.pixels, + frames.frameList[j].rgbaImage.height * frames.frameList[j].rgbaImage.pitch); + + if (checkDupe(&ctx,hashes,dupes,i)) + { + printf("**** duplicate of %s\n", files[dupes[i]].GetPath().c_str()); + file.GetFrames().insert(file.GetFrames().end(), + files[dupes[i]].GetFrames().begin(), + files[dupes[i]].GetFrames().end()); + skip = true; + } + } + + if (!skip) + { + for (unsigned int j = 0; j < frames.frameList.size(); j++) + { + printf(" frame %4i (delay:%4i) ", j, frames.frameList[j].delay); + CXBTFFrame frame = createXBTFFrame(frames.frameList[j].rgbaImage, writer, maxMSE, flags); + frame.SetDuration(frames.frameList[j].delay); + file.GetFrames().push_back(frame); + printf("%s%c (%d,%d @ %" PRIu64 " bytes)\n", GetFormatString(frame.GetFormat()), frame.HasAlpha() ? ' ' : '*', + frame.GetWidth(), frame.GetHeight(), frame.GetUnpackedSize()); + } + } + DecoderManager::FreeDecodedFrames(frames); + file.SetLoop(0); + + writer.UpdateFile(file); + } + + if (!writer.UpdateHeader(dupes)) + { + fprintf(stderr, "Error writing header to file\n"); + return 1; + } + + if (!writer.Close()) + { + fprintf(stderr, "Error closing file\n"); + return 1; + } + + return 0; +} + +int main(int argc, char* argv[]) +{ + if (lzo_init() != LZO_E_OK) + return 1; + bool valid = false; + unsigned int flags = 0; + bool dupecheck = false; + CmdLineArgs args(argc, (const char**)argv); + + // setup some defaults, lzo packing, + flags = FLAGS_USE_LZO; + + if (args.size() == 1) + { + Usage(); + return 1; + } + + std::string InputDir; + std::string OutputFilename = "Textures.xbt"; + + for (unsigned int i = 1; i < args.size(); ++i) + { + if (!platform_stricmp(args[i], "-help") || !platform_stricmp(args[i], "-h") || !platform_stricmp(args[i], "-?")) + { + Usage(); + return 1; + } + else if (!platform_stricmp(args[i], "-input") || !platform_stricmp(args[i], "-i")) + { + InputDir = args[++i]; + valid = true; + } + else if (!strcmp(args[i], "-dupecheck")) + { + dupecheck = true; + } + else if (!strcmp(args[i], "-verbose")) + { + DecoderManager::verbose = true; + } + else if (!platform_stricmp(args[i], "-output") || !platform_stricmp(args[i], "-o")) + { + OutputFilename = args[++i]; + valid = true; +#ifdef TARGET_POSIX + char *c = NULL; + while ((c = (char *)strchr(OutputFilename.c_str(), '\\')) != NULL) *c = '/'; +#endif + } + else + { + fprintf(stderr, "Unrecognized command line flag: %s\n", args[i]); + } + } + + if (!valid) + { + Usage(); + return 1; + } + + size_t pos = InputDir.find_last_of(DIR_SEPARATOR); + if (pos != InputDir.length() - 1) + InputDir += DIR_SEPARATOR; + + double maxMSE = 1.5; // HQ only please + DecoderManager::InstantiateDecoders(); + createBundle(InputDir, OutputFilename, maxMSE, flags, dupecheck); + DecoderManager::FreeDecoders(); +} diff --git a/tools/depends/native/TexturePacker/src/Win32/TexturePacker.sln b/tools/depends/native/TexturePacker/src/Win32/TexturePacker.sln new file mode 100644 index 0000000..07cd920 --- /dev/null +++ b/tools/depends/native/TexturePacker/src/Win32/TexturePacker.sln @@ -0,0 +1,22 @@ +
+Microsoft Visual Studio Solution File, Format Version 12.00
+# Visual Studio 2013
+VisualStudioVersion = 12.0.30723.0
+MinimumVisualStudioVersion = 10.0.40219.1
+Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "TexturePacker", "TexturePacker.vcxproj", "{57EC0A84-7E0C-4EEA-9E63-BB4EBF2310D7}"
+EndProject
+Global
+ GlobalSection(SolutionConfigurationPlatforms) = preSolution
+ Debug|Win32 = Debug|Win32
+ Release|Win32 = Release|Win32
+ EndGlobalSection
+ GlobalSection(ProjectConfigurationPlatforms) = postSolution
+ {57EC0A84-7E0C-4EEA-9E63-BB4EBF2310D7}.Debug|Win32.ActiveCfg = Debug|Win32
+ {57EC0A84-7E0C-4EEA-9E63-BB4EBF2310D7}.Debug|Win32.Build.0 = Debug|Win32
+ {57EC0A84-7E0C-4EEA-9E63-BB4EBF2310D7}.Release|Win32.ActiveCfg = Release|Win32
+ {57EC0A84-7E0C-4EEA-9E63-BB4EBF2310D7}.Release|Win32.Build.0 = Release|Win32
+ EndGlobalSection
+ GlobalSection(SolutionProperties) = preSolution
+ HideSolutionNode = FALSE
+ EndGlobalSection
+EndGlobal
diff --git a/tools/depends/native/TexturePacker/src/Win32/TexturePacker.vcxproj b/tools/depends/native/TexturePacker/src/Win32/TexturePacker.vcxproj new file mode 100644 index 0000000..8f540ed --- /dev/null +++ b/tools/depends/native/TexturePacker/src/Win32/TexturePacker.vcxproj @@ -0,0 +1,144 @@ +<?xml version="1.0" encoding="utf-8"?>
+<Project DefaultTargets="Build" ToolsVersion="15.0" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
+ <ItemGroup Label="ProjectConfigurations">
+ <ProjectConfiguration Include="Debug|Win32">
+ <Configuration>Debug</Configuration>
+ <Platform>Win32</Platform>
+ </ProjectConfiguration>
+ <ProjectConfiguration Include="Release|Win32">
+ <Configuration>Release</Configuration>
+ <Platform>Win32</Platform>
+ </ProjectConfiguration>
+ </ItemGroup>
+ <PropertyGroup Label="Globals">
+ <ProjectGuid>{57EC0A84-7E0C-4EEA-9E63-BB4EBF2310D7}</ProjectGuid>
+ <RootNamespace>TexturePacker</RootNamespace>
+ <Keyword>Win32Proj</Keyword>
+ <WindowsTargetPlatformVersion>10.0.17763.0</WindowsTargetPlatformVersion>
+ </PropertyGroup>
+ <Import Project="$(VCTargetsPath)\Microsoft.Cpp.Default.props" />
+ <PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|Win32'" Label="Configuration">
+ <ConfigurationType>Application</ConfigurationType>
+ <CharacterSet>NotSet</CharacterSet>
+ <WholeProgramOptimization>true</WholeProgramOptimization>
+ <PlatformToolset>v141</PlatformToolset>
+ </PropertyGroup>
+ <PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'" Label="Configuration">
+ <ConfigurationType>Application</ConfigurationType>
+ <CharacterSet>NotSet</CharacterSet>
+ <PlatformToolset>v141</PlatformToolset>
+ </PropertyGroup>
+ <Import Project="$(VCTargetsPath)\Microsoft.Cpp.props" />
+ <ImportGroup Label="ExtensionSettings">
+ </ImportGroup>
+ <ImportGroup Condition="'$(Configuration)|$(Platform)'=='Release|Win32'" Label="PropertySheets">
+ <Import Project="$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props" Condition="exists('$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props')" Label="LocalAppDataPlatform" />
+ </ImportGroup>
+ <ImportGroup Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'" Label="PropertySheets">
+ <Import Project="$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props" Condition="exists('$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props')" Label="LocalAppDataPlatform" />
+ </ImportGroup>
+ <PropertyGroup Label="UserMacros" />
+ <PropertyGroup>
+ <_ProjectFileVersion>10.0.30319.1</_ProjectFileVersion>
+ <OutDir Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">$(SolutionDir)$(Configuration)\</OutDir>
+ <IntDir Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">$(Configuration)\</IntDir>
+ <LinkIncremental Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">true</LinkIncremental>
+ <OutDir Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">$(SolutionDir)$(Configuration)\</OutDir>
+ <IntDir Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">$(Configuration)\</IntDir>
+ <LinkIncremental Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">false</LinkIncremental>
+ </PropertyGroup>
+ <PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">
+ <IncludePath>$(VC_IncludePath);$(WindowsSDK_IncludePath);..\..\..\..\..\..\project\BuildDependencies\include</IncludePath>
+ <LibraryPath>$(VC_LibraryPath_x86);$(WindowsSDK_LibraryPath_x86);$(NETFXKitsDir)Lib\um\x86;..\..\..\..\..\..\project\BuildDependencies\lib</LibraryPath>
+ </PropertyGroup>
+ <PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">
+ <IncludePath>$(VC_IncludePath);$(WindowsSDK_IncludePath);..\..\..\..\..\..\project\BuildDependencies\include</IncludePath>
+ <LibraryPath>$(VC_LibraryPath_x86);$(WindowsSDK_LibraryPath_x86);$(NETFXKitsDir)Lib\um\x86;..\..\..\..\..\..\project\BuildDependencies\lib</LibraryPath>
+ </PropertyGroup>
+ <ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">
+ <ClCompile>
+ <Optimization>Disabled</Optimization>
+ <AdditionalIncludeDirectories>.;..;..\decoder;..\..\..\..\..\..\xbmc;..\..\..\..\..\..\project\BuildDependencies\win32\include</AdditionalIncludeDirectories>
+ <PreprocessorDefinitions>WIN32;_DEBUG;_CONSOLE;TARGET_WINDOWS;_ITERATOR_DEBUG_LEVEL=0;_CRT_SECURE_NO_WARNINGS;%(PreprocessorDefinitions)</PreprocessorDefinitions>
+ <MinimalRebuild>true</MinimalRebuild>
+ <BasicRuntimeChecks>EnableFastChecks</BasicRuntimeChecks>
+ <RuntimeLibrary>MultiThreadedDebugDLL</RuntimeLibrary>
+ <PrecompiledHeader>
+ </PrecompiledHeader>
+ <WarningLevel>Level3</WarningLevel>
+ <DebugInformationFormat>EditAndContinue</DebugInformationFormat>
+ <ProgramDataBaseFileName>$(IntDir)$(TargetName).pdb</ProgramDataBaseFileName>
+ </ClCompile>
+ <Link>
+ <AdditionalDependencies>jpeg-staticd.lib;libpng16_staticd.lib;gifd.lib;zlibstaticd.lib;lzo2d.lib;%(AdditionalDependencies)</AdditionalDependencies>
+ <IgnoreSpecificDefaultLibraries>libcmtd.lib;%(IgnoreSpecificDefaultLibraries)</IgnoreSpecificDefaultLibraries>
+ <GenerateDebugInformation>true</GenerateDebugInformation>
+ <SubSystem>Console</SubSystem>
+ <TargetMachine>MachineX86</TargetMachine>
+ <AdditionalLibraryDirectories>..\..\..\..\..\..\project\BuildDependencies\win32\lib;%(AdditionalLibraryDirectories)</AdditionalLibraryDirectories>
+ <ImageHasSafeExceptionHandlers>false</ImageHasSafeExceptionHandlers>
+ </Link>
+ </ItemDefinitionGroup>
+ <ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">
+ <ClCompile>
+ <Optimization>MaxSpeed</Optimization>
+ <IntrinsicFunctions>true</IntrinsicFunctions>
+ <AdditionalIncludeDirectories>.;..;..\decoder;..\..\..\..\..\..\xbmc;..\..\..\..\..\..\project\BuildDependencies\win32\include</AdditionalIncludeDirectories>
+ <PreprocessorDefinitions>WIN32;NDEBUG;_CONSOLE;TARGET_WINDOWS;_ITERATOR_DEBUG_LEVEL=0;_CRT_SECURE_NO_WARNINGS;%(PreprocessorDefinitions)</PreprocessorDefinitions>
+ <RuntimeLibrary>MultiThreadedDLL</RuntimeLibrary>
+ <FunctionLevelLinking>true</FunctionLevelLinking>
+ <PrecompiledHeader>
+ </PrecompiledHeader>
+ <WarningLevel>Level3</WarningLevel>
+ <DebugInformationFormat>ProgramDatabase</DebugInformationFormat>
+ <ProgramDataBaseFileName>$(IntDir)$(TargetName).pdb</ProgramDataBaseFileName>
+ </ClCompile>
+ <Link>
+ <AdditionalDependencies>jpeg-static.lib;libpng16_static.lib;gif.lib;zlibstatic.lib;lzo2.lib;%(AdditionalDependencies)</AdditionalDependencies>
+ <IgnoreSpecificDefaultLibraries>libc.lib;%(IgnoreSpecificDefaultLibraries)</IgnoreSpecificDefaultLibraries>
+ <GenerateDebugInformation>true</GenerateDebugInformation>
+ <SubSystem>Console</SubSystem>
+ <OptimizeReferences>true</OptimizeReferences>
+ <EnableCOMDATFolding>true</EnableCOMDATFolding>
+ <TargetMachine>MachineX86</TargetMachine>
+ <AdditionalLibraryDirectories>..\..\..\..\..\..\project\BuildDependencies\win32\lib;%(AdditionalLibraryDirectories)</AdditionalLibraryDirectories>
+ <ImageHasSafeExceptionHandlers>false</ImageHasSafeExceptionHandlers>
+ </Link>
+ </ItemDefinitionGroup>
+ <ItemGroup>
+ <ClCompile Include="..\DecoderManager.cpp" />
+ <ClCompile Include="..\decoder\GIFDecoder.cpp" />
+ <ClCompile Include="..\decoder\GifHelper.cpp" />
+ <ClCompile Include="..\decoder\JPGDecoder.cpp" />
+ <ClCompile Include="..\decoder\PNGDecoder.cpp" />
+ <ClCompile Include="..\md5.cpp" />
+ <ClCompile Include="..\TexturePacker.cpp" />
+ <ClCompile Include="dirent.c" />
+ <ClCompile Include="..\..\..\..\..\..\xbmc\guilib\XBTF.cpp" />
+ <ClCompile Include="..\XBTFWriter.cpp" />
+ </ItemGroup>
+ <ItemGroup>
+ <ClInclude Include="..\cmdlineargs.h" />
+ <ClInclude Include="..\DecoderManager.h" />
+ <ClInclude Include="..\decoder\GIFDecoder.h" />
+ <ClInclude Include="..\decoder\GifHelper.h" />
+ <ClInclude Include="..\decoder\IDecoder.h" />
+ <ClInclude Include="..\decoder\JPGDecoder.h" />
+ <ClInclude Include="..\decoder\PNGDecoder.h" />
+ <ClInclude Include="..\rgbaimage.h" />
+ <ClInclude Include="dirent.h" />
+ <ClInclude Include="..\md5.h" />
+ <ClInclude Include="..\..\..\..\..\..\xbmc\guilib\XBTF.h" />
+ <ClInclude Include="..\XBTFWriter.h" />
+ <ClInclude Include="resource.h" />
+ </ItemGroup>
+ <ItemGroup>
+ <None Include="ReadMe.txt" />
+ </ItemGroup>
+ <ItemGroup>
+ <ResourceCompile Include="version.rc" />
+ </ItemGroup>
+ <Import Project="$(VCTargetsPath)\Microsoft.Cpp.targets" />
+ <ImportGroup Label="ExtensionTargets">
+ </ImportGroup>
+</Project>
\ No newline at end of file diff --git a/tools/depends/native/TexturePacker/src/Win32/TexturePacker.vcxproj.filters b/tools/depends/native/TexturePacker/src/Win32/TexturePacker.vcxproj.filters new file mode 100644 index 0000000..f045d9c --- /dev/null +++ b/tools/depends/native/TexturePacker/src/Win32/TexturePacker.vcxproj.filters @@ -0,0 +1,101 @@ +<?xml version="1.0" encoding="utf-8"?>
+<Project ToolsVersion="4.0" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
+ <ItemGroup>
+ <Filter Include="Source Files">
+ <UniqueIdentifier>{4FC737F1-C7A5-4376-A066-2A32D752A2FF}</UniqueIdentifier>
+ <Extensions>cpp;c;cc;cxx;def;odl;idl;hpj;bat;asm;asmx</Extensions>
+ </Filter>
+ <Filter Include="Header Files">
+ <UniqueIdentifier>{93995380-89BD-4b04-88EB-625FBE52EBFB}</UniqueIdentifier>
+ <Extensions>h;hpp;hxx;hm;inl;inc;xsd</Extensions>
+ </Filter>
+ <Filter Include="Resource Files">
+ <UniqueIdentifier>{67DA6AB6-F800-4c08-8B7A-83BB121AAD01}</UniqueIdentifier>
+ <Extensions>rc;ico;cur;bmp;dlg;rc2;rct;bin;rgs;gif;jpg;jpeg;jpe;resx;tiff;tif;png;wav</Extensions>
+ </Filter>
+ <Filter Include="decoder">
+ <UniqueIdentifier>{c79bff3f-9118-4c2d-bc31-68b25f7dfbba}</UniqueIdentifier>
+ </Filter>
+ </ItemGroup>
+ <ItemGroup>
+ <ClCompile Include="dirent.c">
+ <Filter>Source Files</Filter>
+ </ClCompile>
+ <ClCompile Include="..\..\..\..\..\..\xbmc\guilib\XBTF.cpp">
+ <Filter>Source Files</Filter>
+ </ClCompile>
+ <ClCompile Include="..\XBTFWriter.cpp">
+ <Filter>Source Files</Filter>
+ </ClCompile>
+ <ClCompile Include="..\md5.cpp">
+ <Filter>Source Files</Filter>
+ </ClCompile>
+ <ClCompile Include="..\decoder\GIFDecoder.cpp">
+ <Filter>decoder</Filter>
+ </ClCompile>
+ <ClCompile Include="..\decoder\GifHelper.cpp">
+ <Filter>decoder</Filter>
+ </ClCompile>
+ <ClCompile Include="..\decoder\JPGDecoder.cpp">
+ <Filter>decoder</Filter>
+ </ClCompile>
+ <ClCompile Include="..\decoder\PNGDecoder.cpp">
+ <Filter>decoder</Filter>
+ </ClCompile>
+ <ClCompile Include="..\TexturePacker.cpp">
+ <Filter>Source Files</Filter>
+ </ClCompile>
+ <ClCompile Include="..\DecoderManager.cpp">
+ <Filter>Source Files</Filter>
+ </ClCompile>
+ </ItemGroup>
+ <ItemGroup>
+ <ClInclude Include="..\cmdlineargs.h">
+ <Filter>Header Files</Filter>
+ </ClInclude>
+ <ClInclude Include="dirent.h">
+ <Filter>Header Files</Filter>
+ </ClInclude>
+ <ClInclude Include="..\md5.h">
+ <Filter>Header Files</Filter>
+ </ClInclude>
+ <ClInclude Include="..\..\..\..\..\..\xbmc\guilib\XBTF.h">
+ <Filter>Header Files</Filter>
+ </ClInclude>
+ <ClInclude Include="..\XBTFWriter.h">
+ <Filter>Header Files</Filter>
+ </ClInclude>
+ <ClInclude Include="..\rgbaimage.h">
+ <Filter>Header Files</Filter>
+ </ClInclude>
+ <ClInclude Include="..\decoder\GIFDecoder.h">
+ <Filter>decoder</Filter>
+ </ClInclude>
+ <ClInclude Include="..\decoder\GifHelper.h">
+ <Filter>decoder</Filter>
+ </ClInclude>
+ <ClInclude Include="..\decoder\IDecoder.h">
+ <Filter>decoder</Filter>
+ </ClInclude>
+ <ClInclude Include="..\decoder\JPGDecoder.h">
+ <Filter>decoder</Filter>
+ </ClInclude>
+ <ClInclude Include="..\decoder\PNGDecoder.h">
+ <Filter>decoder</Filter>
+ </ClInclude>
+ <ClInclude Include="..\DecoderManager.h">
+ <Filter>Source Files</Filter>
+ </ClInclude>
+ <ClInclude Include="resource.h">
+ <Filter>Header Files</Filter>
+ </ClInclude>
+ </ItemGroup>
+ <ItemGroup>
+ <None Include="ReadMe.txt" />
+ </ItemGroup>
+ <ItemGroup>
+ <ResourceCompile Include="version.rc">
+ <Filter>Resource Files</Filter>
+ </ResourceCompile>
+ </ItemGroup>
+</Project>
\ No newline at end of file diff --git a/tools/depends/native/TexturePacker/src/Win32/dirent.c b/tools/depends/native/TexturePacker/src/Win32/dirent.c new file mode 100644 index 0000000..7598516 --- /dev/null +++ b/tools/depends/native/TexturePacker/src/Win32/dirent.c @@ -0,0 +1,145 @@ +/* + + Implementation of POSIX directory browsing functions and types for Win32. + + Author: Kevlin Henney (kevlin@acm.org, kevlin@curbralan.com) + History: Created March 1997. Updated June 2003 and July 2012. + + Copyright Kevlin Henney, 1997, 2003. All rights reserved. + + Permission to use, copy, modify, and distribute this software and its + documentation for any purpose is hereby granted without fee, provided + that this copyright and permissions notice appear in all copies and + derivatives. + + This software is supplied "as is" without express or implied warranty. + + But that said, if there are any problems please get in touch. +*/ + +#include <errno.h> +#include <stdlib.h> +#include <string.h> + +#include <dirent.h> +#include <io.h> /* _findfirst and _findnext set errno iff they return -1 */ + +#ifdef __cplusplus +extern "C" +{ +#endif + +typedef ptrdiff_t handle_type; /* C99's intptr_t not sufficiently portable */ + +struct DIR +{ + handle_type handle; /* -1 for failed rewind */ + struct _finddata_t info; + struct dirent result; /* d_name null iff first time */ + char *name; /* null-terminated char string */ +}; + +DIR *opendir(const char *name) +{ + DIR *dir = 0; + + if(name && name[0]) + { + size_t base_length = strlen(name); + const char *all = /* search pattern must end with suitable wildcard */ + strchr("/\\", name[base_length - 1]) ? "*" : "/*"; + + if((dir = (DIR *) malloc(sizeof *dir)) != 0 && + (dir->name = (char *) malloc(base_length + strlen(all) + 1)) != 0) + { + strcat(strcpy(dir->name, name), all); + + if ((dir->handle = (handle_type)_findfirst(dir->name, &dir->info)) != -1) + { + dir->result.d_name = 0; + dir->result.d_type = 0; + } + else /* rollback */ + { + free(dir->name); + free(dir); + dir = 0; + } + } + else /* rollback */ + { + free(dir); + dir = 0; + errno = ENOMEM; + } + } + else + { + errno = EINVAL; + } + + return dir; +} + +int closedir(DIR *dir) +{ + int result = -1; + + if(dir) + { + if(dir->handle != -1) + { + result = _findclose(dir->handle); + } + + free(dir->name); + free(dir); + } + + if(result == -1) /* map all errors to EBADF */ + { + errno = EBADF; + } + + return result; +} + +struct dirent *readdir(DIR *dir) +{ + struct dirent *result = 0; + + if(dir && dir->handle != -1) + { + if(!dir->result.d_name || _findnext(dir->handle, &dir->info) != -1) + { + result = &dir->result; + result->d_name = dir->info.name; + result->d_type = (dir->info.attrib == _A_SUBDIR) ? DT_DIR : DT_UNKNOWN; + } + } + else + { + errno = EBADF; + } + + return result; +} + +void rewinddir(DIR *dir) +{ + if(dir && dir->handle != -1) + { + _findclose(dir->handle); + dir->handle = (handle_type)_findfirst(dir->name, &dir->info); + dir->result.d_name = 0; + dir->result.d_type = 0; + } + else + { + errno = EBADF; + } +} + +#ifdef __cplusplus +} +#endif diff --git a/tools/depends/native/TexturePacker/src/Win32/dirent.h b/tools/depends/native/TexturePacker/src/Win32/dirent.h new file mode 100644 index 0000000..e57b250 --- /dev/null +++ b/tools/depends/native/TexturePacker/src/Win32/dirent.h @@ -0,0 +1,53 @@ +/* + + Declaration of POSIX directory browsing functions and types for Win32. + + Author: Kevlin Henney (kevlin@acm.org, kevlin@curbralan.com) + History: Created March 1997. Updated June 2003. + + Copyright Kevlin Henney, 1997, 2003. All rights reserved. + + Permission to use, copy, modify, and distribute this software and its + documentation for any purpose is hereby granted without fee, provided + that this copyright and permissions notice appear in all copies and + derivatives. + + This software is supplied "as is" without express or implied warranty. + + But that said, if there are any problems please get in touch. +*/ + +#pragma once + +#ifdef __cplusplus +extern "C" +{ +#endif + +typedef struct DIR DIR; + +#define DT_UNKNOWN 0 +#define DT_FIFO 1 +#define DT_CHR 2 +#define DT_DIR 4 +#define DT_BLK 6 +#define DT_REG 8 +#define DT_LNK 10 +#define DT_SOCK 12 +#define DT_WHT 14 + +struct dirent +{ + char *d_name; + unsigned char d_type; +}; + +DIR *opendir(const char *); +int closedir(DIR *); +struct dirent *readdir(DIR *); +void rewinddir(DIR *); + +#ifdef __cplusplus +} +#endif + diff --git a/tools/depends/native/TexturePacker/src/Win32/version.rc b/tools/depends/native/TexturePacker/src/Win32/version.rc Binary files differnew file mode 100644 index 0000000..7ccb57f --- /dev/null +++ b/tools/depends/native/TexturePacker/src/Win32/version.rc diff --git a/tools/depends/native/TexturePacker/src/XBTFWriter.cpp b/tools/depends/native/TexturePacker/src/XBTFWriter.cpp new file mode 100644 index 0000000..1607db1 --- /dev/null +++ b/tools/depends/native/TexturePacker/src/XBTFWriter.cpp @@ -0,0 +1,164 @@ +/* + * Copyright (C) 2005-2013 Team XBMC + * http://kodi.tv + * + * This Program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2, or (at your option) + * any later version. + * + * This Program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with XBMC; see the file COPYING. If not, see + * <http://www.gnu.org/licenses/>. + * + */ + +#define __STDC_FORMAT_MACROS +#include <cinttypes> +#if defined(TARGET_FREEBSD) || defined(TARGET_DARWIN) +#include <cstdlib> +#elif !defined(TARGET_DARWIN) +#include <malloc.h> +#endif +#include <memory.h> +#include <cstring> + +#include "XBTFWriter.h" +#include "guilib/XBTFReader.h" +#include "utils/EndianSwap.h" + + +#define WRITE_STR(str, size, file) fwrite(str, size, 1, file) +#define WRITE_U32(i, file) { uint32_t _n = Endian_SwapLE32(i); fwrite(&_n, 4, 1, file); } +#define WRITE_U64(i, file) { uint64_t _n = i; _n = Endian_SwapLE64(i); fwrite(&_n, 8, 1, file); } + +CXBTFWriter::CXBTFWriter(const std::string& outputFile) + : m_outputFile(outputFile), + m_file(nullptr), + m_data(nullptr), + m_size(0) +{ } + +CXBTFWriter::~CXBTFWriter() +{ + Close(); +} + +bool CXBTFWriter::Create() +{ + m_file = fopen(m_outputFile.c_str(), "wb"); + if (m_file == nullptr) + return false; + + return true; +} + +bool CXBTFWriter::Close() +{ + if (m_file == nullptr || m_data == nullptr) + return false; + + fwrite(m_data, 1, m_size, m_file); + + Cleanup(); + + return true; +} + +void CXBTFWriter::Cleanup() +{ + free(m_data); + m_data = nullptr; + m_size = 0; + if (m_file) + { + fclose(m_file); + m_file = nullptr; + } +} + +bool CXBTFWriter::AppendContent(unsigned char const* data, size_t length) +{ + unsigned char *new_data = (unsigned char *)realloc(m_data, m_size + length); + + if (new_data == nullptr) + { // OOM - cleanup and fail + Cleanup(); + return false; + } + + m_data = new_data; + + memcpy(m_data + m_size, data, length); + m_size += length; + + return true; +} + +bool CXBTFWriter::UpdateHeader(const std::vector<unsigned int>& dupes) +{ + if (m_file == nullptr) + return false; + + uint64_t headerSize = GetHeaderSize(); + uint64_t offset = headerSize; + + WRITE_STR(XBTF_MAGIC.c_str(), 4, m_file); + WRITE_STR(XBTF_VERSION.c_str(), 1, m_file); + + auto files = GetFiles(); + WRITE_U32(files.size(), m_file); + for (size_t i = 0; i < files.size(); i++) + { + CXBTFFile& file = files[i]; + + // Convert path to lower case and store it into a fixed size array because + // we need to store the path as a fixed length 256 byte character array. + std::string path = file.GetPath(); + char pathMem[CXBTFFile::MaximumPathLength]; + memset(pathMem, 0, sizeof(pathMem)); + + for (std::string::iterator ch = path.begin(); ch != path.end(); ++ch) + pathMem[std::distance(path.begin(), ch)] = tolower(*ch); + + WRITE_STR(pathMem, CXBTFFile::MaximumPathLength, m_file); + WRITE_U32(file.GetLoop(), m_file); + + std::vector<CXBTFFrame>& frames = file.GetFrames(); + WRITE_U32(frames.size(), m_file); + for (size_t j = 0; j < frames.size(); j++) + { + CXBTFFrame& frame = frames[j]; + if (dupes[i] != i) + frame.SetOffset(files[dupes[i]].GetFrames()[j].GetOffset()); + else + { + frame.SetOffset(offset); + offset += frame.GetPackedSize(); + } + + WRITE_U32(frame.GetWidth(), m_file); + WRITE_U32(frame.GetHeight(), m_file); + WRITE_U32(frame.GetFormat(true), m_file); + WRITE_U64(frame.GetPackedSize(), m_file); + WRITE_U64(frame.GetUnpackedSize(), m_file); + WRITE_U32(frame.GetDuration(), m_file); + WRITE_U64(frame.GetOffset(), m_file); + } + } + + // Sanity check + int64_t pos = ftell(m_file); + if (pos != static_cast<int64_t>(headerSize)) + { + printf("Expected header size (%" PRIu64 ") != actual size (%" PRId64 ")\n", headerSize, pos); + return false; + } + + return true; +} diff --git a/tools/depends/native/TexturePacker/src/XBTFWriter.h b/tools/depends/native/TexturePacker/src/XBTFWriter.h new file mode 100644 index 0000000..1e6496d --- /dev/null +++ b/tools/depends/native/TexturePacker/src/XBTFWriter.h @@ -0,0 +1,48 @@ +/* + * Copyright (C) 2005-2013 Team XBMC + * http://kodi.tv + * + * This Program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2, or (at your option) + * any later version. + * + * This Program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with XBMC; see the file COPYING. If not, see + * <http://www.gnu.org/licenses/>. + * + */ + +#pragma once + +#include "guilib/XBTF.h" + +#include <cstdio> +#include <string> +#include <vector> + +class CXBTFWriter : public CXBTFBase +{ +public: + CXBTFWriter(const std::string& outputFile); + ~CXBTFWriter() override; + + bool Create(); + bool Close(); + bool AppendContent(unsigned char const* data, size_t length); + bool UpdateHeader(const std::vector<unsigned int>& dupes); + +private: + void Cleanup(); + + std::string m_outputFile; + FILE* m_file; + unsigned char *m_data; + size_t m_size; +}; + diff --git a/tools/depends/native/TexturePacker/src/autogen.sh b/tools/depends/native/TexturePacker/src/autogen.sh new file mode 100755 index 0000000..bbec436 --- /dev/null +++ b/tools/depends/native/TexturePacker/src/autogen.sh @@ -0,0 +1,3 @@ +#/bin/sh + +autoreconf -vif diff --git a/tools/depends/native/TexturePacker/src/cmdlineargs.h b/tools/depends/native/TexturePacker/src/cmdlineargs.h new file mode 100644 index 0000000..d0b9d03 --- /dev/null +++ b/tools/depends/native/TexturePacker/src/cmdlineargs.h @@ -0,0 +1,148 @@ +/* + * Copyright (C) 2005-2013 Team XBMC + * http://kodi.tv + * + * This Program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2, or (at your option) + * any later version. + * + * This Program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with XBMC; see the file COPYING. If not, see + * <http://www.gnu.org/licenses/>. + * + */ + +#pragma once + +#ifdef TARGET_POSIX +char* GetCommandLine(); +#define _snprintf snprintf +#else +#include <windows.h> +#endif +#include <vector> +#include <string> + +class CmdLineArgs : public std::vector<char*> +{ +public: + CmdLineArgs () + { + // Save local copy of the command line string, because + // ParseCmdLine() modifies this string while parsing it. + char* cmdline = GetCommandLine(); + m_cmdline = new char [strlen (cmdline) + 1]; + if (m_cmdline) + { + strcpy (m_cmdline, cmdline); + ParseCmdLine(); + } else { +#ifdef TARGET_POSIX + delete[] cmdline; +#endif + } + } + + CmdLineArgs (const int argc, const char **argv) + { + std::string cmdline; +#ifdef TARGET_POSIX + cmdline = "\""; +#endif + for (int i = 0 ; i<argc ; i++) + { + cmdline += std::string(argv[i]); + if ( i != (argc-1) ) + { +#ifdef TARGET_POSIX + cmdline += "\" \""; +#else + cmdline += " "; +#endif + } + } +#ifdef TARGET_POSIX + cmdline += "\""; +#endif + m_cmdline = new char [cmdline.length() + 1]; + if (m_cmdline) + { + strcpy(m_cmdline, cmdline.c_str()); + ParseCmdLine(); + } + } + + ~CmdLineArgs() + { + delete[] m_cmdline; + } + +private: + char* m_cmdline; // the command line string + + //////////////////////////////////////////////////////////////////////////////// + // Parse m_cmdline into individual tokens, which are delimited by spaces. If a + // token begins with a quote, then that token is terminated by the next quote + // followed immediately by a space or terminator. This allows tokens to contain + // spaces. + // This input string: This "is" a ""test"" "of the parsing" alg"o"rithm. + // Produces these tokens: This, is, a, "test", of the parsing, alg"o"rithm + //////////////////////////////////////////////////////////////////////////////// + void ParseCmdLine () + { + enum { TERM = '\0', + QUOTE = '\"' }; + + bool bInQuotes = false; + char* pargs = m_cmdline; + + while (*pargs) + { + while (isspace (*pargs)) // skip leading whitespace + pargs++; + + bInQuotes = (*pargs == QUOTE); // see if this token is quoted + + if (bInQuotes) // skip leading quote + pargs++; + + push_back (pargs); // store position of current token + + // Find next token. + // NOTE: Args are normally terminated by whitespace, unless the + // arg is quoted. That's why we handle the two cases separately, + // even though they are very similar. + if (bInQuotes) + { + // find next quote followed by a space or terminator + while (*pargs && + !(*pargs == QUOTE && (isspace (pargs[1]) || pargs[1] == TERM))) + pargs++; + if (*pargs) + { + *pargs = TERM; // terminate token + if (pargs[1]) // if quoted token not followed by a terminator + pargs += 2; // advance to next token + } + } + else + { + // skip to next non-whitespace character + while (*pargs && !isspace (*pargs)) + pargs++; + if (*pargs && isspace (*pargs)) // end of token + { + *pargs = TERM; // terminate token + pargs++; // advance to next token or terminator + } + } + } // while (*pargs) + } // ParseCmdLine() +}; // class CmdLineArgs + diff --git a/tools/depends/native/TexturePacker/src/configure.ac b/tools/depends/native/TexturePacker/src/configure.ac new file mode 100644 index 0000000..4b83b5e --- /dev/null +++ b/tools/depends/native/TexturePacker/src/configure.ac @@ -0,0 +1,41 @@ +dnl Process this file with autoconf to produce a configure script. +AC_INIT(TexturePacker, 1.0) +AC_CONFIG_AUX_DIR(config) +AC_CONFIG_HEADERS([config.h]) +AC_CONFIG_SRCDIR(TexturePacker.cpp) +AM_INIT_AUTOMAKE([foreign]) +AC_PROG_CXX +AC_LANG([C++]) +AC_C_BIGENDIAN + +abs_top_srcdir=${abs_top_srcdir=$(cd $srcdir; pwd)} +KODI_SRC_DIR=${KODI_SRC_DIR:-"${abs_top_srcdir}/../../../../.."} + +AC_ARG_ENABLE([static], + [AS_HELP_STRING([--enable-static], + [build static TexturePacker (default is no)])], + [STATIC_FLAG="-static"], + [STATIC_FLAG=""]) + + +PKG_CHECK_MODULES([PNG], [libpng], + [INCLUDES="$PNG_CFLAGS"; LIBS="$LIBS $(${PKG_CONFIG} --silence-errors --static --libs libpng)"], + AC_MSG_ERROR("libpng not found")) + +AC_CHECK_HEADER([gif_lib.h],, AC_MSG_ERROR("gif_lib.h not found")) +AC_COMPILE_IFELSE([AC_LANG_PROGRAM([[#include <gif_lib.h>]], [[ +#if !defined GIFLIB_MAJOR || GIFLIB_MAJOR < 5 +#error libgif version < 5; +#endif ]])], [], [AC_MSG_NOTICE([[WARNING: libgif version is unsupported, please consider upgrading to 5.0.5 or higher.]])]) + +AC_CHECK_LIB([gif],[main],, AC_MSG_ERROR("libgif not found")) +AC_CHECK_HEADER([jpeglib.h],, AC_MSG_ERROR("jpeglib.h not found")) +AC_CHECK_LIB([jpeg],[main],, AC_MSG_ERROR("libjpeg not found")) +AC_CHECK_HEADER([lzo/lzo1x.h],, AC_MSG_ERROR("lzo/lzo1x.h not found")) +AC_CHECK_LIB([lzo2],[main],, AC_MSG_ERROR("liblzo2 not found")) + +AC_SUBST(KODI_SRC_DIR) +AC_SUBST(STATIC_FLAG) +AC_SUBST(EXTRA_DEFINES) + +AC_OUTPUT(Makefile) diff --git a/tools/depends/native/TexturePacker/src/decoder/GIFDecoder.cpp b/tools/depends/native/TexturePacker/src/decoder/GIFDecoder.cpp new file mode 100644 index 0000000..5bdfacd --- /dev/null +++ b/tools/depends/native/TexturePacker/src/decoder/GIFDecoder.cpp @@ -0,0 +1,79 @@ +/* + * Copyright (C) 2014 Team Kodi + * http://kodi.tv + * + * This Program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2, or (at your option) + * any later version. + * + * This Program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with XBMC; see the file COPYING. If not, see + * <http://www.gnu.org/licenses/>. + * + */ + +#include "GIFDecoder.h" + +#include "GifHelper.h" + +#include <cstring> + +// returns true for gif files, otherwise returns false +bool GIFDecoder::CanDecode(const std::string &filename) +{ + return std::string::npos != filename.rfind(".gif",filename.length() - 4, 4); +} + +bool GIFDecoder::LoadFile(const std::string &filename, DecodedFrames &frames) +{ + int n = 0; + bool result = false; + + GifHelper *gifImage = new GifHelper(); + if (gifImage->LoadGif(filename.c_str())) + { + auto extractedFrames = gifImage->GetFrames(); + n = extractedFrames.size(); + if (n > 0) + { + unsigned int height = gifImage->GetHeight(); + unsigned int width = gifImage->GetWidth(); + unsigned int pitch = gifImage->GetPitch(); + unsigned int frameSize = pitch * height; + for (unsigned int i = 0; i < extractedFrames.size(); i++) + { + DecodedFrame frame; + + frame.rgbaImage.pixels = (char *)new char[frameSize]; + memcpy(frame.rgbaImage.pixels, extractedFrames[i]->m_pImage, frameSize); + frame.rgbaImage.height = height; + frame.rgbaImage.width = width; + frame.rgbaImage.bbp = 32; + frame.rgbaImage.pitch = pitch; + frame.delay = extractedFrames[i]->m_delay; + frame.decoder = this; + + frames.frameList.push_back(frame); + } + } + result = true; + } + delete gifImage; + return result; +} + +void GIFDecoder::FreeDecodedFrame(DecodedFrame &frame) +{ + delete [] frame.rgbaImage.pixels; +} + +void GIFDecoder::FillSupportedExtensions() +{ + m_supportedExtensions.emplace_back(".gif"); +} diff --git a/tools/depends/native/TexturePacker/src/decoder/GIFDecoder.h b/tools/depends/native/TexturePacker/src/decoder/GIFDecoder.h new file mode 100644 index 0000000..8f0b42d --- /dev/null +++ b/tools/depends/native/TexturePacker/src/decoder/GIFDecoder.h @@ -0,0 +1,36 @@ +/* + * Copyright (C) 2014 Team Kodi + * http://kodi.tv + * + * This Program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2, or (at your option) + * any later version. + * + * This Program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with XBMC; see the file COPYING. If not, see + * <http://www.gnu.org/licenses/>. + * + */ + +#pragma once + +#include "IDecoder.h" + +class GIFDecoder : public IDecoder +{ + public: + ~GIFDecoder() override = default; + bool CanDecode(const std::string &filename) override; + bool LoadFile(const std::string &filename, DecodedFrames &frames) override; + void FreeDecodedFrame(DecodedFrame &frame) override; + const char* GetImageFormatName() override { return "GIF"; } + const char* GetDecoderName() override { return "libgif"; } + protected: + void FillSupportedExtensions() override; +}; diff --git a/tools/depends/native/TexturePacker/src/decoder/GifHelper.cpp b/tools/depends/native/TexturePacker/src/decoder/GifHelper.cpp new file mode 100644 index 0000000..41ca270 --- /dev/null +++ b/tools/depends/native/TexturePacker/src/decoder/GifHelper.cpp @@ -0,0 +1,493 @@ +/* + * Copyright (C) 2014 Team Kodi + * http://kodi.tv + * + * This Program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2, or (at your option) + * any later version. + * + * This Program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with XBMC; see the file COPYING. If not, see + * <http://www.gnu.org/licenses/>. + * + */ + +#include "GifHelper.h" + +#include <algorithm> +#include <cstdlib> +#include <cstring> + +#define UNSIGNED_LITTLE_ENDIAN(lo, hi) ((lo) | ((hi) << 8)) +#define GIF_MAX_MEMORY 82944000U // about 79 MB, which is equivalent to 10 full hd frames. + +class Gifreader +{ +public: + unsigned char* buffer = nullptr; + unsigned int buffSize = 0; + unsigned int readPosition = 0; + + Gifreader() = default; +}; + +int ReadFromVfs(GifFileType* gif, GifByteType* gifbyte, int len) +{ + CFile *gifFile = static_cast<CFile*>(gif->UserData); + return gifFile->Read(gifbyte, len); +} + +GifHelper::GifHelper() +{ + m_gifFile = new CFile(); +} + +GifHelper::~GifHelper() +{ + Close(m_gif); + Release(); + delete m_gifFile; +} + +bool GifHelper::Open(GifFileType*& gif, void *dataPtr, InputFunc readFunc) +{ + int err = 0; +#if GIFLIB_MAJOR == 5 + gif = DGifOpen(dataPtr, readFunc, &err); +#else + gif = DGifOpen(dataPtr, readFunc); + if (!gif) + err = GifLastError(); +#endif + + if (!gif) + { + fprintf(stderr, "Gif::Open(): Could not open file %s. Reason: %s\n", m_filename.c_str(), GifErrorString(err)); + return false; + } + + return true; +} + +void GifHelper::Close(GifFileType* gif) +{ + int err = 0; + int reason = 0; +#if GIFLIB_MAJOR == 5 && GIFLIB_MINOR >= 1 + err = DGifCloseFile(gif, &reason); +#else + err = DGifCloseFile(gif); +#if GIFLIB_MAJOR < 5 + reason = GifLastError(); +#endif + if (err == GIF_ERROR) + free(gif); +#endif + if (err == GIF_ERROR) + { + fprintf(stderr, "GifHelper::Close(): closing file %s failed. Reason: %s\n", m_filename.c_str(), Reason(reason)); + } +} + +const char* GifHelper::Reason(int reason) +{ + const char* err = GifErrorString(reason); + if (err) + return err; + + return "unknown"; + +} + +void GifHelper::Release() +{ + delete[] m_pTemplate; + m_pTemplate = nullptr; + m_globalPalette.clear(); + m_frames.clear(); +} + +void GifHelper::ConvertColorTable(std::vector<GifColor> &dest, ColorMapObject* src, unsigned int size) +{ + for (unsigned int i = 0; i < size; ++i) + { + GifColor c; + + c.r = src->Colors[i].Red; + c.g = src->Colors[i].Green; + c.b = src->Colors[i].Blue; + c.a = 0xff; + dest.push_back(c); + } +} + +bool GifHelper::LoadGifMetaData(GifFileType* gif) +{ + if (!Slurp(gif)) + return false; + + m_height = gif->SHeight; + m_width = gif->SWidth; + if (!m_height || !m_width) + { + fprintf(stderr, "Gif::LoadGif(): Zero sized image. File %s\n", m_filename.c_str()); + return false; + } + + m_numFrames = gif->ImageCount; + if (m_numFrames > 0) + { + ExtensionBlock* extb = gif->SavedImages[0].ExtensionBlocks; + if (extb && extb->Function == APPLICATION_EXT_FUNC_CODE) + { + // Read number of loops + if (++extb && extb->Function == CONTINUE_EXT_FUNC_CODE) + { + uint8_t low = static_cast<uint8_t>(extb->Bytes[1]); + uint8_t high = static_cast<uint8_t>(extb->Bytes[2]); + m_loops = UNSIGNED_LITTLE_ENDIAN(low, high); + } + } + } + else + { + fprintf(stderr, "Gif::LoadGif(): No images found in file %s\n", m_filename.c_str()); + return false; + } + + m_pitch = m_width * sizeof(GifColor); + m_imageSize = m_pitch * m_height; + unsigned long memoryUsage = m_numFrames * m_imageSize; + if (memoryUsage > GIF_MAX_MEMORY) + { + // at least 1 image + m_numFrames = std::max(1U, GIF_MAX_MEMORY / m_imageSize); + fprintf(stderr, "Gif::LoadGif(): Memory consumption too high: %lu bytes. Restricting animation to %u. File %s\n", memoryUsage, m_numFrames, m_filename.c_str()); + } + + return true; +} + +bool GifHelper::LoadGifMetaData(const char* file) +{ + m_gifFile->Close(); + if (!m_gifFile->Open(file) || !Open(m_gif, m_gifFile, ReadFromVfs)) + return false; + + return LoadGifMetaData(m_gif); +} + +bool GifHelper::Slurp(GifFileType* gif) +{ + if (DGifSlurp(gif) == GIF_ERROR) + { + int reason = 0; +#if GIFLIB_MAJOR == 5 + reason = gif->Error; +#else + reason = GifLastError(); +#endif + fprintf(stderr, "Gif::LoadGif(): Could not read file %s. Reason: %s\n", m_filename.c_str(), GifErrorString(reason)); + return false; + } + + return true; +} + +bool GifHelper::LoadGif(const char* file) +{ + m_filename = file; + if (!LoadGifMetaData(m_filename.c_str())) + return false; + + try + { + InitTemplateAndColormap(); + + int extractedFrames = ExtractFrames(m_numFrames); + if (extractedFrames < 0) + { + fprintf(stderr, "Gif::LoadGif(): Could not extract any frame. File %s\n", m_filename.c_str()); + return false; + } + else if (extractedFrames < (int)m_numFrames) + { + fprintf(stderr, "Gif::LoadGif(): Could only extract %d/%d frames. File %s\n", extractedFrames, m_numFrames, m_filename.c_str()); + m_numFrames = extractedFrames; + } + + return true; + } + catch (std::bad_alloc& ba) + { + fprintf(stderr, "Gif::Load(): Out of memory while reading file %s - %s\n", m_filename.c_str(), ba.what()); + Release(); + return false; + } +} + +void GifHelper::InitTemplateAndColormap() +{ + m_pTemplate = new unsigned char[m_imageSize]; + memset(m_pTemplate, 0, m_imageSize); + + if (m_gif->SColorMap) + { + m_globalPalette.clear(); + ConvertColorTable(m_globalPalette, m_gif->SColorMap, m_gif->SColorMap->ColorCount); + } + else + m_globalPalette.clear(); +} + +bool GifHelper::GcbToFrame(GifFrame &frame, unsigned int imgIdx) +{ + int transparent = -1; + frame.m_delay = 0; + frame.m_disposal = 0; + + if (m_gif->ImageCount > 0) + { +#if GIFLIB_MAJOR == 5 + GraphicsControlBlock gcb; + if (DGifSavedExtensionToGCB(m_gif, imgIdx, &gcb)) + { + // delay in ms + frame.m_delay = gcb.DelayTime * 10; + frame.m_disposal = gcb.DisposalMode; + transparent = gcb.TransparentColor; + } +#else + ExtensionBlock* extb = m_gif->SavedImages[imgIdx].ExtensionBlocks; + while (extb && extb->Function != GRAPHICS_EXT_FUNC_CODE) + extb++; + + if (extb && extb->ByteCount == 4) + { + uint8_t low = static_cast<uint8_t>(extb->Bytes[1]); + uint8_t high = static_cast<uint8_t>(extb->Bytes[2]); + frame.m_delay = UNSIGNED_LITTLE_ENDIAN(low, high) * 10; + frame.m_disposal = (extb->Bytes[0] >> 2) & 0x07; + if (extb->Bytes[0] & 0x01) + { + transparent = static_cast<uint8_t>(extb->Bytes[3]); + } + else + transparent = -1; + } +#endif + } + + if (transparent >= 0 && (unsigned)transparent < frame.m_palette.size()) + frame.m_palette[transparent].a = 0; + return true; +} + +int GifHelper::ExtractFrames(unsigned int count) +{ + if (!m_gif) + return -1; + + if (!m_pTemplate) + { + fprintf(stderr, "Gif::ExtractFrames(): No frame template available\n"); + return -1; + } + + int extracted = 0; + for (unsigned int i = 0; i < count; i++) + { + FramePtr frame(new GifFrame); + SavedImage savedImage = m_gif->SavedImages[i]; + GifImageDesc imageDesc = m_gif->SavedImages[i].ImageDesc; + frame->m_height = imageDesc.Height; + frame->m_width = imageDesc.Width; + frame->m_top = imageDesc.Top; + frame->m_left = imageDesc.Left; + + if (frame->m_top + frame->m_height > m_height || frame->m_left + frame->m_width > m_width + || !frame->m_width || !frame->m_height + || frame->m_width > m_width || frame->m_height > m_height) + { + fprintf(stderr, "Gif::ExtractFrames(): Illegal frame dimensions: width: %d, height: %d, left: %d, top: %d instead of (%d,%d), skip it\n", + frame->m_width, frame->m_height, frame->m_left, frame->m_top, m_width, m_height); + continue; + } + + if (imageDesc.ColorMap) + { + frame->m_palette.clear(); + ConvertColorTable(frame->m_palette, imageDesc.ColorMap, imageDesc.ColorMap->ColorCount); + // TODO save a backup of the palette for frames without a table in case there's no global table. + } + else if (m_gif->SColorMap) + { + frame->m_palette = m_globalPalette; + } + else + { + fprintf(stderr, "Gif::ExtractFrames(): No color map found for frame %d, skip it\n", i); + continue; + } + + // fill delay, disposal and transparent color into frame + if (!GcbToFrame(*frame, i)) + { + fprintf(stderr, "Gif::ExtractFrames(): Corrupted Graphics Control Block for frame %d, skip it\n", i); + continue; + } + + frame->m_pImage = new unsigned char[m_imageSize]; + frame->m_imageSize = m_imageSize; + memcpy(frame->m_pImage, m_pTemplate, m_imageSize); + + ConstructFrame(*frame, savedImage.RasterBits); + + if (!PrepareTemplate(*frame)) + { + fprintf(stderr, "Gif::ExtractFrames(): Could not prepare template after frame %d, skip it\n", i); + continue; + } + + extracted++; + m_frames.push_back(frame); + } + return extracted; +} + +void GifHelper::ConstructFrame(GifFrame &frame, const unsigned char* src) const +{ + size_t paletteSize = frame.m_palette.size(); + + for (unsigned int dest_y = frame.m_top, src_y = 0; src_y < frame.m_height; ++dest_y, ++src_y) + { + unsigned char *to = frame.m_pImage + (dest_y * m_pitch) + (frame.m_left * sizeof(GifColor)); + + const unsigned char *from = src + (src_y * frame.m_width); + for (unsigned int src_x = 0; src_x < frame.m_width; ++src_x) + { + unsigned char index = *from++; + + if (index >= paletteSize) + { + fprintf(stderr, "Gif::ConstructFrame(): Pixel (%d,%d) has no valid palette entry, skip it\n", src_x, src_y); + continue; + } + + GifColor col = frame.m_palette[index]; + if (col.a != 0) + memcpy(to, &col, sizeof(GifColor)); + + to += 4; + } + } +} + +bool GifHelper::PrepareTemplate(GifFrame &frame) +{ + switch (frame.m_disposal) + { + /* No disposal specified. */ + case DISPOSAL_UNSPECIFIED: + /* Leave image in place */ + case DISPOSE_DO_NOT: + memcpy(m_pTemplate, frame.m_pImage, m_imageSize); + break; + + /* + Clear the frame's area to transparency. + The disposal names is misleading. Do not restore to the background color because + this part of the specification is ignored by all browsers/image viewers. + */ + case DISPOSE_BACKGROUND: + { + ClearFrameAreaToTransparency(m_pTemplate, frame); + break; + } + /* Restore to previous content */ + case DISPOSE_PREVIOUS: + { + + /* + * This disposal method makes no sense for the first frame + * Since browsers etc. handle that too, we'll fall back to DISPOSE_DO_NOT + */ + if (m_frames.empty()) + { + frame.m_disposal = DISPOSE_DO_NOT; + return PrepareTemplate(frame); + } + + bool valid = false; + + for (int i = m_frames.size() - 1; i >= 0; --i) + { + if (m_frames[i]->m_disposal != DISPOSE_PREVIOUS) + { + memcpy(m_pTemplate, m_frames[i]->m_pImage, m_imageSize); + valid = true; + break; + } + } + if (!valid) + { + fprintf(stderr, "Gif::PrepareTemplate(): Disposal method DISPOSE_PREVIOUS encountered, but could not find a suitable frame.\n"); + return false; + } + break; + } + default: + { + fprintf(stderr, "Gif::PrepareTemplate(): Unknown disposal method: %d. Using DISPOSAL_UNSPECIFIED, the animation might be wrong now.\n", frame.m_disposal); + frame.m_disposal = DISPOSAL_UNSPECIFIED; + return PrepareTemplate(frame); + } + } + return true; +} + +void GifHelper::ClearFrameAreaToTransparency(unsigned char* dest, const GifFrame &frame) +{ + for (unsigned int dest_y = frame.m_top, src_y = 0; src_y < frame.m_height; ++dest_y, ++src_y) + { + unsigned char *to = dest + (dest_y * m_pitch) + (frame.m_left * sizeof(GifColor)); + for (unsigned int src_x = 0; src_x < frame.m_width; ++src_x) + { + to += 3; + *to++ = 0; + } + } +} + +GifFrame::GifFrame(const GifFrame& src) + : m_delay(src.m_delay), + m_top(src.m_top), + m_left(src.m_left), + m_disposal(src.m_disposal), + m_height(src.m_height), + m_width(src.m_width), + m_imageSize(src.m_imageSize) +{ + if (src.m_pImage) + { + m_pImage = new unsigned char[m_imageSize]; + memcpy(m_pImage, src.m_pImage, m_imageSize); + } + + if (src.m_palette.size()) + { + m_palette = src.m_palette; + } +} + +GifFrame::~GifFrame() +{ + delete[] m_pImage; + m_pImage = nullptr; +} diff --git a/tools/depends/native/TexturePacker/src/decoder/GifHelper.h b/tools/depends/native/TexturePacker/src/decoder/GifHelper.h new file mode 100644 index 0000000..1e897a7 --- /dev/null +++ b/tools/depends/native/TexturePacker/src/decoder/GifHelper.h @@ -0,0 +1,220 @@ +/* + * Copyright (C) 2014 Team Kodi + * http://kodi.tv + * + * This Program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2, or (at your option) + * any later version. + * + * This Program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with XBMC; see the file COPYING. If not, see + * <http://www.gnu.org/licenses/>. + * + */ + +#pragma once + +#include <gif_lib.h> +#ifndef CONTINUE_EXT_FUNC_CODE +#define CONTINUE_EXT_FUNC_CODE 0 +#endif + +#ifndef DISPOSAL_UNSPECIFIED +#define DISPOSAL_UNSPECIFIED 0 +#endif + +#ifndef DISPOSE_DO_NOT +#define DISPOSE_DO_NOT 1 +#endif + +#ifndef DISPOSE_BACKGROUND +#define DISPOSE_BACKGROUND 2 +#endif + +#ifndef DISPOSE_PREVIOUS +#define DISPOSE_PREVIOUS 3 +#endif + +#include <vector> +#include <string> +#include <memory> +#include "SimpleFS.h" + +#pragma pack(1) +struct GifColor +{ + uint8_t b, g, r, a; +}; +#pragma pack() + +class CFile; + +class GifFrame +{ + friend class GifHelper; +public: + + GifFrame() = default; + virtual ~GifFrame(); + + unsigned char* m_pImage = nullptr; + unsigned int m_delay = 0; + +private: + GifFrame(const GifFrame& src); + + unsigned int m_top = 0; + unsigned int m_left = 0; + unsigned int m_disposal = 0; + unsigned int m_height = 0; + unsigned int m_width = 0; + unsigned int m_imageSize = 0; + std::vector<GifColor> m_palette; +}; + + + +class GifHelper +{ + friend class GifFrame; + + typedef std::shared_ptr<GifFrame> FramePtr; + +public: + GifHelper(); + virtual ~GifHelper(); + + + bool LoadGif(const char* file); + + std::vector<FramePtr>& GetFrames() { return m_frames; } + unsigned int GetPitch() const { return m_pitch; } + unsigned int GetNumLoops() const { return m_loops; } + unsigned int GetWidth() const { return m_width; } + unsigned int GetHeight() const { return m_height; } + +private: + std::vector<FramePtr> m_frames; + unsigned int m_imageSize = 0; + unsigned int m_pitch = 0; + unsigned int m_loops = 0; + unsigned int m_numFrames = 0; + + std::string m_filename; + GifFileType* m_gif = nullptr; + std::vector<GifColor> m_globalPalette; + unsigned char* m_pTemplate = nullptr; + CFile* m_gifFile; + + unsigned int m_width; + unsigned int m_height; + + bool Open(GifFileType *& gif, void * dataPtr, InputFunc readFunc); + void Close(GifFileType * gif); + + const char* Reason(int reason); + + bool LoadGifMetaData(const char* file); + bool Slurp(GifFileType* gif); + void InitTemplateAndColormap(); + bool LoadGifMetaData(GifFileType* gif); + static void ConvertColorTable(std::vector<GifColor> &dest, ColorMapObject* src, unsigned int size); + bool GcbToFrame(GifFrame &frame, unsigned int imgIdx); + int ExtractFrames(unsigned int count); + void ClearFrameAreaToTransparency(unsigned char* dest, const GifFrame &frame); + void ConstructFrame(GifFrame &frame, const unsigned char* src) const; + bool PrepareTemplate(GifFrame &frame); + void Release(); + +#if GIFLIB_MAJOR != 5 + /* + taken from giflib 5.1.0 + */ + const char* GifErrorString(int ErrorCode) + { + const char *Err; + + switch (ErrorCode) { + case E_GIF_ERR_OPEN_FAILED: + Err = "Failed to open given file"; + break; + case E_GIF_ERR_WRITE_FAILED: + Err = "Failed to write to given file"; + break; + case E_GIF_ERR_HAS_SCRN_DSCR: + Err = "Screen descriptor has already been set"; + break; + case E_GIF_ERR_HAS_IMAG_DSCR: + Err = "Image descriptor is still active"; + break; + case E_GIF_ERR_NO_COLOR_MAP: + Err = "Neither global nor local color map"; + break; + case E_GIF_ERR_DATA_TOO_BIG: + Err = "Number of pixels bigger than width * height"; + break; + case E_GIF_ERR_NOT_ENOUGH_MEM: + Err = "Failed to allocate required memory"; + break; + case E_GIF_ERR_DISK_IS_FULL: + Err = "Write failed (disk full?)"; + break; + case E_GIF_ERR_CLOSE_FAILED: + Err = "Failed to close given file"; + break; + case E_GIF_ERR_NOT_WRITEABLE: + Err = "Given file was not opened for write"; + break; + case D_GIF_ERR_OPEN_FAILED: + Err = "Failed to open given file"; + break; + case D_GIF_ERR_READ_FAILED: + Err = "Failed to read from given file"; + break; + case D_GIF_ERR_NOT_GIF_FILE: + Err = "Data is not in GIF format"; + break; + case D_GIF_ERR_NO_SCRN_DSCR: + Err = "No screen descriptor detected"; + break; + case D_GIF_ERR_NO_IMAG_DSCR: + Err = "No Image Descriptor detected"; + break; + case D_GIF_ERR_NO_COLOR_MAP: + Err = "Neither global nor local color map"; + break; + case D_GIF_ERR_WRONG_RECORD: + Err = "Wrong record type detected"; + break; + case D_GIF_ERR_DATA_TOO_BIG: + Err = "Number of pixels bigger than width * height"; + break; + case D_GIF_ERR_NOT_ENOUGH_MEM: + Err = "Failed to allocate required memory"; + break; + case D_GIF_ERR_CLOSE_FAILED: + Err = "Failed to close given file"; + break; + case D_GIF_ERR_NOT_READABLE: + Err = "Given file was not opened for read"; + break; + case D_GIF_ERR_IMAGE_DEFECT: + Err = "Image is defective, decoding aborted"; + break; + case D_GIF_ERR_EOF_TOO_SOON: + Err = "Image EOF detected before image complete"; + break; + default: + Err = NULL; + break; + } + return Err; + } +#endif +}; diff --git a/tools/depends/native/TexturePacker/src/decoder/IDecoder.h b/tools/depends/native/TexturePacker/src/decoder/IDecoder.h new file mode 100644 index 0000000..673ff1a --- /dev/null +++ b/tools/depends/native/TexturePacker/src/decoder/IDecoder.h @@ -0,0 +1,99 @@ +/* + * Copyright (C) 2014 Team Kodi + * http://kodi.tv + * + * This Program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2, or (at your option) + * any later version. + * + * This Program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with XBMC; see the file COPYING. If not, see + * <http://www.gnu.org/licenses/>. + * + */ + +#pragma once + +#include <cstdint> +#include <string> +#include <vector> + +/* forward declarations */ + +class DecodedFrame; +class DecodedFrames; + +class IDecoder +{ + public: + virtual ~IDecoder() = default; + virtual bool CanDecode(const std::string &filename) = 0; + virtual bool LoadFile(const std::string &filename, DecodedFrames &frames) = 0; + virtual void FreeDecodedFrame(DecodedFrame &frame) = 0; + virtual const char* GetImageFormatName() = 0; + virtual const char* GetDecoderName() = 0; + + const std::vector<std::string>& GetSupportedExtensions() + { + m_supportedExtensions.clear(); + FillSupportedExtensions(); + return m_supportedExtensions; + } + + protected: + virtual void FillSupportedExtensions() = 0; + //fill this with extensions in FillSupportedExtensions like ".png" + std::vector<std::string> m_supportedExtensions; +}; + +class RGBAImage +{ +public: + RGBAImage() = default; + + char* pixels = nullptr; // image data + int width = 0; // width + int height = 0; // height + int bbp = 0; // bits per pixel + int pitch = 0; // rowsize in bytes +}; + +class DecodedFrame +{ +public: + DecodedFrame() = default; + RGBAImage rgbaImage; /* rgbaimage for this frame */ + int delay = 0; /* Frame delay in ms */ + IDecoder* decoder = nullptr; /* Pointer to decoder */ +}; + +class DecodedFrames +{ + public: + DecodedFrames() = default; + std::vector<DecodedFrame> frameList; + + void clear() + { + for (auto f : frameList) + { + if (f.decoder != NULL) + { + f.decoder->FreeDecodedFrame(f); + } + else + { + fprintf(stderr, + "ERROR: %s - can not determine decoder type for frame!\n", + __FUNCTION__); + } + } + frameList.clear(); + } +}; diff --git a/tools/depends/native/TexturePacker/src/decoder/JPGDecoder.cpp b/tools/depends/native/TexturePacker/src/decoder/JPGDecoder.cpp new file mode 100644 index 0000000..ce06d28 --- /dev/null +++ b/tools/depends/native/TexturePacker/src/decoder/JPGDecoder.cpp @@ -0,0 +1,137 @@ +/* + * Copyright (C) 2014 Team Kodi + * http://kodi.tv + * + * This Program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2, or (at your option) + * any later version. + * + * This Program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with XBMC; see the file COPYING. If not, see + * <http://www.gnu.org/licenses/>. + * + */ + +#include "JPGDecoder.h" + +#include "SimpleFS.h" + +#include <jpeglib.h> + +bool JPGDecoder::CanDecode(const std::string &filename) +{ + CFile *fp = new CFile(); + bool ret = false; + unsigned char magic[2]; + if (fp->Open(filename)) + { + + //JPEG image files begin with FF D8 and end with FF D9. + // check for FF D8 big + little endian on start + uint64_t readbytes = fp->Read(magic, 2); + if (readbytes == 2) + { + if ((magic[0] == 0xd8 && magic[1] == 0xff) || + (magic[1] == 0xd8 && magic[0] == 0xff)) + ret = true; + } + + if (ret) + { + ret = false; + //check on FF D9 big + little endian on end + uint64_t fileSize = fp->GetFileSize(); + fp->Seek(fileSize - 2); + readbytes = fp->Read(magic, 2); + if (readbytes == 2) + { + if ((magic[0] == 0xd9 && magic[1] == 0xff) || + (magic[1] == 0xd9 && magic[0] == 0xff)) + ret = true; + } + } + } + delete fp; + return ret; +} + +bool JPGDecoder::LoadFile(const std::string &filename, DecodedFrames &frames) +{ + #define WIDTHBYTES(bits) ((((bits) + 31) / 32) * 4) + CFile *arq = new CFile(); + if (!arq->Open(filename)) + { + delete arq; + return false; + } + + struct jpeg_decompress_struct cinfo; + struct jpeg_error_mgr jerr; + + int ImageSize; + + cinfo.err = jpeg_std_error(&jerr); + jpeg_create_decompress(&cinfo); + + jpeg_stdio_src(&cinfo, arq->getFP()); + jpeg_read_header(&cinfo, TRUE); + jpeg_start_decompress(&cinfo); + + // Image Size is calculated as (width * height * bytes per pixel = 4 + ImageSize = cinfo.image_width * cinfo.image_height * 4; + + DecodedFrame frame; + + frame.rgbaImage.pixels = (char *)new char[ImageSize]; + + unsigned char *scanlinebuff = new unsigned char[3 * cinfo.image_width]; + unsigned char *dst = (unsigned char *)frame.rgbaImage.pixels; + while (cinfo.output_scanline < cinfo.output_height) + { + jpeg_read_scanlines(&cinfo,&scanlinebuff,1); + + unsigned char *src2 = scanlinebuff; + unsigned char *dst2 = dst; + for (unsigned int x = 0; x < cinfo.image_width; x++, src2 += 3) + { + *dst2++ = src2[2]; + *dst2++ = src2[1]; + *dst2++ = src2[0]; + *dst2++ = 0xff; + } + dst += cinfo.image_width * 4; + } + delete [] scanlinebuff; + + jpeg_finish_decompress(&cinfo); + jpeg_destroy_decompress(&cinfo); + + frame.rgbaImage.height = cinfo.image_height; + frame.rgbaImage.width = cinfo.image_width; + frame.rgbaImage.bbp = 32; + frame.rgbaImage.pitch = 4 * cinfo.image_width; + + frame.decoder = this; + + frames.frameList.push_back(frame); + + delete arq; + return true; +} + +void JPGDecoder::FreeDecodedFrame(DecodedFrame &frame) +{ + delete [] frame.rgbaImage.pixels; +} + +void JPGDecoder::FillSupportedExtensions() +{ + m_supportedExtensions.emplace_back(".jpg"); + m_supportedExtensions.emplace_back(".jpeg"); +} diff --git a/tools/depends/native/TexturePacker/src/decoder/JPGDecoder.h b/tools/depends/native/TexturePacker/src/decoder/JPGDecoder.h new file mode 100644 index 0000000..bbf23ba --- /dev/null +++ b/tools/depends/native/TexturePacker/src/decoder/JPGDecoder.h @@ -0,0 +1,36 @@ +/* + * Copyright (C) 2014 Team Kodi + * http://kodi.tv + * + * This Program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2, or (at your option) + * any later version. + * + * This Program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with XBMC; see the file COPYING. If not, see + * <http://www.gnu.org/licenses/>. + * + */ + +#pragma once + +#include "IDecoder.h" + +class JPGDecoder : public IDecoder +{ + public: + ~JPGDecoder() override = default; + bool CanDecode(const std::string &filename) override; + bool LoadFile(const std::string &filename, DecodedFrames &frames) override; + void FreeDecodedFrame(DecodedFrame &frame) override; + const char* GetImageFormatName() override { return "JPG"; } + const char* GetDecoderName() override { return "libjpeg"; } + protected: + void FillSupportedExtensions() override; +}; diff --git a/tools/depends/native/TexturePacker/src/decoder/PNGDecoder.cpp b/tools/depends/native/TexturePacker/src/decoder/PNGDecoder.cpp new file mode 100644 index 0000000..f327400 --- /dev/null +++ b/tools/depends/native/TexturePacker/src/decoder/PNGDecoder.cpp @@ -0,0 +1,244 @@ +/* + * Copyright (C) 2014 Team Kodi + * http://kodi.tv + * + * This Program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2, or (at your option) + * any later version. + * + * This Program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with XBMC; see the file COPYING. If not, see + * <http://www.gnu.org/licenses/>. + * + */ + +#include "PNGDecoder.h" + +#include "SimpleFS.h" + +#include <png.h> + +#ifndef png_jmpbuf +# define png_jmpbuf(png_ptr) ((png_ptr)->jmpbuf) +#endif + +/* Check to see if a file is a PNG file using png_sig_cmp(). png_sig_cmp() + * returns zero if the image is a PNG and nonzero if it isn't a PNG. + * + * The function check_if_png() shown here, but not used, returns nonzero (true) + * if the file can be opened and is a PNG, 0 (false) otherwise. + * + * If this call is successful, and you are going to keep the file open, + * you should call png_set_sig_bytes(png_ptr, PNG_BYTES_TO_CHECK); once + * you have created the png_ptr, so that libpng knows your application + * has read that many bytes from the start of the file. Make sure you + * don't call png_set_sig_bytes() with more than 8 bytes read or give it + * an incorrect number of bytes read, or you will either have read too + * many bytes (your fault), or you are telling libpng to read the wrong + * number of magic bytes (also your fault). + * + * Many applications already read the first 2 or 4 bytes from the start + * of the image to determine the file type, so it would be easiest just + * to pass the bytes to png_sig_cmp() or even skip that if you know + * you have a PNG file, and call png_set_sig_bytes(). + */ +bool PNGDecoder::CanDecode(const std::string &filename) +{ + #define PNG_BYTES_TO_CHECK 4 + CFile fp; + char buf[PNG_BYTES_TO_CHECK]; + + /* Open the prospective PNG file. */ + if (!fp.Open(filename)) + return false; + + /* Read in some of the signature bytes */ + if (fp.Read(buf, PNG_BYTES_TO_CHECK) != PNG_BYTES_TO_CHECK) + { + fprintf(stderr, "error reading header ...\n"); + return false; + } + fp.Close(); + + /* Compare the first PNG_BYTES_TO_CHECK bytes of the signature. + Return nonzero (true) if they match */ + return(!png_sig_cmp((png_bytep)buf, (png_size_t)0, PNG_BYTES_TO_CHECK)); +} + +bool PNGDecoder::LoadFile(const std::string &filename, DecodedFrames &frames) +{ + png_byte header[8]; + + CFile fp; + if (!fp.Open(filename)) + { + perror(filename.c_str()); + return false; + } + + // read the header + fp.Read(header, 8); + + if (png_sig_cmp(header, 0, 8)) + { + fprintf(stderr, "error: %s is not a PNG.\n", filename.c_str()); + return false; + } + + png_structp png_ptr = png_create_read_struct(PNG_LIBPNG_VER_STRING, NULL, NULL, NULL); + if (!png_ptr) + { + fprintf(stderr, "error: png_create_read_struct returned 0.\n"); + return false; + } + + // create png info struct + png_infop info_ptr = png_create_info_struct(png_ptr); + if (!info_ptr) + { + fprintf(stderr, "error: png_create_info_struct returned 0.\n"); + png_destroy_read_struct(&png_ptr, (png_infopp)NULL, (png_infopp)NULL); + return false; + } + + // create png info struct + png_infop end_info = png_create_info_struct(png_ptr); + if (!end_info) + { + fprintf(stderr, "error: png_create_info_struct returned 0.\n"); + png_destroy_read_struct(&png_ptr, &info_ptr, (png_infopp) NULL); + return false; + } + + // the code in this if statement gets called if libpng encounters an error + if (setjmp(png_jmpbuf(png_ptr))) { + fprintf(stderr, "error from libpng\n"); + png_destroy_read_struct(&png_ptr, &info_ptr, &end_info); + return false; + } + + // init png reading + png_init_io(png_ptr, fp.getFP()); + + // let libpng know you already read the first 8 bytes + png_set_sig_bytes(png_ptr, 8); + + // read all the info up to the image data + png_read_info(png_ptr, info_ptr); + + // variables to pass to get info + int bit_depth, color_type; + png_uint_32 temp_width, temp_height; + + // get info about png + png_get_IHDR(png_ptr, info_ptr, &temp_width, &temp_height, &bit_depth, &color_type, + NULL, NULL, NULL); + + if (png_get_valid(png_ptr, info_ptr, PNG_INFO_tRNS)) + { + png_set_tRNS_to_alpha(png_ptr); + } + + //set it to 32bit pixeldepth + png_color_8 sig_bit; + sig_bit.red = 32; + sig_bit.green = 32; + sig_bit.blue = 32; + // if the image has an alpha channel then + sig_bit.alpha = 32; + png_set_sBIT(png_ptr, info_ptr, &sig_bit); + + + /* Add filler (or alpha) byte (before/after each RGB triplet) */ + png_set_filler(png_ptr, 0xff, PNG_FILLER_AFTER); + + + if (color_type == PNG_COLOR_TYPE_RGB || + color_type == PNG_COLOR_TYPE_RGB_ALPHA) + png_set_bgr(png_ptr); + + // convert indexed color to rgb + if (color_type == PNG_COLOR_TYPE_PALETTE) + png_set_palette_to_rgb(png_ptr); + + /* swap the RGBA or GA data to ARGB or AG (or BGRA to ABGR) */ + //png_set_swap_alpha(png_ptr); + + //libsquish only eats 32bit RGBA, must convert grayscale into this format + if (color_type == PNG_COLOR_TYPE_GRAY || + color_type == PNG_COLOR_TYPE_GRAY_ALPHA) + { + png_set_expand_gray_1_2_4_to_8(png_ptr); + png_set_gray_to_rgb(png_ptr); + } + + // Update the png info struct. + png_read_update_info(png_ptr, info_ptr); + + // Row size in bytes. + int rowbytes = png_get_rowbytes(png_ptr, info_ptr); + + // glTexImage2d requires rows to be 4-byte aligned + // rowbytes += 3 - ((rowbytes-1) % 4); + + // Allocate the image_data as a big block, to be given to opengl + png_byte * image_data; + image_data = (png_byte*)new png_byte[rowbytes * temp_height * sizeof(png_byte)+15]; + if (image_data == NULL) + { + fprintf(stderr, "error: could not allocate memory for PNG image data\n"); + png_destroy_read_struct(&png_ptr, &info_ptr, &end_info); + return false; + } + + // row_pointers is for pointing to image_data for reading the png with libpng + png_bytep * row_pointers = (png_bytep*) new png_bytep[temp_height * sizeof(png_bytep)]; + if (row_pointers == NULL) + { + fprintf(stderr, "error: could not allocate memory for PNG row pointers\n"); + png_destroy_read_struct(&png_ptr, &info_ptr, &end_info); + delete [] image_data; + return false; + } + + // set the individual row_pointers to point at the correct offsets of image_data + for (unsigned int i = 0; i < temp_height; i++) + { + row_pointers[i] = image_data + i * rowbytes; + } + + // read the png into image_data through row_pointers + png_read_image(png_ptr, row_pointers); + + DecodedFrame frame; + + frame.rgbaImage.pixels = (char *)image_data; + frame.rgbaImage.height = temp_height; + frame.rgbaImage.width = temp_width; + frame.rgbaImage.bbp = 32; + frame.rgbaImage.pitch = 4 * temp_width; + + frame.decoder = this; + + frames.frameList.push_back(frame); + // clean up + png_destroy_read_struct(&png_ptr, &info_ptr, &end_info); + delete [] row_pointers; + return true; +} + +void PNGDecoder::FreeDecodedFrame(DecodedFrame &frame) +{ + delete [] frame.rgbaImage.pixels; +} + +void PNGDecoder::FillSupportedExtensions() +{ + m_supportedExtensions.emplace_back(".png"); +} diff --git a/tools/depends/native/TexturePacker/src/decoder/PNGDecoder.h b/tools/depends/native/TexturePacker/src/decoder/PNGDecoder.h new file mode 100644 index 0000000..c7dba76 --- /dev/null +++ b/tools/depends/native/TexturePacker/src/decoder/PNGDecoder.h @@ -0,0 +1,36 @@ +/* + * Copyright (C) 2014 Team Kodi + * http://kodi.tv + * + * This Program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2, or (at your option) + * any later version. + * + * This Program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with XBMC; see the file COPYING. If not, see + * <http://www.gnu.org/licenses/>. + * + */ + +#pragma once + +#include "IDecoder.h" + +class PNGDecoder : public IDecoder +{ + public: + ~PNGDecoder() override = default; + bool CanDecode(const std::string &filename) override; + bool LoadFile(const std::string &filename, DecodedFrames &frames) override; + void FreeDecodedFrame(DecodedFrame &frame) override; + const char* GetImageFormatName() override { return "PNG"; } + const char* GetDecoderName() override { return "libpng"; } + protected: + void FillSupportedExtensions() override; +}; diff --git a/tools/depends/native/TexturePacker/src/md5.cpp b/tools/depends/native/TexturePacker/src/md5.cpp new file mode 100644 index 0000000..b9788dd --- /dev/null +++ b/tools/depends/native/TexturePacker/src/md5.cpp @@ -0,0 +1,231 @@ +/* + * This code implements the MD5 message-digest algorithm. + * The algorithm is due to Ron Rivest. This code was + * written by Colin Plumb in 1993, no copyright is claimed. + * This code is in the public domain; do with it what you wish. + * + * Equivalent code is available from RSA Data Security, Inc. + * This code has been tested against that, and is equivalent, + * except that you don't need to include two pages of legalese + * with every copy. + * + * To compute the message digest of a chunk of bytes, declare an + * MD5Context structure, pass it to MD5Init, call MD5Update as + * needed on buffers full of bytes, and then call MD5Final, which + * will fill a supplied 16-byte array with the digest. + * + * Changed so as no longer to depend on Colin Plumb's `usual.h' header + * definitions; now uses stuff from dpkg's config.h. + * - Ian Jackson <ian@chiark.greenend.org.uk>. + * Still in the public domain. + */ + +#include "md5.h" + + +#ifdef WORDS_BIGENDIAN +void +byteSwap(uint32_t *buf, unsigned words) +{ + uint8_t *p = (uint8_t*)buf; + + do { + *buf++ = (uint32_t)((unsigned)p[3] << 8 | p[2]) << 16 | + ((unsigned)p[1] << 8 | p[0]); + p += 4; + } while (--words); +} +#else +#define byteSwap(buf,words) +#endif + +/* The four core functions - F1 is optimized somewhat */ + +/* #define F1(x, y, z) (x & y | ~x & z) */ +#define F1(x, y, z) (z ^ (x & (y ^ z))) +#define F2(x, y, z) F1(z, x, y) +#define F3(x, y, z) (x ^ y ^ z) +#define F4(x, y, z) (y ^ (x | ~z)) + +/* This is the central step in the MD5 algorithm. */ +#define MD5STEP(f,w,x,y,z,in,s) \ + (w += f(x,y,z) + in, w = (w<<s | w>>(32-s)) + x) + +/* + * The core of the MD5 algorithm, this alters an existing MD5 hash to + * reflect the addition of 16 longwords of new data. MD5Update blocks + * the data and converts bytes into longwords for this routine. + */ +static void +MD5Transform(uint32_t buf[4], uint32_t const in[16]) +{ + uint32_t a, b, c, d; + + a = buf[0]; + b = buf[1]; + c = buf[2]; + d = buf[3]; + + MD5STEP(F1, a, b, c, d, in[0] + 0xd76aa478, 7); + MD5STEP(F1, d, a, b, c, in[1] + 0xe8c7b756, 12); + MD5STEP(F1, c, d, a, b, in[2] + 0x242070db, 17); + MD5STEP(F1, b, c, d, a, in[3] + 0xc1bdceee, 22); + MD5STEP(F1, a, b, c, d, in[4] + 0xf57c0faf, 7); + MD5STEP(F1, d, a, b, c, in[5] + 0x4787c62a, 12); + MD5STEP(F1, c, d, a, b, in[6] + 0xa8304613, 17); + MD5STEP(F1, b, c, d, a, in[7] + 0xfd469501, 22); + MD5STEP(F1, a, b, c, d, in[8] + 0x698098d8, 7); + MD5STEP(F1, d, a, b, c, in[9] + 0x8b44f7af, 12); + MD5STEP(F1, c, d, a, b, in[10] + 0xffff5bb1, 17); + MD5STEP(F1, b, c, d, a, in[11] + 0x895cd7be, 22); + MD5STEP(F1, a, b, c, d, in[12] + 0x6b901122, 7); + MD5STEP(F1, d, a, b, c, in[13] + 0xfd987193, 12); + MD5STEP(F1, c, d, a, b, in[14] + 0xa679438e, 17); + MD5STEP(F1, b, c, d, a, in[15] + 0x49b40821, 22); + + MD5STEP(F2, a, b, c, d, in[1] + 0xf61e2562, 5); + MD5STEP(F2, d, a, b, c, in[6] + 0xc040b340, 9); + MD5STEP(F2, c, d, a, b, in[11] + 0x265e5a51, 14); + MD5STEP(F2, b, c, d, a, in[0] + 0xe9b6c7aa, 20); + MD5STEP(F2, a, b, c, d, in[5] + 0xd62f105d, 5); + MD5STEP(F2, d, a, b, c, in[10] + 0x02441453, 9); + MD5STEP(F2, c, d, a, b, in[15] + 0xd8a1e681, 14); + MD5STEP(F2, b, c, d, a, in[4] + 0xe7d3fbc8, 20); + MD5STEP(F2, a, b, c, d, in[9] + 0x21e1cde6, 5); + MD5STEP(F2, d, a, b, c, in[14] + 0xc33707d6, 9); + MD5STEP(F2, c, d, a, b, in[3] + 0xf4d50d87, 14); + MD5STEP(F2, b, c, d, a, in[8] + 0x455a14ed, 20); + MD5STEP(F2, a, b, c, d, in[13] + 0xa9e3e905, 5); + MD5STEP(F2, d, a, b, c, in[2] + 0xfcefa3f8, 9); + MD5STEP(F2, c, d, a, b, in[7] + 0x676f02d9, 14); + MD5STEP(F2, b, c, d, a, in[12] + 0x8d2a4c8a, 20); + + MD5STEP(F3, a, b, c, d, in[5] + 0xfffa3942, 4); + MD5STEP(F3, d, a, b, c, in[8] + 0x8771f681, 11); + MD5STEP(F3, c, d, a, b, in[11] + 0x6d9d6122, 16); + MD5STEP(F3, b, c, d, a, in[14] + 0xfde5380c, 23); + MD5STEP(F3, a, b, c, d, in[1] + 0xa4beea44, 4); + MD5STEP(F3, d, a, b, c, in[4] + 0x4bdecfa9, 11); + MD5STEP(F3, c, d, a, b, in[7] + 0xf6bb4b60, 16); + MD5STEP(F3, b, c, d, a, in[10] + 0xbebfbc70, 23); + MD5STEP(F3, a, b, c, d, in[13] + 0x289b7ec6, 4); + MD5STEP(F3, d, a, b, c, in[0] + 0xeaa127fa, 11); + MD5STEP(F3, c, d, a, b, in[3] + 0xd4ef3085, 16); + MD5STEP(F3, b, c, d, a, in[6] + 0x04881d05, 23); + MD5STEP(F3, a, b, c, d, in[9] + 0xd9d4d039, 4); + MD5STEP(F3, d, a, b, c, in[12] + 0xe6db99e5, 11); + MD5STEP(F3, c, d, a, b, in[15] + 0x1fa27cf8, 16); + MD5STEP(F3, b, c, d, a, in[2] + 0xc4ac5665, 23); + + MD5STEP(F4, a, b, c, d, in[0] + 0xf4292244, 6); + MD5STEP(F4, d, a, b, c, in[7] + 0x432aff97, 10); + MD5STEP(F4, c, d, a, b, in[14] + 0xab9423a7, 15); + MD5STEP(F4, b, c, d, a, in[5] + 0xfc93a039, 21); + MD5STEP(F4, a, b, c, d, in[12] + 0x655b59c3, 6); + MD5STEP(F4, d, a, b, c, in[3] + 0x8f0ccc92, 10); + MD5STEP(F4, c, d, a, b, in[10] + 0xffeff47d, 15); + MD5STEP(F4, b, c, d, a, in[1] + 0x85845dd1, 21); + MD5STEP(F4, a, b, c, d, in[8] + 0x6fa87e4f, 6); + MD5STEP(F4, d, a, b, c, in[15] + 0xfe2ce6e0, 10); + MD5STEP(F4, c, d, a, b, in[6] + 0xa3014314, 15); + MD5STEP(F4, b, c, d, a, in[13] + 0x4e0811a1, 21); + MD5STEP(F4, a, b, c, d, in[4] + 0xf7537e82, 6); + MD5STEP(F4, d, a, b, c, in[11] + 0xbd3af235, 10); + MD5STEP(F4, c, d, a, b, in[2] + 0x2ad7d2bb, 15); + MD5STEP(F4, b, c, d, a, in[9] + 0xeb86d391, 21); + + buf[0] += a; + buf[1] += b; + buf[2] += c; + buf[3] += d; +} + +/* + * Start MD5 accumulation. Set bit count to 0 and buffer to mysterious + * initialization constants. + */ +void MD5Init(struct MD5Context *ctx) +{ + ctx->buf[0] = 0x67452301; + ctx->buf[1] = 0xefcdab89; + ctx->buf[2] = 0x98badcfe; + ctx->buf[3] = 0x10325476; + + ctx->bytes[0] = 0; + ctx->bytes[1] = 0; +} + +/* + * Update context to reflect the concatenation of another buffer full + * of bytes. + */ +void MD5Update(struct MD5Context *ctx, const uint8_t *buf, unsigned len) +{ + uint32_t t; + + /* Update byte count */ + + t = ctx->bytes[0]; + if ((ctx->bytes[0] = t + len) < t) + ctx->bytes[1]++; /* Carry from low to high */ + + t = 64 - (t & 0x3f); /* Space available in ctx->in (at least 1) */ + if (t > len) { + memcpy((uint8_t*)ctx->in + 64 - t, buf, len); + return; + } + /* First chunk is an odd size */ + memcpy((uint8_t*)ctx->in + 64 - t, buf, t); + byteSwap(ctx->in, 16); + MD5Transform(ctx->buf, ctx->in); + buf += t; + len -= t; + + /* Process data in 64-byte chunks */ + while (len >= 64) { + memcpy(ctx->in, buf, 64); + byteSwap(ctx->in, 16); + MD5Transform(ctx->buf, ctx->in); + buf += 64; + len -= 64; + } + + /* Handle any remaining bytes of data. */ + memcpy(ctx->in, buf, len); +} + +/* + * Final wrapup - pad to 64-byte boundary with the bit pattern + * 1 0* (64-bit count of bits processed, MSB-first) + */ +void MD5Final(uint8_t digest[16], struct MD5Context *ctx) +{ + int count = ctx->bytes[0] & 0x3f; /* Number of bytes in ctx->in */ + uint8_t *p = (uint8_t*)ctx->in + count; + + /* Set the first char of padding to 0x80. There is always room. */ + *p++ = 0x80; + + /* Bytes of padding needed to make 56 bytes (-8..55) */ + count = 56 - 1 - count; + + if (count < 0) { /* Padding forces an extra block */ + memset(p, 0, count + 8); + byteSwap(ctx->in, 16); + MD5Transform(ctx->buf, ctx->in); + p = (uint8_t*)ctx->in; + count = 56; + } + memset(p, 0, count); + byteSwap(ctx->in, 14); + + /* Append length in bits and transform */ + ctx->in[14] = ctx->bytes[0] << 3; + ctx->in[15] = ctx->bytes[1] << 3 | ctx->bytes[0] >> 29; + MD5Transform(ctx->buf, ctx->in); + + byteSwap(ctx->buf, 4); + memcpy(digest, ctx->buf, 16); + memset(ctx, 0, sizeof(*ctx)); /* In case it's sensitive */ +} + diff --git a/tools/depends/native/TexturePacker/src/md5.h b/tools/depends/native/TexturePacker/src/md5.h new file mode 100644 index 0000000..76475bc --- /dev/null +++ b/tools/depends/native/TexturePacker/src/md5.h @@ -0,0 +1,38 @@ +/* + * This code implements the MD5 message-digest algorithm. + * The algorithm is due to Ron Rivest. This code was + * written by Colin Plumb in 1993, no copyright is claimed. + * This code is in the public domain; do with it what you wish. + * + * Equivalent code is available from RSA Data Security, Inc. + * This code has been tested against that, and is equivalent, + * except that you don't need to include two pages of legalese + * with every copy. + * + * To compute the message digest of a chunk of bytes, declare an + * MD5Context structure, pass it to MD5Init, call MD5Update as + * needed on buffers full of bytes, and then call MD5Final, which + * will fill a supplied 16-byte array with the digest. + * + * Changed so as no longer to depend on Colin Plumb's `usual.h' header + * definitions; now uses stuff from dpkg's config.h. + * - Ian Jackson <ian@chiark.greenend.org.uk>. + * Still in the public domain. + */ + +#pragma once + +#include <cstdint> +#include <cstring> /* for memcpy() */ + +struct MD5Context +{ + uint32_t buf[4]; + uint32_t bytes[2]; + uint32_t in[16]; +}; + +void MD5Init(struct MD5Context *ctx); +void MD5Update(struct MD5Context *ctx, const uint8_t *buf, unsigned len); +void MD5Final(unsigned char digest[16], struct MD5Context *ctx); + |