From 1e360bdb6bfdd55cadace38557f679719869563d Mon Sep 17 00:00:00 2001 From: "erwin.coumans" Date: Tue, 13 Sep 2011 01:52:42 +0000 Subject: [PATCH] add Intel build support for the OpenCL cloth demo, and use the bullet_logo.png Thanks to ggjunker for the patch, see Issue 533 --- CMakeLists.txt | 42 +- Demos/DX11ClothDemo/cloth.h | 1 + Demos/OpenCLClothDemo/AMD/CMakeLists.txt | 7 +- Demos/OpenCLClothDemo/Apple/CMakeLists.txt | 2 - Demos/OpenCLClothDemo/CMakeLists.txt | 4 + Demos/OpenCLClothDemo/Intel/CMakeLists.txt | 86 + Demos/OpenCLClothDemo/MiniCL/CMakeLists.txt | 5 +- Demos/OpenCLClothDemo/NVidia/CMakeLists.txt | 2 - Demos/OpenCLClothDemo/amdFlag.bmp | Bin 1396038 -> 0 bytes Demos/OpenCLClothDemo/atiFlag.bmp | Bin 1396038 -> 0 bytes Demos/OpenCLClothDemo/bmpLoader.cpp | 325 -- Demos/OpenCLClothDemo/bmpLoader.h | 200 - Demos/OpenCLClothDemo/bmpLoader.hpp | 189 - Demos/OpenCLClothDemo/cl_cloth_demo.cpp | 8 +- Demos/OpenCLClothDemo/cloth.h | 117 +- Demos/OpenCLClothDemo/clstuff.cpp | 2 + Demos/OpenCLClothDemo/texture1.bmp | Bin 786486 -> 0 bytes Demos/OpenGL/CMakeLists.txt | 2 + Demos/OpenGL/stb_image.cpp | 4342 +++++++++++++++++ Demos/OpenGL/stb_image.h | 332 ++ Demos/ParticlesOpenCL/CMakeLists.txt | 4 + .../btParticlesDemoDynamicsWorld.cpp | 6 +- Demos/SharedOpenCL/btOclCommon.cpp | 2 + Demos/SharedOpenCL/btOclUtils.cpp | 5 +- LICENSE | 6 +- bullet_logo.png | Bin 0 -> 3380 bytes .../BroadphaseCollision/btQuantizedBvh.h | 4 +- .../GpuSoftBodySolvers/OpenCL/CMakeLists.txt | 4 + 28 files changed, 4885 insertions(+), 812 deletions(-) create mode 100644 Demos/OpenCLClothDemo/Intel/CMakeLists.txt delete mode 100644 Demos/OpenCLClothDemo/amdFlag.bmp delete mode 100644 Demos/OpenCLClothDemo/atiFlag.bmp delete mode 100644 Demos/OpenCLClothDemo/bmpLoader.cpp delete mode 100644 Demos/OpenCLClothDemo/bmpLoader.h delete mode 100644 Demos/OpenCLClothDemo/bmpLoader.hpp delete mode 100644 Demos/OpenCLClothDemo/texture1.bmp create mode 100644 Demos/OpenGL/stb_image.cpp create mode 100644 Demos/OpenGL/stb_image.h create mode 100644 bullet_logo.png diff --git a/CMakeLists.txt b/CMakeLists.txt index 75374525e..af49e6321 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -125,20 +125,38 @@ IF(MSVC) IF(AMD_OPENCL_BASE_DIR) #AMD adds an extras slash at the end of the ATISTREAMSDKROOT variable SET(AMD_OPENCL_INCLUDES ${AMD_OPENCL_BASE_DIR}/include ) + MESSAGE("AMD OPENCL SDK FOUND") MESSAGE(${AMD_OPENCL_INCLUDES}) IF (CMAKE_CL_64) SET(CMAKE_ATISTREAMSDK_LIBPATH ${AMD_OPENCL_BASE_DIR}/lib/x86_64 ) ELSE(CMAKE_CL_64) - SET(CMAKE_ATISTREAMSDK_LIBPATH ${AMD_OPENCL_BASE_DIR}/lib/x86 ) + SET(CMAKE_ATISTREAMSDK_LIBPATH ${AMD_OPENCL_BASE_DIR}/lib/x86 ) ENDIF(CMAKE_CL_64) OPTION(BUILD_AMD_OPENCL_DEMOS "Build OpenCL demos for AMD (GPU or CPU)" ON) ELSE() OPTION(BUILD_AMD_OPENCL_DEMOS "Build OpenCL demos for AMD (GPU or CPU)" OFF) ENDIF() + FIND_PATH(INTEL_OPENCL_BASE_DIR include/CL/cl.h PATH $ENV{INTELOCLSDKROOT} ) + IF(INTEL_OPENCL_BASE_DIR) + SET(INTEL_OPENCL_INCLUDES ${INTEL_OPENCL_BASE_DIR}/include ) + MESSAGE("INTEL OPENCL SDK FOUND") + MESSAGE(${INTEL_OPENCL_INCLUDES}) + IF (CMAKE_CL_64) + SET(CMAKE_INTELOCLSDK_LIBPATH ${INTEL_OPENCL_BASE_DIR}/lib/x64 ) + ELSE(CMAKE_CL_64) + SET(CMAKE_INTELOCLSDK_LIBPATH ${INTEL_OPENCL_BASE_DIR}/lib/x86 ) + ENDIF(CMAKE_CL_64) + SET(INTEL_OPENCL_LIBRARIES ${CMAKE_INTELOCLSDK_LIBPATH}/OpenCL.lib) + OPTION(BUILD_INTEL_OPENCL_DEMOS "Build OpenCL demos for Intel (CPU)" ON) + ELSE() + OPTION(BUILD_INTEL_OPENCL_DEMOS "Build OpenCL demos for Intel (CPU)" OFF) + ENDIF() + FIND_PATH(NVIDIA_OPENCL_BASE_DIR include/CL/cl.h PATH $ENV{CUDA_PATH} ) IF(NVIDIA_OPENCL_BASE_DIR) SET(NVIDIA_OPENCL_INCLUDES ${NVIDIA_OPENCL_BASE_DIR}/include ) + MESSAGE("NVIDIA OPENCL SDK FOUND") MESSAGE(${NVIDIA_OPENCL_INCLUDES}) IF (CMAKE_CL_64) SET(CMAKE_NVSDKCOMPUTE_LIBPATH ${NVIDIA_OPENCL_BASE_DIR}/lib/x64 ) @@ -167,16 +185,30 @@ IF (MSVC OR APPLE) ELSE() OPTION(BUILD_MINICL_OPENCL_DEMOS "Build OpenCL demos for MiniCL (Generic CPU)" OFF) + FIND_PATH(INTEL_OPENCL_INCLUDES CL/cl.h) + FIND_PATH(INTEL_OPENCL_ICD_CFG intelocl64.icd /etc/OpenCL/vendors) + FIND_LIBRARY(INTEL_OPENCL_LIBRARIES OpenCL PATH /usr/lib64) + IF (INTEL_OPENCL_INCLUDES AND INTEL_OPENCL_LIBRARIES AND INTEL_OPENCL_ICD_CFG) + MESSAGE("INTEL OPENCL SDK FOUND") + MESSAGE(${INTEL_OPENCL_LIBRARIES}) + OPTION(BUILD_INTEL_OPENCL_DEMOS "Build OpenCL demos for Intel (CPU)" ON) + ELSE () + MESSAGE("INTEL OPENCL NOT FOUND") + OPTION(BUILD_INTEL_OPENCL_DEMOS "Build OpenCL demos for Intel (CPU)" OFF) + ENDIF () + FIND_PATH(NVIDIA_OPENCL_INCLUDES CL/cl.h) - FIND_LIBRARY(NVIDIA_OPENCL_LIBRARIES OpenCL PATH /usr/lib /usr/local/lib) - IF (NVIDIA_OPENCL_INCLUDES AND NVIDIA_OPENCL_LIBRARIES) - MESSAGE("OPENCL FOUND") + FIND_PATH(NVIDIA_OPENCL_ICD_CFG nvidia.icd /etc/OpenCL/vendors) + FIND_LIBRARY(NVIDIA_OPENCL_LIBRARIES OpenCL PATH /usr/lib64 /usr/local/lib) + IF (NVIDIA_OPENCL_INCLUDES AND NVIDIA_OPENCL_LIBRARIES AND NVIDIA_OPENCL_ICD_CFG) + MESSAGE("NVidia OPENCL FOUND") MESSAGE(${NVIDIA_OPENCL_LIBRARIES}) OPTION(BUILD_NVIDIA_OPENCL_DEMOS "Build OpenCL demos for NVidia (GPU)" ON) ELSE () - MESSAGE("OPENCL NOT FOUND") + MESSAGE("NVidia OPENCL NOT FOUND") OPTION(BUILD_NVIDIA_OPENCL_DEMOS "Build OpenCL demos for NVidia (GPU)" OFF) ENDIF () + ENDIF() OPTION(BUILD_CPU_DEMOS "Build original Bullet CPU demos" ON) diff --git a/Demos/DX11ClothDemo/cloth.h b/Demos/DX11ClothDemo/cloth.h index 28a329b54..47781d7f0 100644 --- a/Demos/DX11ClothDemo/cloth.h +++ b/Demos/DX11ClothDemo/cloth.h @@ -80,6 +80,7 @@ public: } + void draw(void) { diff --git a/Demos/OpenCLClothDemo/AMD/CMakeLists.txt b/Demos/OpenCLClothDemo/AMD/CMakeLists.txt index ad6069953..391166b4f 100644 --- a/Demos/OpenCLClothDemo/AMD/CMakeLists.txt +++ b/Demos/OpenCLClothDemo/AMD/CMakeLists.txt @@ -45,8 +45,8 @@ IF (USE_GLUT) # ${BULLET_PHYSICS_SOURCE_DIR}/Demos/OpenGL/GLDebugDrawer.cpp ../gl_win.cpp ../clstuff.cpp - ../bmpLoader.cpp - ../bmpLoader.h + + ../clstuff.h ../gl_win.h ../cloth.h @@ -73,8 +73,7 @@ IF (NOT INTERNAL_CREATE_DISTRIBUTABLE_MSVC_PROJECTFILES) ENDIF(CMAKE_CL_64) ENDIF(WIN32) ADD_CUSTOM_COMMAND( TARGET AppOpenCLClothDemo_AMD POST_BUILD - COMMAND ${CMAKE_COMMAND} ARGS -E copy_if_different ${BULLET_PHYSICS_SOURCE_DIR}/Demos/OpenCLClothDemo/amdFlag.bmp ${CMAKE_CURRENT_BINARY_DIR} - COMMAND ${CMAKE_COMMAND} ARGS -E copy_if_different ${BULLET_PHYSICS_SOURCE_DIR}/Demos/OpenCLClothDemo/atiFlag.bmp ${CMAKE_CURRENT_BINARY_DIR} + COMMAND ${CMAKE_COMMAND} ARGS -E copy_if_different ${BULLET_PHYSICS_SOURCE_DIR}/bullet_logo.png ${CMAKE_CURRENT_BINARY_DIR} ) ENDIF(NOT INTERNAL_CREATE_DISTRIBUTABLE_MSVC_PROJECTFILES) diff --git a/Demos/OpenCLClothDemo/Apple/CMakeLists.txt b/Demos/OpenCLClothDemo/Apple/CMakeLists.txt index e89513c18..f9a24cf1f 100644 --- a/Demos/OpenCLClothDemo/Apple/CMakeLists.txt +++ b/Demos/OpenCLClothDemo/Apple/CMakeLists.txt @@ -39,8 +39,6 @@ IF (USE_GLUT) ${BULLET_PHYSICS_SOURCE_DIR}/Demos/SharedOpenCL/btOclCommon.cpp ../gl_win.cpp ../clstuff.cpp - ../bmpLoader.cpp - ../bmpLoader.h ../clstuff.h ../gl_win.h diff --git a/Demos/OpenCLClothDemo/CMakeLists.txt b/Demos/OpenCLClothDemo/CMakeLists.txt index 2678c2a4d..03cf16adc 100644 --- a/Demos/OpenCLClothDemo/CMakeLists.txt +++ b/Demos/OpenCLClothDemo/CMakeLists.txt @@ -1,5 +1,9 @@ SUBDIRS( MiniCL ) +IF(BUILD_INTEL_OPENCL_DEMOS) + SUBDIRS(Intel) +ENDIF() + IF(BUILD_AMD_OPENCL_DEMOS) SUBDIRS(AMD) ENDIF() diff --git a/Demos/OpenCLClothDemo/Intel/CMakeLists.txt b/Demos/OpenCLClothDemo/Intel/CMakeLists.txt new file mode 100644 index 000000000..0018c09a5 --- /dev/null +++ b/Demos/OpenCLClothDemo/Intel/CMakeLists.txt @@ -0,0 +1,86 @@ + + +INCLUDE_DIRECTORIES( +${BULLET_PHYSICS_SOURCE_DIR}/src +${BULLET_PHYSICS_SOURCE_DIR}/Demos/SharedOpenCL +${BULLET_PHYSICS_SOURCE_DIR}/Demos/OpenGL +${INTEL_OPENCL_INCLUDES} +) + +ADD_DEFINITIONS(-DUSE_INTEL_OPENCL) +ADD_DEFINITIONS(-DCL_PLATFORM_INTEL) + + +IF (CMAKE_CL_64) + SET(CMAK_GLEW_LIBRARY + ${BULLET_PHYSICS_SOURCE_DIR}/Glut/glew64.lib ) +ELSE(CMAKE_CL_64) + SET(CMAK_GLEW_LIBRARY ${BULLET_PHYSICS_SOURCE_DIR}/Glut/glew32.lib ) +ENDIF(CMAKE_CL_64) + + +IF (USE_GLUT) + LINK_LIBRARIES( + OpenGLSupport + BulletSoftBodySolvers_OpenCL_Intel + BulletMultiThreaded + BulletSoftBody + BulletDynamics + BulletCollision + LinearMath + ${GLUT_glut_LIBRARY} + ${OPENGL_gl_LIBRARY} + ${OPENGL_glu_LIBRARY} + ${CMAK_GLEW_LIBRARY} + ${INTEL_OPENCL_LIBRARIES} + ) + + + ADD_EXECUTABLE(AppOpenCLClothDemo_Intel + ../cl_cloth_demo.cpp + ${BULLET_PHYSICS_SOURCE_DIR}/Demos/SharedOpenCL/btOclUtils.h + ${BULLET_PHYSICS_SOURCE_DIR}/Demos/SharedOpenCL/btOclCommon.h + ${BULLET_PHYSICS_SOURCE_DIR}/Demos/SharedOpenCL/btOclUtils.cpp + ${BULLET_PHYSICS_SOURCE_DIR}/Demos/SharedOpenCL/btOclCommon.cpp +# ${BULLET_PHYSICS_SOURCE_DIR}/Demos/OpenGL/GLDebugDrawer.cpp + ../gl_win.cpp + ../clstuff.cpp + ../clstuff.h + ../gl_win.h + ../cloth.h + + ) +ELSE (USE_GLUT) +ENDIF (USE_GLUT) + +IF (NOT INTERNAL_CREATE_DISTRIBUTABLE_MSVC_PROJECTFILES) + IF(WIN32) + IF (CMAKE_CL_64) + ADD_CUSTOM_COMMAND( TARGET AppOpenCLClothDemo_Intel POST_BUILD + COMMAND ${CMAKE_COMMAND} ARGS -E copy_if_different ${BULLET_PHYSICS_SOURCE_DIR}/glut64.dll ${CMAKE_CURRENT_BINARY_DIR} + ) + ADD_CUSTOM_COMMAND( TARGET AppOpenCLClothDemo_Intel POST_BUILD + COMMAND ${CMAKE_COMMAND} ARGS -E copy_if_different ${BULLET_PHYSICS_SOURCE_DIR}/GLEW64.DLL ${CMAKE_CURRENT_BINARY_DIR}) + ELSE(CMAKE_CL_64) + + ADD_CUSTOM_COMMAND( TARGET AppOpenCLClothDemo_Intel POST_BUILD + COMMAND ${CMAKE_COMMAND} ARGS -E copy_if_different ${BULLET_PHYSICS_SOURCE_DIR}/GLUT32.DLL ${CMAKE_CURRENT_BINARY_DIR} + ) + ADD_CUSTOM_COMMAND( TARGET AppOpenCLClothDemo_Intel POST_BUILD + COMMAND ${CMAKE_COMMAND} ARGS -E copy_if_different ${BULLET_PHYSICS_SOURCE_DIR}/GLEW32.DLL ${CMAKE_CURRENT_BINARY_DIR}) + ENDIF(CMAKE_CL_64) + ENDIF(WIN32) + ADD_CUSTOM_COMMAND( TARGET AppOpenCLClothDemo_Intel POST_BUILD + COMMAND ${CMAKE_COMMAND} ARGS -E copy_if_different ${BULLET_PHYSICS_SOURCE_DIR}/bullet_logo.png ${CMAKE_CURRENT_BINARY_DIR} + ) +ENDIF(NOT INTERNAL_CREATE_DISTRIBUTABLE_MSVC_PROJECTFILES) + +IF (UNIX) + TARGET_LINK_LIBRARIES(AppOpenCLClothDemo_Intel pthread) +ENDIF(UNIX) + +IF (INTERNAL_ADD_POSTFIX_EXECUTABLE_NAMES) + SET_TARGET_PROPERTIES(AppOpenCLClothDemo_Intel PROPERTIES DEBUG_POSTFIX "_Debug") + SET_TARGET_PROPERTIES(AppOpenCLClothDemo_Intel PROPERTIES MINSIZEREL_POSTFIX "_MinsizeRel") + SET_TARGET_PROPERTIES(AppOpenCLClothDemo_Intel PROPERTIES RELWITHDEBINFO_POSTFIX "_RelWithDebugInfo") +ENDIF(INTERNAL_ADD_POSTFIX_EXECUTABLE_NAMES) diff --git a/Demos/OpenCLClothDemo/MiniCL/CMakeLists.txt b/Demos/OpenCLClothDemo/MiniCL/CMakeLists.txt index fb1586b60..9fb579210 100644 --- a/Demos/OpenCLClothDemo/MiniCL/CMakeLists.txt +++ b/Demos/OpenCLClothDemo/MiniCL/CMakeLists.txt @@ -40,8 +40,6 @@ IF (USE_GLUT) ../cl_cloth_demo.cpp ../gl_win.cpp ../clstuff.cpp - ../bmpLoader.cpp - ../bmpLoader.h ../clstuff.h ../gl_win.h ${BULLET_PHYSICS_SOURCE_DIR}/src/BulletMultiThreaded/GpuSoftBodySolvers/OpenCL/MiniCL/MiniCLTaskWrap.cpp @@ -77,8 +75,7 @@ ENDIF(WIN32) IF(NOT INTERNAL_CREATE_DISTRIBUTABLE_MSVC_PROJECTFILES) ADD_CUSTOM_COMMAND( TARGET AppOpenCLClothDemo_Mini POST_BUILD - COMMAND ${CMAKE_COMMAND} ARGS -E copy_if_different ${BULLET_PHYSICS_SOURCE_DIR}/Demos/OpenCLClothDemo/amdFlag.bmp ${CMAKE_CURRENT_BINARY_DIR} - COMMAND ${CMAKE_COMMAND} ARGS -E copy_if_different ${BULLET_PHYSICS_SOURCE_DIR}/Demos/OpenCLClothDemo/atiFlag.bmp ${CMAKE_CURRENT_BINARY_DIR} + COMMAND ${CMAKE_COMMAND} ARGS -E copy_if_different ${BULLET_PHYSICS_SOURCE_DIR}/bullet_logo.png ${CMAKE_CURRENT_BINARY_DIR} ) ENDIF() IF (UNIX) diff --git a/Demos/OpenCLClothDemo/NVidia/CMakeLists.txt b/Demos/OpenCLClothDemo/NVidia/CMakeLists.txt index 2f0bc5f27..3c2f9ac15 100644 --- a/Demos/OpenCLClothDemo/NVidia/CMakeLists.txt +++ b/Demos/OpenCLClothDemo/NVidia/CMakeLists.txt @@ -46,8 +46,6 @@ IF (USE_GLUT) ${BULLET_PHYSICS_SOURCE_DIR}/Demos/SharedOpenCL/btOclCommon.cpp ../gl_win.cpp ../clstuff.cpp - ../bmpLoader.cpp - ../bmpLoader.h ../clstuff.h ../gl_win.h diff --git a/Demos/OpenCLClothDemo/amdFlag.bmp b/Demos/OpenCLClothDemo/amdFlag.bmp deleted file mode 100644 index dd1d394ec7ef603cd68b9956780c5430106dc9f8..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 1396038 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 CQsM#t diff --git a/Demos/OpenCLClothDemo/atiFlag.bmp b/Demos/OpenCLClothDemo/atiFlag.bmp deleted file mode 100644 index 2be4847dd830b84f51b3a3fdd07f6e0d98a5315c..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 1396038 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 -#include -#include - -namespace amd -{ - -static const short bitMapID = 19778; - -void -BitMap::releaseResources(void) -{ - if (pixels_ != NULL) { - delete[] pixels_; - } - - if (colors_ != NULL) { - delete[] colors_; - } - - pixels_ = NULL; - colors_ = NULL; - isLoaded_ = false; -} - -BitMap& BitMap::operator=(const BitMap& rhs) -{ - if (this == &rhs) { - return *this; - } - - // Copy header - id = rhs.id; - size = rhs.size; - reserved1 = rhs.reserved1; - reserved2 = rhs.reserved2; - offset = rhs.offset; - - // Copy header info - sizeInfo = rhs.sizeInfo; - width = rhs.width; - height = rhs.height; - planes = rhs.planes; - bitsPerPixel = rhs.bitsPerPixel; - compression = rhs.compression; - imageSize = rhs.imageSize; - xPelsPerMeter = rhs.xPelsPerMeter; - yPelsPerMeter = rhs.yPelsPerMeter; - clrUsed = rhs.clrUsed; - clrImportant = rhs.clrImportant; - - numColors_ = rhs.numColors_; - isLoaded_ = rhs.isLoaded_; - - pixels_ = NULL; - colors_ = NULL; - if (isLoaded_) { - if (rhs.colors_ != NULL) { - colors_ = new ColorPalette[numColors_]; - if (colors_ == NULL) { - isLoaded_ = false; - return *this; - } - memcpy(colors_, rhs.colors_, numColors_ * sizeof(ColorPalette)); - } - - pixels_ = new uchar4[width * height]; - if (pixels_ == NULL) { - delete[] colors_; - colors_ = NULL; - isLoaded_ = false; - return *this; - } - memcpy(pixels_, rhs.pixels_, width * height * sizeof(uchar4)); - } - - return *this; -} - -void -BitMap::load(const char * filename) -{ - // Release any existing resources - releaseResources(); - - // Open BMP file - FILE * fd = fopen(filename, "rb"); - - // Opened OK - if (fd != NULL) { - // Read header - fread((BitMapHeader *)this, sizeof(BitMapHeader), 1, fd); - - // Failed to read header - if (ferror(fd)) { - fclose(fd); - return; - } - - // Confirm that we have a bitmap file - if (id != bitMapID) { - fclose(fd); - return; - } - - // Read map info header - fread((BitMapInfoHeader *)this, sizeof(BitMapInfoHeader), 1, fd); - - // Failed to read map info header - if (ferror(fd)) { - fclose(fd); - return; - } - - // No support for compressed images - if (compression) { - fclose(fd); - return; - } - - // Support only 8 or 24 bits images - if (bitsPerPixel < 8) { - fclose(fd); - return; - } - - // Store number of colors - numColors_ = 1 << bitsPerPixel; - - //load the palate for 8 bits per pixel - if(bitsPerPixel == 8) { - colors_ = new ColorPalette[numColors_]; - if (colors_ == NULL) { - fclose(fd); - return; - } - fread( - (char *)colors_, - numColors_ * sizeof(ColorPalette), - 1, - fd); - - // Failed to read colors - if (ferror(fd)) { - fclose(fd); - return; - } - } - - // Allocate buffer to hold all pixels - unsigned int sizeBuffer = size - offset; - unsigned char * tmpPixels = new unsigned char[sizeBuffer]; - - if (tmpPixels == NULL) { - delete colors_; - colors_ = NULL; - fclose(fd); - return; - } - - // Read pixels from file, including any padding - fread(tmpPixels, sizeBuffer * sizeof(unsigned char), 1, fd); - - // Failed to read pixel data - if (ferror(fd)) { - delete colors_; - colors_ = NULL; - delete tmpPixels; - fclose(fd); - return; - } - - // Allocate image - pixels_ = new uchar4[width * height]; - if (pixels_ == NULL) { - delete colors_; - colors_ = NULL; - delete tmpPixels; - fclose(fd); - return; - } - // Set image, including w component (white) - memset(pixels_, 0xff, width * height * sizeof(uchar4)); - - unsigned int index = 0; - for(int y = 0; y < height; y++) { - for(int x = 0; x < width; x++) { - // Read RGB values - if (bitsPerPixel == 8) { - pixels_[(y * width + x)] = colors_[tmpPixels[index++]]; - } - else { // 24 bit - pixels_[(y * width + x)].z = tmpPixels[index++]; - pixels_[(y * width + x)].y = tmpPixels[index++]; - pixels_[(y * width + x)].x = tmpPixels[index++]; - } - } - - // Handle padding - for(int x = 0; x < (4 - (3 * width) % 4) % 4; x++) { - index++; - } - } - - // Loaded file so we can close the file. - fclose(fd); - delete[] tmpPixels; - - // Loaded file so record this fact - isLoaded_ = true; - } -} - -int -BitMap::colorIndex(uchar4 color) -{ - for (int i = 0; i < numColors_; i++) { - if (colors_[i].x == color.x && - colors_[i].y == color.y && - colors_[i].z == color.z && - colors_[i].w == color.w) { - return i; - } - } - - return 0; -} - -bool -BitMap::write(const char * filename) -{ - if (!isLoaded_) { - return false; - } - - // Open BMP file - FILE * fd = fopen(filename, "wb"); - - // Opened OK - if (fd != NULL) { - // Write header - fwrite((BitMapHeader *)this, sizeof(BitMapHeader), 1, fd); - - // Failed to write header - if (ferror(fd)) { - fclose(fd); - return false; - } - - // Write map info header - fwrite((BitMapInfoHeader *)this, sizeof(BitMapInfoHeader), 1, fd); - - // Failed to write map info header - if (ferror(fd)) { - fclose(fd); - return false; - } - - // Write palate for 8 bits per pixel - if(bitsPerPixel == 8) { - fwrite( - (char *)colors_, - numColors_ * sizeof(ColorPalette), - 1, - fd); - - // Failed to write colors - if (ferror(fd)) { - fclose(fd); - return false; - } - } - - for(int y = 0; y < height; y++) { - for(int x = 0; x < width; x++) { - // Read RGB values - if (bitsPerPixel == 8) { - fputc( - colorIndex( - pixels_[(y * width + x)]), - fd); - } - else { // 24 bit - fputc(pixels_[(y * width + x)].z, fd); - fputc(pixels_[(y * width + x)].y, fd); - fputc(pixels_[(y * width + x)].x, fd); - - if (ferror(fd)) { - fclose(fd); - return false; - } - } - } - - // Add padding - for(int x = 0; x < (4 - (3 * width) % 4) % 4; x++) { - fputc(0, fd); - } - } - - return true; - } - - return false; -} - -} // amd diff --git a/Demos/OpenCLClothDemo/bmpLoader.h b/Demos/OpenCLClothDemo/bmpLoader.h deleted file mode 100644 index 69964d68d..000000000 --- a/Demos/OpenCLClothDemo/bmpLoader.h +++ /dev/null @@ -1,200 +0,0 @@ -/* -Bullet Continuous Collision Detection and Physics Library -Copyright (c) 2010 Advanced Micro Devices - -This software is provided 'as-is', without any express or implied warranty. -In no event will the authors be held liable for any damages arising from the use of this software. -Permission is granted to anyone to use this software for any purpose, -including commercial applications, and to alter it and redistribute it freely, -subject to the following restrictions: - -1. The origin of this software must not be misrepresented; you must not claim that you wrote the original software. If you use this software in a product, an acknowledgment in the product documentation would be appreciated but is not required. -2. Altered source versions must be plainly marked as such, and must not be misrepresented as being the original software. -3. This notice may not be removed or altered from any source distribution. -*/ - - -#ifndef BMPLOADER_H_ -#define BMPLOADER_H_ - -#include - -namespace amd -{ - -//! @fixme this needs to be moved to common types header? -#pragma pack(1) -typedef struct -{ - unsigned char x; - unsigned char y; - unsigned char z; - unsigned char w; -} uchar4; - -typedef uchar4 ColorPalette; - -//! \struct Bitmap header info -typedef struct { - short id; - int size; - short reserved1; - short reserved2; - int offset; -} BitMapHeader; - -//! \struct Bitmap info header -typedef struct { - int sizeInfo; - int width; - int height; - short planes; - short bitsPerPixel; - unsigned compression; - unsigned imageSize; - int xPelsPerMeter; - int yPelsPerMeter; - int clrUsed; - int clrImportant; -} BitMapInfoHeader; - -//! \class Bitmap used to load a bitmap image from a file. -class BitMap : public BitMapHeader, public BitMapInfoHeader -{ -private: - uchar4 * pixels_; - - int numColors_; - - ColorPalette * colors_; - - bool isLoaded_; - - void releaseResources(void); - - int colorIndex(uchar4 color); -public: - - //! \brief Default constructor - BitMap() - : pixels_(NULL), - numColors_(0), - colors_(NULL), - isLoaded_(false) - {} - - /*!\brief Constructor - * - * Tries to load bitmap image from filename provided. - * - * \param filename pointer to null terminated string that is the path and - * filename to the bitmap image to be loaded. - * - * In the base of an error, e.g. the bitmap file could not be loaded for - * some reason, then a following call to isLoaded will return false. - */ - BitMap(const char * filename) - : pixels_(NULL), - numColors_(0), - colors_(NULL), - isLoaded_(false) - { - load(filename); - } - - /*! \brief Copy constructor - * - * \param rhs is the bitmap to be copied (cloned). - */ - BitMap(const BitMap& rhs) - { - *this = rhs; - } - - //! \brief Destructor - ~BitMap() - { - releaseResources(); - } - - /*! \brief Assignment - * \param rhs is the bitmap to be assigned (cloned). - */ - BitMap& operator=(const BitMap& rhs); - - /*! \brief Load Bitmap image - * - * \param filename is a pointer to a null terminated string that is the - * path and filename name to the the bitmap file to be loaded. - * - * In the base of an error, e.g. the bitmap file could not be loaded for - * some reason, then a following call to isLoaded will return false. - */ - void - load(const char * filename); - - /*! \brief Write Bitmap image - * - * \param filename is a pointer to a null terminated string that is the - * path and filename name to the the bitmap file to be written. - * - * \return In the case that the bitmap is written true is returned. In - * the case that a bitmap image is not already loaded or the write fails - * for some reason false is returned. - */ - bool - write(const char * filename); - - /*! \brief Get image width - * - * \return If a bitmap image has been successfully loaded, then the width - * image is returned, otherwise -1; - */ - int - getWidth(void) const - { - if (isLoaded_) { - return width; - } - else { - return -1; - } - } - - /*! \brief Get image height - * - * \return If a bitmap image has been successfully loaded, then the height - * image is returned, otherwise -1. - */ - int - getHeight(void) const - { - if (isLoaded_) { - return height; - } - else { - return -1; - } - } - - /*! \brief Get image width - * - * \return If a bitmap image has been successfully loaded, then returns - * a pointer to image's pixels, otherwise NULL. - */ - const uchar4 * - getPixels(void) const { return pixels_; } - - /*! \brief Is an image currently loaded - * - * \return If a bitmap image has been successfully loaded, then returns - * true, otherwise if an image could not be loaded or an image has yet - * to be loaded false is returned. - */ - bool - isLoaded(void) const { return isLoaded_; } -}; -#pragma pack() -} - -#endif // BMPLOADER_H_ diff --git a/Demos/OpenCLClothDemo/bmpLoader.hpp b/Demos/OpenCLClothDemo/bmpLoader.hpp deleted file mode 100644 index 2daae0a47..000000000 --- a/Demos/OpenCLClothDemo/bmpLoader.hpp +++ /dev/null @@ -1,189 +0,0 @@ -// -// Copyright (c) 2008 Advanced Micro Devices, Inc. All rights reserved. -// - -#ifndef BMPLOADER_H_ -#define BMPLOADER_H_ - -#include -#include - -namespace amd -{ - -//! @fixme this needs to be moved to common types header? -#pragma pack(1) -typedef struct -{ - unsigned char x; - unsigned char y; - unsigned char z; - unsigned char w; -} uchar4; - -typedef uchar4 ColorPalette; - -//! \struct Bitmap header info -typedef struct { - short id; - int size; - short reserved1; - short reserved2; - int offset; -} BitMapHeader; - -//! \struct Bitmap info header -typedef struct { - int sizeInfo; - int width; - int height; - short planes; - short bitsPerPixel; - unsigned compression; - unsigned imageSize; - int xPelsPerMeter; - int yPelsPerMeter; - int clrUsed; - int clrImportant; -} BitMapInfoHeader; - -//! \class Bitmap used to load a bitmap image from a file. -class BitMap : public BitMapHeader, public BitMapInfoHeader -{ -private: - uchar4 * pixels_; - - int numColors_; - - ColorPalette * colors_; - - bool isLoaded_; - - void releaseResources(void); - - int colorIndex(uchar4 color); -public: - - //! \brief Default constructor - BitMap() - : pixels_(NULL), - numColors_(0), - colors_(NULL), - isLoaded_(false) - {} - - /*!\brief Constructor - * - * Tries to load bitmap image from filename provided. - * - * \param filename pointer to null terminated string that is the path and - * filename to the bitmap image to be loaded. - * - * In the base of an error, e.g. the bitmap file could not be loaded for - * some reason, then a following call to isLoaded will return false. - */ - BitMap(const char * filename) - : pixels_(NULL), - numColors_(0), - colors_(NULL), - isLoaded_(false) - { - load(filename); - } - - /*! \brief Copy constructor - * - * \param rhs is the bitmap to be copied (cloned). - */ - BitMap(const BitMap& rhs) - { - *this = rhs; - } - - //! \brief Destructor - ~BitMap() - { - releaseResources(); - } - - /*! \brief Assignment - * \param rhs is the bitmap to be assigned (cloned). - */ - BitMap& operator=(const BitMap& rhs); - - /*! \brief Load Bitmap image - * - * \param filename is a pointer to a null terminated string that is the - * path and filename name to the the bitmap file to be loaded. - * - * In the base of an error, e.g. the bitmap file could not be loaded for - * some reason, then a following call to isLoaded will return false. - */ - void - load(const char * filename); - - /*! \brief Write Bitmap image - * - * \param filename is a pointer to a null terminated string that is the - * path and filename name to the the bitmap file to be written. - * - * \return In the case that the bitmap is written true is returned. In - * the case that a bitmap image is not already loaded or the write fails - * for some reason false is returned. - */ - bool - write(const char * filename); - - /*! \brief Get image width - * - * \return If a bitmap image has been successfully loaded, then the width - * image is returned, otherwise -1; - */ - int - getWidth(void) const - { - if (isLoaded_) { - return width; - } - else { - return -1; - } - } - - /*! \brief Get image height - * - * \return If a bitmap image has been successfully loaded, then the height - * image is returned, otherwise -1. - */ - int - getHeight(void) const - { - if (isLoaded_) { - return height; - } - else { - return -1; - } - } - - /*! \brief Get image width - * - * \return If a bitmap image has been successfully loaded, then returns - * a pointer to image's pixels, otherwise NULL. - */ - const uchar4 * - getPixels(void) const { return pixels_; } - - /*! \brief Is an image currently loaded - * - * \return If a bitmap image has been successfully loaded, then returns - * true, otherwise if an image could not be loaded or an image has yet - * to be loaded false is returned. - */ - bool - isLoaded(void) const { return isLoaded_; } -}; -#pragma pack() -} - -#endif // BMPLOADER_H_ diff --git a/Demos/OpenCLClothDemo/cl_cloth_demo.cpp b/Demos/OpenCLClothDemo/cl_cloth_demo.cpp index c20e549e8..0fd5c05d8 100644 --- a/Demos/OpenCLClothDemo/cl_cloth_demo.cpp +++ b/Demos/OpenCLClothDemo/cl_cloth_demo.cpp @@ -41,7 +41,7 @@ const int numFlags = 5; const int clothWidth = 40; const int clothHeight = 60;//60; float _windAngle = 1.0;//0.4; -float _windStrength = 15; +float _windStrength = 10.; @@ -256,7 +256,7 @@ void createFlag( btSoftBodySolver &solver, int width, int height, btAlignedObjec } - float rotateAngleRoundZ = 0.5; + float rotateAngleRoundZ = 0.0; float rotateAngleRoundX = 0.5; btMatrix3x3 defaultRotate; defaultRotate[0] = btVector3(cos(rotateAngleRoundZ), sin(rotateAngleRoundZ), 0.f); @@ -589,8 +589,8 @@ int main(int argc, char *argv[]) m_dynamicsWorld->stepSimulation(1./60.,0); std::string flagTexs[] = { - "atiFlag.bmp", - "amdFlag.bmp", + "bullet_logo.png", + "bullet_logo.png", }; int numFlagTexs = 2; diff --git a/Demos/OpenCLClothDemo/cloth.h b/Demos/OpenCLClothDemo/cloth.h index bb743c8dc..89d7e8d05 100644 --- a/Demos/OpenCLClothDemo/cloth.h +++ b/Demos/OpenCLClothDemo/cloth.h @@ -16,7 +16,8 @@ subject to the following restrictions: #include "gl_win.h" //for OpenGL stuff -#include "bmpLoader.h" +#include "stb_image.h" + #include #include #include "LinearMath/btScalar.h" @@ -84,7 +85,7 @@ class piece_of_cloth glEnable(GL_DEPTH_TEST); - glColor3f(0.0f, 1.0f, 1.0f); + glColor3f(1.0f, 1.0f, 1.0f); #ifdef USE_GPU_COPY int error = 0; glBindBuffer(GL_ARRAY_BUFFER, clothVBO); @@ -134,82 +135,60 @@ class piece_of_cloth void create_texture(std::string filename) { - amd::BitMap texBMP(filename.c_str()); + int width,height,n; + unsigned char *data = stbi_load(filename.c_str(), &width, &height, &n, 0); - if ( !texBMP.isLoaded() ) - { - //alternative path - char newPath[1024]; - sprintf(newPath,"Demos/OpenCLClothDemo/%s",filename.c_str()); - texBMP.load(newPath); - if (!texBMP.isLoaded()) + + GLubyte* image=new GLubyte[512*256*4]; + for(int y=0;y<256;++y) + { + const int t=y>>4; + GLubyte* pi=image+y*512*4; + for(int x=0;x<512;++x) { - sprintf(newPath,"../../../../../Demos/OpenCLClothDemo/%s",filename.c_str()); - texBMP.load(newPath); + const int s=x>>5; + const GLubyte b=180; + GLubyte c=b+((s+t&1)&1)*(255-b); + pi[0]=pi[1]=pi[2]=c;pi[3]=1;pi+=4; } } - - if ( texBMP.isLoaded() ) { - glEnable(GL_TEXTURE_2D); - glGenTextures(1, &m_texture); - - glBindTexture(GL_TEXTURE_2D, m_texture); - - glPixelStorei(GL_UNPACK_ALIGNMENT, 1); - glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR); - glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR); - - glPixelStorei(GL_UNPACK_ALIGNMENT, 1); - glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_REPEAT); - glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_REPEAT); - glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR); - glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR); - glTexEnvf(GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_DECAL); - - glTexImage2D( - GL_TEXTURE_2D, - 0, - GL_RGBA8, - texBMP.getWidth(), - texBMP.getHeight(), - 0, - GL_RGBA, - GL_UNSIGNED_BYTE, - texBMP.getPixels()); - - glBindTexture(GL_TEXTURE_2D, 0); - } - else { - printf("ERROR: could not load bitmap, using placeholder\n"); - - GLubyte* image=new GLubyte[256*256*3]; - for(int y=0;y<256;++y) + if ( data ) + { + + for (int i=0;i>4; - GLubyte* pi=image+y*256*3; - for(int x=0;x<256;++x) - { - const int s=x>>4; - const GLubyte b=180; - GLubyte c=b+((s+t&1)&1)*(255-b); - pi[0]=pi[1]=pi[2]=c;pi+=3; - } - } + int offsetx = (512-width)/2; + int offsety = (256-height)/2; - glGenTextures(1,(GLuint*)&m_texture); - glBindTexture(GL_TEXTURE_2D,m_texture); - glTexEnvf(GL_TEXTURE_ENV,GL_TEXTURE_ENV_MODE,GL_MODULATE); - glTexParameterf(GL_TEXTURE_2D,GL_TEXTURE_MIN_FILTER,GL_LINEAR_MIPMAP_LINEAR); - glTexParameterf(GL_TEXTURE_2D,GL_TEXTURE_MAG_FILTER,GL_LINEAR_MIPMAP_LINEAR); - glTexParameterf(GL_TEXTURE_2D,GL_TEXTURE_WRAP_S,GL_REPEAT); - glTexParameterf(GL_TEXTURE_2D,GL_TEXTURE_WRAP_T,GL_REPEAT); - gluBuild2DMipmaps(GL_TEXTURE_2D,3,256,256,GL_RGB,GL_UNSIGNED_BYTE,image); - delete[] image; + GLubyte* pi=image+((j+offsety)*512+i+offsetx)*4; + const GLubyte* src=data+(j*width+i)*4; + pi[0] = src[0]; + pi[1] = src[1]; + pi[2] = src[2]; + pi[3] = 1; + } + } } + else + { + printf("ERROR: could not load bitmap, using placeholder\n"); + } + + glGenTextures(1,(GLuint*)&m_texture); + glBindTexture(GL_TEXTURE_2D,m_texture); + glTexEnvf(GL_TEXTURE_ENV,GL_TEXTURE_ENV_MODE,GL_MODULATE); + glTexParameterf(GL_TEXTURE_2D,GL_TEXTURE_MIN_FILTER,GL_LINEAR_MIPMAP_LINEAR); + glTexParameterf(GL_TEXTURE_2D,GL_TEXTURE_MAG_FILTER,GL_LINEAR_MIPMAP_LINEAR); + glTexParameterf(GL_TEXTURE_2D,GL_TEXTURE_WRAP_S,GL_REPEAT); + glTexParameterf(GL_TEXTURE_2D,GL_TEXTURE_WRAP_T,GL_REPEAT); + gluBuild2DMipmaps(GL_TEXTURE_2D,4,512,256,GL_RGBA,GL_UNSIGNED_BYTE,image); + delete[] image; } void create_buffers(int width_, int height_) @@ -237,8 +216,8 @@ class piece_of_cloth cpu_buffer[y*width+x].normal[0] = 1; cpu_buffer[y*width+x].normal[1] = 0; cpu_buffer[y*width+x].normal[2] = 0; - cpu_buffer[y*width+x].texcoord[0] = x/((float)(width-1)); - cpu_buffer[y*width+x].texcoord[1] = y/((float)(height-1)); + cpu_buffer[y*width+x].texcoord[0] = 1*x/((float)(width-1)); + cpu_buffer[y*width+x].texcoord[1] = (1.f-4*y/((float)(height-1))); } } diff --git a/Demos/OpenCLClothDemo/clstuff.cpp b/Demos/OpenCLClothDemo/clstuff.cpp index bfda3464e..f8b2c78b0 100644 --- a/Demos/OpenCLClothDemo/clstuff.cpp +++ b/Demos/OpenCLClothDemo/clstuff.cpp @@ -34,6 +34,8 @@ void initCL( void* glCtx, void* glDC ) #if defined(CL_PLATFORM_MINI_CL) cl_device_type deviceType = CL_DEVICE_TYPE_CPU;//or use CL_DEVICE_TYPE_DEBUG to debug MiniCL +#elif defined(CL_PLATFORM_INTEL) + cl_device_type deviceType = CL_DEVICE_TYPE_CPU; #elif defined(CL_PLATFORM_AMD) cl_device_type deviceType = CL_DEVICE_TYPE_GPU; #elif defined(CL_PLATFORM_NVIDIA) diff --git a/Demos/OpenCLClothDemo/texture1.bmp b/Demos/OpenCLClothDemo/texture1.bmp deleted file mode 100644 index 1d3da81c1018175fc27d941d9932f1d082beb521..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 786486 zcmeI$OS0@Rav0FI#|n=<^w2BNSmC)>?TvUTuJ)Bm2!KR^AVA`CI@A)0!YA`2nD6QR zumAn8|M-`G{PREm`uXqw{O7}e{rm5K`Nx0%=iBE$|MHLj^WXmQ|Nr~?K!5-N z0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+ z009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBly zK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t6-z__zP@f4~1T zNyx$^K!5;&y8_?N|MzfrJL?G$AV6SvfvEHA|HD^IfCLB-Xds~ZH$b!n0RjXj6iEC3 zgh>dQ009C7t_eiV|Jq`+2@oJaU`~Ok`F~#L%tO=!2oNA}K|u4rfMqHH0t8kO(EL}a zq&x@^AW$lhc7FftQ)*`(0RjZ370~>rEuFv#5Fk)5p!wI^SxJBZfoTQO=09yJ0w+L# z0D)40wE2HVN*9|)fB*pka|)!*f6hEaO@IIa0v7}{{|i{A64+HBZ4?iT?27$R-f0CN zI@mD;2n-{T_JQd}hOwL=kh9`W5V{Zv5V$CC_PsATe$i&T>1RdX4no2NmJm4mqKz+6 z-j+!mUWt|m*oy#xM+6SP<$i;Y)ha!(=CjTZjbq7C8KJ4+r;lx{&>$UO0GRui>YLd4B>48sgc9!7NaX60vfdYZE4>lby*vyntfs{8IDcxw8c~Sh~>o742gaCnm z7YM)5vu9Yn1I8eZIN5~KjSQ;X=QOWXFI9L4s1 z?R~EO2@oh0_n)I}QTS8uFn;bI1`|I2TxbFT0uKm;UuFLJfnXeQNg!XZ z=+{d--<%vB9lhS%+;Rd0?g&KRWB&EdLDoJdkS}8NYxAh0{m)*TpKC(`1bzyfeUFFZ zKX)@>aDl_JzB@R$nD7WJCQ$LcFD9^aIu+ILv}ETh$eqBG0u`U|li@k*ErE)QadXLA znL3xih60zq)(w56{3mefo?Mztm;iyt1bmy1Q9FnL0RpcJ==ragKmY^?5O`8R+kaBq zSp*0Wcvs+3&;Lw*H(I9?AV7e?O@Z>ZfAb*A2@oJa;B^5#|Me0GfB*pkj|r6beE+ud zSWz5AfB=Es0wvAAcMSF?K!5;&X9P-mzQ5`}QwygMAVA;&fs(fWKp2i7K!5;&X9TqU zXPlivfB=C(1WMYzf8-gYSi&GcfWUnLZU4TZ9S9I0FpGemKTD;=Nq_)>h5|pEf5WqE zMSuVS0wW0IJO2m~ih%$D0tA`}}8G2)r&(((^xaUXN1%1PBly&`O}N z^K1UC!0khT0D;#93OoPnaSDI{0RjZ>3zYQy`={7}009E!0wsN^Zccd&YtQ_tw|4rn zBS2sTfuD`&fe9lxJQG6+<};Bvg#dw_1xk9+^K+J|$W^*!5|;=80%HnXZAx#=A5*U| zs!M2vdzwao0D(IK@Ajojr$>|TWc~2kDDuqf!+|-D0D%n!GA-!urx#6r#uiO@G1Sb_ zQIMI}%qD&!K!8A7flM#@{M7cWo4e&hO@F<4+@0lVFoz>|j(;xu?1f~;+y5Ds13zz@_0tD&=^#3|Hs|XMvFtvc@KXv&8 zPk;b{Y61Pfn$AK31PIJ4p!v^RJCPG0K;Vvm{(nc$S^@+J%qtM~|9P_zIROF$2wWA= z|F4RfPk;b{H3ankHR>n}0t5(L70~~$ikVM<0D(0G^#3*LC<_7v2wWA=|F4RfPk;b{ zH3Y)`|9M^`DOnI8&{iO76wP1TMr*f1fvAp!t4t$6U_F7T8@%$mp6cKkMO7X=THz5O z&`==y{Kt81n4_)o0%6hfGyO_{z@!4#lyzA93^7 zlBjMTVR=R%^3Tll69EE)3q+rD`RnU>npX#OOxirpFn=6Z1qK&j?30s^5rVxm}uZLf!AUX^3(CTcm@j8JB zxo#7y-V%t)*Y)+S9H%?CYZWq^PY3lg;KO8pt}@}0K!kj0t;r1qqCyP&+A!tWw;G{F zvm55)KNQX{@#`glRQS?zlkW(m_|uKtNq_vcLzQEEu1*oARp@lkp4&#edm{ACIznFi zwKrz({aaP1cbxm|pH^g_+#kp^;(g%6^^S-PpLu;s!- zdUK>4dAFH2VINq&TSeB$H@z5Z&c&-pQRQ(KAY}IecS&-3qzX0q^fWYel(f9uM`g&Be2XLtR zu5Biy^rzYV#ZQ1hp+Nfie?|(|nsz2|sQNc}wxs!ZCWiE<=BL|`0D)NqG=xr-N@1gs z>T{!gs$Z)Eu#fd2&O!nN2uv*y^?(0gz|_?gJOKg(E(t_`1YBBcG64bv z2uv*y{t+;BB7!GCfB=C@0%8C6Pe7OGOeR2pz|;cz|J3CZJOKg(?g;oJ;EtZP1PBnA zS|I!*VCqB!Pk;ac0+$5z|4UpZ6Cglf8G*3>f1a1gOCkga5Fn5j(Esy3ekDMFz`_FI z9{~%eDK!EF2oQ(_^#2IND**xoHWASOHz~9<2@oI<3F!Y3h*tsx2y7yt|8G)gX%Zkn zAQI63BM`3y2oTsrK>y#Q(9$G8fIuXm|3@HR2@oK#iGcpUNui}lfB=C=K>v?Gyb>Tl zU=soTf0IH>lK=q%k%0amfp{fAfWRgK`u`?{mL>rL1VVwZ`G20npF9&FK!Cui0#WnV z|5q)vya*5=5D7&6Kl;@x0RjXFtS1n4et+{{uf#GUK!89hkT!q)KUFe9fB=D&1P(jD z=D$*jeb_A+y|11PBlyFoi&-$)Ei+MP7m=K!5;&Gl8@Ael~u#k8uJ72oRV;;HY$-^#B92oNAJzCgaue}5f65fKs~K!8Arz_+pgd??w?90CLg z5ExeAXP*xz44Z|(2oNAZ;F3Vt+cVFX_B5FQ0RjX@6UcP<^rz8+7Y_jfe*)>(+GB+F z)B<%^V(OFyPheGny3e`Qs#R4N%d4*3iy=sdz#0N|pL4%eYp5=h#r;ArLm?3Y%Lv^6 zuDkBAjPs<4R2O&Be1%P56M@1{ySK*AFnR}I|387Bg~&``NPxf;0-3Kk{OOfk!T`eO zSAyB$&=C3R^A0|8B(Rb|{u>`8)3YE432)Lc&QuG>C(T;e1PJ^IoPFtI`kY1k86Pv? zp`yy@UHxgOyaYplK!w2JS6{Ku!%Ggs{tP}G#uUe$S(T4Zk)|LC5V$0ec7RLE-<_NW zAC9~m+ry`ai8pzEIDW?wAn>q2+9)0l;Qn!G3Wp>24|;2d!*tpXzLlDD2@rToAnGA+ zh0*HVD4ny{R>w8p=Pcmnk*9sT-2Y3@UfyzV0a z0t6NoNZZ}Q$sVSb3Oq1!7>Pjw1PDAPkT$xrmkdh5!Kq1Ud;s{lC*Gwk1G-0D++dH2 zAs7M#2s|dB|360UAOZvk3?&fu|DggC3;_ZJ2y_+D|GVnaf5kgf;WoB)9y0^uk8{Bw_t?D?2Lcwrtp)IkIYR0xD$ z>wwP{8CmkKKzNJZjl}5$2z&&>Pjc#K)f`_SykO%;D?$RR3WQ(co#%c&by4+;$IkZ! z!kXUS%?<JU##I8S;r_ePFn^y~j6|COGLIMQ70^v8+_W66nfDb=29WZ7g zg;k?LfIyu<_#NGRt_xtORc8W21u2-1Kv*dt1PJ5>!tbT+bN<{Je?9b>F_DF14r{b< zno`?SAiUm#JnvSBlzlgWk@F3!Gjg0_BajM&w|AW9G|tUO($Z`WGEVwoX~v04B(n>I z_iBgd+3VFi{`3y?KGFUq0%2WB=9@zx5(ux*4$o2gUJC`%yHU8%w0;6nQTiQZ=QRYP z3p4oZ8s^Jnk=~YNQkyi9s3MbQA?ybPqN_5(>jPOkqOCxBZQAZ{x2pnCMXoM4e?5Wd zN>seAXCk9k0?~D9wXJ>X1fp_$UhDR;YHES>8WfI9oweX!5s0qVD=|3qD-f0A^ZNbC z!>R&l(F;db1(Da20_kOY@^oiK0#P}lU%jp&5LNlo>ly;G7)Kzwe&YnTXC%t8UfrXb z7QU|MAfqt_q6;}@kefsm)#CHIN#bjynU?R;$QlT;m`fnNqI1Q+ShP_&7Rzp>bfQXC zyso4nmw5%!t2=Kl3q&53V}Xp;NFl0A-Rl|@vRF(Yz08XxI8i!kF+#D@D%6dPkc$`y z{1iy9_s=CJbP|Ya(diW1rUH@trPp*fBLpTAh;I8tk*^o3T0BtG2>H_M1K~M>z{3L3 zC-Cs;j{6Ekh4{RFfAVl&Am#lza{o{}5Ext_{R##Tc;WEWqG54U%=}2hqiscCB7yX~ zm?-$gLRE|Ef~IsOBh|-QNMIR(=u259uNf1GYVr3vVXIa#}8P91PBly&`Q7`0j(tMLx2E*xdin8x#}fa0t5&& z6bSzaXt=Gd2oNAZU~mEbfA9hcj{pGzodm-E|9S3oifsuHAV6S1f$)!j0mBm#0RjXF zbP~}2JHgtP009Dn3xxgOKLHJ1Ea4F#K%k+3{@)PORs;wTm`fo1BVew`MN5DH0Rndf z!v61{fbK|IOMn1@xdin8x#}fa0t5&&6bSzaXt=Gd2oNAZU~mEbfA9hcj{pGzodop% zPO!EmK!CvD0{Z{p1riMHyZA*Xvfx!jz|G^6+JOTs=^biP}|L3{K5%wfN zfB=C31@!*`iy|Zf1PJsN(ENJ~+n)dd0s{&}&EG%%3|J!}5gJ@ zl|bfGdh(~O%q4qA;Otu7+0$AA%L|-+IHQd(UkC|S2xM+)#cq}m*g+uk)lB!(4)u~_ zB#^(Q(PXa#HW$c$FYEofdAZk4KYv}<&Ruo{$_4UYO8(dKQ+mwI$5!}jkHGBtmcY-V zzZIBs35+1{^8-1XFhcP87|tTE7|$Q%*8v6cRUR;4ArWXOkiY*Gzc!5R#jPq5KV0%+ z3XaYQ92P4a%&hejfk_3z8{X=9Qi{5;>(J`XvZ}d2N%@)|YC{5V36xy;>N#&E_3pXV zT;GN7#=qg|U-`_#hAdKEOdxZ;Z~n9xRF8BjgnNWx&p(0kau6dhwLtk*PiIb@_{hPh z)IUc?PG_RnemZ|9Oq7mL2}A-VH~ef)w3XN10%wId9Pb^>!uub3MuQ8dFSWG=qMKa) zx;D#P*_Bsqy_sz*b;+mg(RL&7n82lb{+aw(U=F$|aJ90V%r8+bp(xqM90J1%lw9)f zoME#NSc$;5jvnp{lz^K*%JXVFc_2-KNdMPM|6!%IF|km4awC~$b6 zn+z5PU>bob1P(unDIymnftvz{m;Y?==2?~#7){{ts*e_=cnA<6K%k+(Vdwu0Hax;s z1PBlyFq*(&^B*lp@em+DfIvfm!_M!o{SAd}MSuW-(FAn<(JCSy0t5*37SQ>73)`On z0RjUGX#N8hMMwk)5a=gx*7iT+{SLJ=0RjXFyen|l{NIhr=>!N6Aka_Xtn>S8e?N0O z6Cgm~b%C?y|9W5oAV7csfqnvq&A;Dqb|yf80D;#9bpF>%AOHdc2s|&K`9E*&L;?f| zyen|n`9Fj2M&)z@1PBo5C!q89v$Zn;0tChsIP3iW+COH!L`8rAfhGcH&A-X!HX%TO z0D;j2&f31e^N&_3@em+Dpou`H?d$wagl$5A0D%DoH2(pMA|wI?2=o)kw|#%@?9NvvJQj^8(0*9BgdT@4)JMm}G?rdxAyaI<;V%~H_ zKD)r-g}gsFJ4?g(&oCPvVXG+w4sXH~kqdGefx}C9X>b{ehZ9MW9}d8AFAAvsi};%# zo!-5|kCs8$k4Z(ZTYN(iIn5|v=I@Wj(rAS(CYYuh92 zMj#Y8ymFbraINRw0%;+7pJ@NL1kzf6M&1g>xl0Nh-m%Q!k_dAp6;)@h;6+;~5LNl} zTDZ_O0%rp0r79db+tBzc0#VgoiNT>=1(die?^c^fcd77oE26oQjVd@-@S^=GpuRte zOh^TyYg6}{Zfj&ffvC6xMku6e0mZGR+i+oYTQ0qB$hAhwQI*$7N)~?tVR4xdNN+`W zL&~2?t|SoFeWkoM&m}DD=XrAt>Hi5tx8l+(!zBfxJFsMq8z!Z!8x}oGIl2Jlui+-1 zmludG#`5`Yl3-ZYO;X-G&9LHi&zl2on|^p(wnbPe@vxwu=ao{EODYhR`{!%AgOQyD zq6@P##R9oU)%?6Jkdzc6fwamcBhe;a348>io5N&k0o9zke3{^*%I04)`}m1KBoN-E z=qImp2`J@U^-7}+D|qQS-O31o5`plVmCQG1Oo6bDpXV`y6jeqbs$j`$W;Z_(C=m#+ zS;>5J#uNza_<0^PNKu6XQOU|*!%aLBxFZnWx;y(=`>udGzUyCpdRVE#=km?XBydR} zyn&Y%nmmp`Sj5lsIDv`eBM?<5|4NL&lLFyweDYjpH53So_<3%)v#st3M0Lr(-Z{ux z0(Ao6ovhozs@DY+ai|i6<;Xn09-U@{1gZ;@XyI6 z3@D(2U5gU(=AXNUVRHgK1i~xbV}E=07Er-X!Xa$_xl;hPCD2Op! zGL}C#Ioc)!-Vz9}`dcwL_l|%H-qHK44FP{X-#p850z(Oe7k;R~1XC!Wf`w4uX`xuj z^LL>K0*eWR_kXd}Hc3YX3kw}Wl{^=2YZ`%h1;P(u-Yj;GTm{qWhbD#3=_W=9tSu0I z8fz!JYIcek30!?$^s|-RMHmD|5Qsja5ke9}oj_E|&uiU2udhlIsUCSf7Xc6$Ss?ndMh;bM zKLw&{{=NQO^~!|9P;U;tl88eI%qtLnar0&&@~=Qx(DeB`?fHi^nCg+|gLfi<^#r01 zaJ>Zg%qS}B&)1tuKlg7n;bxqc6Ce-@L?34Oljqq5qTzFK}BCw%A^!aZnAmu-S=q6OWk|aQ2B7yW9 zpD1{t5+Fc;K(#>B|Eu@0kN^P!1SS&D{3j}wPzewq&`Ka`{-4)YJKKi<0RjYu70~>L zEsekk5FpT1AnN~J&$2lI0t5(*AP{wa|LikDQN%!i0D-OoY3KhN>3XQm2@oJa;9Y^k z=KpR;PA5Qs0D;~DntyL$`x78QU^D@pf3%8-hX4Tr4+v=f43uD;v}5ZF*a+uyM0QYJuPLxFs^4}aYdN6G{U5Li_pZ10)pRnwOj0RjZ}5y&+8 z^rwATWJ-Vlfh7gf#-1Np5T z;AgLHHDMMIaS|XvU?PE5ExP$W6B!DX009DH3N-J`JvJPZPE-U45ST)sM_cZ_=M=Dl zBtU?`AOgL6@}>O;F%bp<0t8kSxYUy`On@x;mw;#q5FoI;KwIuu!Nss^m0<#EIck;}_S#lRA0RjZ} z6v#C2@}KsklQjVX1jZLA@8l&j$In-U1PBn=P@trNm(SS{P|5@d5SU1yyq{-gPL!`u z2@oK#n?R;}SO2t|p?nDtATYQLx~e0Kwu()iuQiE zWTKRXN`L@?4FwKc_ocxN(WFd(0DSW@6;e{MTrNkd5yAV6Sn zfwrCe>TZMM2#){(0)q%#?XE-3AH+}?1PBlqM_{NfeJ7Z4NJT<`0D++d?zGnD*A7J| z7y<+c3@h+_e{Oi!pQ0y_wl_wACIJBZ1V009CE2$Zz+bj|{aOMw6Z0-Fn@y*(P)+(-I71fo0E z9z}a`VQjT(|6F9pYQ;*kCSVdq-f#_RaGDk@r3Ph#%dZ=WOz`_FISHEzY zQVRvbqI*6R2)R5HSXCgr{Hx};ZC+t<2Yl{VmsZL4i_p#lMi2^0^t{Ne>Xe4A`lj_{P~qo$2{~W+L&RBioi{Q@aEs#%JRnq!m3p~ zKNjbV2mSP%F)1+$`uRFY*fWOl)AloA#=OK#AQVXNdHAd67X{MN z{2X~P+9i($zGPV?6$(U`Jp9RXZ-EHE?zMN2JMUjuk)4U;KD$74$!AYzkoY6jhOdJp zxLX+I72HimzEcZC7klblUJO2BZ2tOUYK{&CE>$*M=$XKn0@0NoGsvN$io}|~4wbB6 zB7r;Qj<)hj;B|rMKEEE%H~~a5&0ojKR3sGw&F{l!!-_C0A#hV5y2&?pn|gUfQT;kK zg5WCzs;|o7!ioSaAy6lf-oUzj=313zT|F{a;-c*>P<@fYg}sBcKY_16c=5i^-(S~w z_~v!@ESvw0HUeOsr4il*xoH2bd&nS?&pEIT-<{1Stm+9H&qvq$2>TN_6PUN>pJim6009C7t_n=?XTjB^%qKvA0D(GzxBgJ5i`FUv1PBly zK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF z5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk z1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs y0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FoIO!2bgsD41vf diff --git a/Demos/OpenGL/CMakeLists.txt b/Demos/OpenGL/CMakeLists.txt index dbff17c17..067b09944 100644 --- a/Demos/OpenGL/CMakeLists.txt +++ b/Demos/OpenGL/CMakeLists.txt @@ -42,6 +42,8 @@ ADD_LIBRARY(OpenGLSupport GlutStuff.cpp GlutStuff.h + stb_image.cpp + stb_image.h Win32DemoApplication.cpp Win32DemoApplication.h diff --git a/Demos/OpenGL/stb_image.cpp b/Demos/OpenGL/stb_image.cpp new file mode 100644 index 000000000..fb2de7d6d --- /dev/null +++ b/Demos/OpenGL/stb_image.cpp @@ -0,0 +1,4342 @@ +#include "stb_image.h" + +#ifndef STBI_HEADER_FILE_ONLY + +#ifndef STBI_NO_HDR +#include // ldexp +#include // strcmp, strtok +#endif + +#ifndef STBI_NO_STDIO +#include +#endif +#include +#include +#include +#include + +#ifndef _MSC_VER + #ifdef __cplusplus + #define stbi_inline inline + #else + #define stbi_inline + #endif +#else + #define stbi_inline __forceinline +#endif + + +// implementation: +typedef unsigned char uint8; +typedef unsigned short uint16; +typedef signed short int16; +typedef unsigned int uint32; +typedef signed int int32; +typedef unsigned int uint; + +// should produce compiler error if size is wrong +typedef unsigned char validate_uint32[sizeof(uint32)==4 ? 1 : -1]; + +#if defined(STBI_NO_STDIO) && !defined(STBI_NO_WRITE) +#define STBI_NO_WRITE +#endif + +#define STBI_NOTUSED(v) (void)sizeof(v) + +#ifdef _MSC_VER +#define STBI_HAS_LROTL +#endif + +#ifdef STBI_HAS_LROTL + #define stbi_lrot(x,y) _lrotl(x,y) +#else + #define stbi_lrot(x,y) (((x) << (y)) | ((x) >> (32 - (y)))) +#endif + +/////////////////////////////////////////////// +// +// stbi struct and start_xxx functions + +// stbi structure is our basic context used by all images, so it +// contains all the IO context, plus some basic image information +typedef struct +{ + uint32 img_x, img_y; + int img_n, img_out_n; + + stbi_io_callbacks io; + void *io_user_data; + + int read_from_callbacks; + int buflen; + uint8 buffer_start[128]; + + uint8 *img_buffer, *img_buffer_end; + uint8 *img_buffer_original; +} stbi; + + +static void refill_buffer(stbi *s); + +// initialize a memory-decode context +static void start_mem(stbi *s, uint8 const *buffer, int len) +{ + s->io.read = NULL; + s->read_from_callbacks = 0; + s->img_buffer = s->img_buffer_original = (uint8 *) buffer; + s->img_buffer_end = (uint8 *) buffer+len; +} + +// initialize a callback-based context +static void start_callbacks(stbi *s, stbi_io_callbacks *c, void *user) +{ + s->io = *c; + s->io_user_data = user; + s->buflen = sizeof(s->buffer_start); + s->read_from_callbacks = 1; + s->img_buffer_original = s->buffer_start; + refill_buffer(s); +} + +#ifndef STBI_NO_STDIO + +static int stdio_read(void *user, char *data, int size) +{ + return (int) fread(data,1,size,(FILE*) user); +} + +static void stdio_skip(void *user, unsigned n) +{ + fseek((FILE*) user, n, SEEK_CUR); +} + +static int stdio_eof(void *user) +{ + return feof((FILE*) user); +} + +static stbi_io_callbacks stbi_stdio_callbacks = +{ + stdio_read, + stdio_skip, + stdio_eof, +}; + +static void start_file(stbi *s, FILE *f) +{ + start_callbacks(s, &stbi_stdio_callbacks, (void *) f); +} + +//static void stop_file(stbi *s) { } + +#endif // !STBI_NO_STDIO + +static void stbi_rewind(stbi *s) +{ + // conceptually rewind SHOULD rewind to the beginning of the stream, + // but we just rewind to the beginning of the initial buffer, because + // we only use it after doing 'test', which only ever looks at at most 92 bytes + s->img_buffer = s->img_buffer_original; +} + +static int stbi_jpeg_test(stbi *s); +static stbi_uc *stbi_jpeg_load(stbi *s, int *x, int *y, int *comp, int req_comp); +static int stbi_jpeg_info(stbi *s, int *x, int *y, int *comp); +static int stbi_png_test(stbi *s); +static stbi_uc *stbi_png_load(stbi *s, int *x, int *y, int *comp, int req_comp); +static int stbi_png_info(stbi *s, int *x, int *y, int *comp); +static int stbi_bmp_test(stbi *s); +static stbi_uc *stbi_bmp_load(stbi *s, int *x, int *y, int *comp, int req_comp); +static int stbi_tga_test(stbi *s); +static stbi_uc *stbi_tga_load(stbi *s, int *x, int *y, int *comp, int req_comp); +static int stbi_tga_info(stbi *s, int *x, int *y, int *comp); +static int stbi_psd_test(stbi *s); +static stbi_uc *stbi_psd_load(stbi *s, int *x, int *y, int *comp, int req_comp); +static int stbi_hdr_test(stbi *s); +static float *stbi_hdr_load(stbi *s, int *x, int *y, int *comp, int req_comp); +static int stbi_pic_test(stbi *s); +static stbi_uc *stbi_pic_load(stbi *s, int *x, int *y, int *comp, int req_comp); +static int stbi_gif_test(stbi *s); +static stbi_uc *stbi_gif_load(stbi *s, int *x, int *y, int *comp, int req_comp); +static int stbi_gif_info(stbi *s, int *x, int *y, int *comp); + + +// this is not threadsafe +static const char *failure_reason; + +const char *stbi_failure_reason(void) +{ + return failure_reason; +} + +static int e(const char *str) +{ + failure_reason = str; + return 0; +} + +// e - error +// epf - error returning pointer to float +// epuc - error returning pointer to unsigned char + +#ifdef STBI_NO_FAILURE_STRINGS + #define e(x,y) 0 +#elif defined(STBI_FAILURE_USERMSG) + #define e(x,y) e(y) +#else + #define e(x,y) e(x) +#endif + +#define epf(x,y) ((float *) (e(x,y)?NULL:NULL)) +#define epuc(x,y) ((unsigned char *) (e(x,y)?NULL:NULL)) + +void stbi_image_free(void *retval_from_stbi_load) +{ + free(retval_from_stbi_load); +} + +#ifndef STBI_NO_HDR +static float *ldr_to_hdr(stbi_uc *data, int x, int y, int comp); +static stbi_uc *hdr_to_ldr(float *data, int x, int y, int comp); +#endif + +static unsigned char *stbi_load_main(stbi *s, int *x, int *y, int *comp, int req_comp) +{ + if (stbi_jpeg_test(s)) return stbi_jpeg_load(s,x,y,comp,req_comp); + if (stbi_png_test(s)) return stbi_png_load(s,x,y,comp,req_comp); + if (stbi_bmp_test(s)) return stbi_bmp_load(s,x,y,comp,req_comp); + if (stbi_gif_test(s)) return stbi_gif_load(s,x,y,comp,req_comp); + if (stbi_psd_test(s)) return stbi_psd_load(s,x,y,comp,req_comp); + if (stbi_pic_test(s)) return stbi_pic_load(s,x,y,comp,req_comp); + + #ifndef STBI_NO_HDR + if (stbi_hdr_test(s)) { + float *hdr = stbi_hdr_load(s, x,y,comp,req_comp); + return hdr_to_ldr(hdr, *x, *y, req_comp ? req_comp : *comp); + } + #endif + + // test tga last because it's a crappy test! + if (stbi_tga_test(s)) + return stbi_tga_load(s,x,y,comp,req_comp); + return epuc("unknown image type", "Image not of any known type, or corrupt"); +} + +#ifndef STBI_NO_STDIO +unsigned char *stbi_load(char const *filename, int *x, int *y, int *comp, int req_comp) +{ + FILE *f = fopen(filename, "rb"); + unsigned char *result; + if (!f) return epuc("can't fopen", "Unable to open file"); + result = stbi_load_from_file(f,x,y,comp,req_comp); + fclose(f); + return result; +} + +unsigned char *stbi_load_from_file(FILE *f, int *x, int *y, int *comp, int req_comp) +{ + stbi s; + start_file(&s,f); + return stbi_load_main(&s,x,y,comp,req_comp); +} +#endif //!STBI_NO_STDIO + +unsigned char *stbi_load_from_memory(stbi_uc const *buffer, int len, int *x, int *y, int *comp, int req_comp) +{ + stbi s; + start_mem(&s,buffer,len); + return stbi_load_main(&s,x,y,comp,req_comp); +} + +unsigned char *stbi_load_from_callbacks(stbi_io_callbacks const *clbk, void *user, int *x, int *y, int *comp, int req_comp) +{ + stbi s; + start_callbacks(&s, (stbi_io_callbacks *) clbk, user); + return stbi_load_main(&s,x,y,comp,req_comp); +} + +#ifndef STBI_NO_HDR + +float *stbi_loadf_main(stbi *s, int *x, int *y, int *comp, int req_comp) +{ + unsigned char *data; + #ifndef STBI_NO_HDR + if (stbi_hdr_test(s)) + return stbi_hdr_load(s,x,y,comp,req_comp); + #endif + data = stbi_load_main(s, x, y, comp, req_comp); + if (data) + return ldr_to_hdr(data, *x, *y, req_comp ? req_comp : *comp); + return epf("unknown image type", "Image not of any known type, or corrupt"); +} + +float *stbi_loadf_from_memory(stbi_uc const *buffer, int len, int *x, int *y, int *comp, int req_comp) +{ + stbi s; + start_mem(&s,buffer,len); + return stbi_loadf_main(&s,x,y,comp,req_comp); +} + +float *stbi_loadf_from_callbacks(stbi_io_callbacks const *clbk, void *user, int *x, int *y, int *comp, int req_comp) +{ + stbi s; + start_callbacks(&s, (stbi_io_callbacks *) clbk, user); + return stbi_loadf_main(&s,x,y,comp,req_comp); +} + +#ifndef STBI_NO_STDIO +float *stbi_loadf(char const *filename, int *x, int *y, int *comp, int req_comp) +{ + FILE *f = fopen(filename, "rb"); + float *result; + if (!f) return epf("can't fopen", "Unable to open file"); + result = stbi_loadf_from_file(f,x,y,comp,req_comp); + fclose(f); + return result; +} + +float *stbi_loadf_from_file(FILE *f, int *x, int *y, int *comp, int req_comp) +{ + stbi s; + start_file(&s,f); + return stbi_loadf_main(&s,x,y,comp,req_comp); +} +#endif // !STBI_NO_STDIO + +#endif // !STBI_NO_HDR + +// these is-hdr-or-not is defined independent of whether STBI_NO_HDR is +// defined, for API simplicity; if STBI_NO_HDR is defined, it always +// reports false! + +int stbi_is_hdr_from_memory(stbi_uc const *buffer, int len) +{ + #ifndef STBI_NO_HDR + stbi s; + start_mem(&s,buffer,len); + return stbi_hdr_test(&s); + #else + STBI_NOTUSED(buffer); + STBI_NOTUSED(len); + return 0; + #endif +} + +#ifndef STBI_NO_STDIO +extern int stbi_is_hdr (char const *filename) +{ + FILE *f = fopen(filename, "rb"); + int result=0; + if (f) { + result = stbi_is_hdr_from_file(f); + fclose(f); + } + return result; +} + +extern int stbi_is_hdr_from_file(FILE *f) +{ + #ifndef STBI_NO_HDR + stbi s; + start_file(&s,f); + return stbi_hdr_test(&s); + #else + return 0; + #endif +} +#endif // !STBI_NO_STDIO + +extern int stbi_is_hdr_from_callbacks(stbi_io_callbacks const *clbk, void *user) +{ + #ifndef STBI_NO_HDR + stbi s; + start_callbacks(&s, (stbi_io_callbacks *) clbk, user); + return stbi_hdr_test(&s); + #else + return 0; + #endif +} + +#ifndef STBI_NO_HDR +static float h2l_gamma_i=1.0f/2.2f, h2l_scale_i=1.0f; +static float l2h_gamma=2.2f, l2h_scale=1.0f; + +void stbi_hdr_to_ldr_gamma(float gamma) { h2l_gamma_i = 1/gamma; } +void stbi_hdr_to_ldr_scale(float scale) { h2l_scale_i = 1/scale; } + +void stbi_ldr_to_hdr_gamma(float gamma) { l2h_gamma = gamma; } +void stbi_ldr_to_hdr_scale(float scale) { l2h_scale = scale; } +#endif + + +////////////////////////////////////////////////////////////////////////////// +// +// Common code used by all image loaders +// + +enum +{ + SCAN_load=0, + SCAN_type, + SCAN_header +}; + +static void refill_buffer(stbi *s) +{ + int n = (s->io.read)(s->io_user_data,(char*)s->buffer_start,s->buflen); + if (n == 0) { + // at end of file, treat same as if from memory + s->read_from_callbacks = 0; + s->img_buffer = s->img_buffer_end-1; + *s->img_buffer = 0; + } else { + s->img_buffer = s->buffer_start; + s->img_buffer_end = s->buffer_start + n; + } +} + +stbi_inline static int get8(stbi *s) +{ + if (s->img_buffer < s->img_buffer_end) + return *s->img_buffer++; + if (s->read_from_callbacks) { + refill_buffer(s); + return *s->img_buffer++; + } + return 0; +} + +stbi_inline static int at_eof(stbi *s) +{ + if (s->io.read) { + if (!(s->io.eof)(s->io_user_data)) return 0; + // if feof() is true, check if buffer = end + // special case: we've only got the special 0 character at the end + if (s->read_from_callbacks == 0) return 1; + } + + return s->img_buffer >= s->img_buffer_end; +} + +stbi_inline static uint8 get8u(stbi *s) +{ + return (uint8) get8(s); +} + +static void skip(stbi *s, int n) +{ + if (s->io.read) { + int blen = s->img_buffer_end - s->img_buffer; + if (blen < n) { + s->img_buffer = s->img_buffer_end; + (s->io.skip)(s->io_user_data, n - blen); + return; + } + } + s->img_buffer += n; +} + +static int getn(stbi *s, stbi_uc *buffer, int n) +{ + if (s->io.read) { + int blen = s->img_buffer_end - s->img_buffer; + if (blen < n) { + int res, count; + + memcpy(buffer, s->img_buffer, blen); + + count = (s->io.read)(s->io_user_data, (char*) buffer + blen, n - blen); + res = (count == (n-blen)); + s->img_buffer = s->img_buffer_end; + return res; + } + } + + if (s->img_buffer+n <= s->img_buffer_end) { + memcpy(buffer, s->img_buffer, n); + s->img_buffer += n; + return 1; + } else + return 0; +} + +static int get16(stbi *s) +{ + int z = get8(s); + return (z << 8) + get8(s); +} + +static uint32 get32(stbi *s) +{ + uint32 z = get16(s); + return (z << 16) + get16(s); +} + +static int get16le(stbi *s) +{ + int z = get8(s); + return z + (get8(s) << 8); +} + +static uint32 get32le(stbi *s) +{ + uint32 z = get16le(s); + return z + (get16le(s) << 16); +} + +////////////////////////////////////////////////////////////////////////////// +// +// generic converter from built-in img_n to req_comp +// individual types do this automatically as much as possible (e.g. jpeg +// does all cases internally since it needs to colorspace convert anyway, +// and it never has alpha, so very few cases ). png can automatically +// interleave an alpha=255 channel, but falls back to this for other cases +// +// assume data buffer is malloced, so malloc a new one and free that one +// only failure mode is malloc failing + +static uint8 compute_y(int r, int g, int b) +{ + return (uint8) (((r*77) + (g*150) + (29*b)) >> 8); +} + +static unsigned char *convert_format(unsigned char *data, int img_n, int req_comp, uint x, uint y) +{ + int i,j; + unsigned char *good; + + if (req_comp == img_n) return data; + assert(req_comp >= 1 && req_comp <= 4); + + good = (unsigned char *) malloc(req_comp * x * y); + if (good == NULL) { + free(data); + return epuc("outofmem", "Out of memory"); + } + + for (j=0; j < (int) y; ++j) { + unsigned char *src = data + j * x * img_n ; + unsigned char *dest = good + j * x * req_comp; + + #define COMBO(a,b) ((a)*8+(b)) + #define CASE(a,b) case COMBO(a,b): for(i=x-1; i >= 0; --i, src += a, dest += b) + // convert source image with img_n components to one with req_comp components; + // avoid switch per pixel, so use switch per scanline and massive macros + switch (COMBO(img_n, req_comp)) { + CASE(1,2) dest[0]=src[0], dest[1]=255; break; + CASE(1,3) dest[0]=dest[1]=dest[2]=src[0]; break; + CASE(1,4) dest[0]=dest[1]=dest[2]=src[0], dest[3]=255; break; + CASE(2,1) dest[0]=src[0]; break; + CASE(2,3) dest[0]=dest[1]=dest[2]=src[0]; break; + CASE(2,4) dest[0]=dest[1]=dest[2]=src[0], dest[3]=src[1]; break; + CASE(3,4) dest[0]=src[0],dest[1]=src[1],dest[2]=src[2],dest[3]=255; break; + CASE(3,1) dest[0]=compute_y(src[0],src[1],src[2]); break; + CASE(3,2) dest[0]=compute_y(src[0],src[1],src[2]), dest[1] = 255; break; + CASE(4,1) dest[0]=compute_y(src[0],src[1],src[2]); break; + CASE(4,2) dest[0]=compute_y(src[0],src[1],src[2]), dest[1] = src[3]; break; + CASE(4,3) dest[0]=src[0],dest[1]=src[1],dest[2]=src[2]; break; + default: assert(0); + } + #undef CASE + } + + free(data); + return good; +} + +#ifndef STBI_NO_HDR +static float *ldr_to_hdr(stbi_uc *data, int x, int y, int comp) +{ + int i,k,n; + float *output = (float *) malloc(x * y * comp * sizeof(float)); + if (output == NULL) { free(data); return epf("outofmem", "Out of memory"); } + // compute number of non-alpha components + if (comp & 1) n = comp; else n = comp-1; + for (i=0; i < x*y; ++i) { + for (k=0; k < n; ++k) { + output[i*comp + k] = (float) pow(data[i*comp+k]/255.0f, l2h_gamma) * l2h_scale; + } + if (k < comp) output[i*comp + k] = data[i*comp+k]/255.0f; + } + free(data); + return output; +} + +#define float2int(x) ((int) (x)) +static stbi_uc *hdr_to_ldr(float *data, int x, int y, int comp) +{ + int i,k,n; + stbi_uc *output = (stbi_uc *) malloc(x * y * comp); + if (output == NULL) { free(data); return epuc("outofmem", "Out of memory"); } + // compute number of non-alpha components + if (comp & 1) n = comp; else n = comp-1; + for (i=0; i < x*y; ++i) { + for (k=0; k < n; ++k) { + float z = (float) pow(data[i*comp+k]*h2l_scale_i, h2l_gamma_i) * 255 + 0.5f; + if (z < 0) z = 0; + if (z > 255) z = 255; + output[i*comp + k] = (uint8) float2int(z); + } + if (k < comp) { + float z = data[i*comp+k] * 255 + 0.5f; + if (z < 0) z = 0; + if (z > 255) z = 255; + output[i*comp + k] = (uint8) float2int(z); + } + } + free(data); + return output; +} +#endif + +////////////////////////////////////////////////////////////////////////////// +// +// "baseline" JPEG/JFIF decoder (not actually fully baseline implementation) +// +// simple implementation +// - channel subsampling of at most 2 in each dimension +// - doesn't support delayed output of y-dimension +// - simple interface (only one output format: 8-bit interleaved RGB) +// - doesn't try to recover corrupt jpegs +// - doesn't allow partial loading, loading multiple at once +// - still fast on x86 (copying globals into locals doesn't help x86) +// - allocates lots of intermediate memory (full size of all components) +// - non-interleaved case requires this anyway +// - allows good upsampling (see next) +// high-quality +// - upsampled channels are bilinearly interpolated, even across blocks +// - quality integer IDCT derived from IJG's 'slow' +// performance +// - fast huffman; reasonable integer IDCT +// - uses a lot of intermediate memory, could cache poorly +// - load http://nothings.org/remote/anemones.jpg 3 times on 2.8Ghz P4 +// stb_jpeg: 1.34 seconds (MSVC6, default release build) +// stb_jpeg: 1.06 seconds (MSVC6, processor = Pentium Pro) +// IJL11.dll: 1.08 seconds (compiled by intel) +// IJG 1998: 0.98 seconds (MSVC6, makefile provided by IJG) +// IJG 1998: 0.95 seconds (MSVC6, makefile + proc=PPro) + +// huffman decoding acceleration +#define FAST_BITS 9 // larger handles more cases; smaller stomps less cache + +typedef struct +{ + uint8 fast[1 << FAST_BITS]; + // weirdly, repacking this into AoS is a 10% speed loss, instead of a win + uint16 code[256]; + uint8 values[256]; + uint8 size[257]; + unsigned int maxcode[18]; + int delta[17]; // old 'firstsymbol' - old 'firstcode' +} huffman; + +typedef struct +{ + #ifdef STBI_SIMD + unsigned short dequant2[4][64]; + #endif + stbi *s; + huffman huff_dc[4]; + huffman huff_ac[4]; + uint8 dequant[4][64]; + +// sizes for components, interleaved MCUs + int img_h_max, img_v_max; + int img_mcu_x, img_mcu_y; + int img_mcu_w, img_mcu_h; + +// definition of jpeg image component + struct + { + int id; + int h,v; + int tq; + int hd,ha; + int dc_pred; + + int x,y,w2,h2; + uint8 *data; + void *raw_data; + uint8 *linebuf; + } img_comp[4]; + + uint32 code_buffer; // jpeg entropy-coded buffer + int code_bits; // number of valid bits + unsigned char marker; // marker seen while filling entropy buffer + int nomore; // flag if we saw a marker so must stop + + int scan_n, order[4]; + int restart_interval, todo; +} jpeg; + +static int build_huffman(huffman *h, int *count) +{ + int i,j,k=0,code; + // build size list for each symbol (from JPEG spec) + for (i=0; i < 16; ++i) + for (j=0; j < count[i]; ++j) + h->size[k++] = (uint8) (i+1); + h->size[k] = 0; + + // compute actual symbols (from jpeg spec) + code = 0; + k = 0; + for(j=1; j <= 16; ++j) { + // compute delta to add to code to compute symbol id + h->delta[j] = k - code; + if (h->size[k] == j) { + while (h->size[k] == j) + h->code[k++] = (uint16) (code++); + if (code-1 >= (1 << j)) return e("bad code lengths","Corrupt JPEG"); + } + // compute largest code + 1 for this size, preshifted as needed later + h->maxcode[j] = code << (16-j); + code <<= 1; + } + h->maxcode[j] = 0xffffffff; + + // build non-spec acceleration table; 255 is flag for not-accelerated + memset(h->fast, 255, 1 << FAST_BITS); + for (i=0; i < k; ++i) { + int s = h->size[i]; + if (s <= FAST_BITS) { + int c = h->code[i] << (FAST_BITS-s); + int m = 1 << (FAST_BITS-s); + for (j=0; j < m; ++j) { + h->fast[c+j] = (uint8) i; + } + } + } + return 1; +} + +static void grow_buffer_unsafe(jpeg *j) +{ + do { + int b = j->nomore ? 0 : get8(j->s); + if (b == 0xff) { + int c = get8(j->s); + if (c != 0) { + j->marker = (unsigned char) c; + j->nomore = 1; + return; + } + } + j->code_buffer |= b << (24 - j->code_bits); + j->code_bits += 8; + } while (j->code_bits <= 24); +} + +// (1 << n) - 1 +static uint32 bmask[17]={0,1,3,7,15,31,63,127,255,511,1023,2047,4095,8191,16383,32767,65535}; + +// decode a jpeg huffman value from the bitstream +stbi_inline static int decode(jpeg *j, huffman *h) +{ + unsigned int temp; + int c,k; + + if (j->code_bits < 16) grow_buffer_unsafe(j); + + // look at the top FAST_BITS and determine what symbol ID it is, + // if the code is <= FAST_BITS + c = (j->code_buffer >> (32 - FAST_BITS)) & ((1 << FAST_BITS)-1); + k = h->fast[c]; + if (k < 255) { + int s = h->size[k]; + if (s > j->code_bits) + return -1; + j->code_buffer <<= s; + j->code_bits -= s; + return h->values[k]; + } + + // naive test is to shift the code_buffer down so k bits are + // valid, then test against maxcode. To speed this up, we've + // preshifted maxcode left so that it has (16-k) 0s at the + // end; in other words, regardless of the number of bits, it + // wants to be compared against something shifted to have 16; + // that way we don't need to shift inside the loop. + temp = j->code_buffer >> 16; + for (k=FAST_BITS+1 ; ; ++k) + if (temp < h->maxcode[k]) + break; + if (k == 17) { + // error! code not found + j->code_bits -= 16; + return -1; + } + + if (k > j->code_bits) + return -1; + + // convert the huffman code to the symbol id + c = ((j->code_buffer >> (32 - k)) & bmask[k]) + h->delta[k]; + assert((((j->code_buffer) >> (32 - h->size[c])) & bmask[h->size[c]]) == h->code[c]); + + // convert the id to a symbol + j->code_bits -= k; + j->code_buffer <<= k; + return h->values[c]; +} + +// combined JPEG 'receive' and JPEG 'extend', since baseline +// always extends everything it receives. +stbi_inline static int extend_receive(jpeg *j, int n) +{ + unsigned int m = 1 << (n-1); + unsigned int k; + if (j->code_bits < n) grow_buffer_unsafe(j); + + #if 1 + k = stbi_lrot(j->code_buffer, n); + j->code_buffer = k & ~bmask[n]; + k &= bmask[n]; + j->code_bits -= n; + #else + k = (j->code_buffer >> (32 - n)) & bmask[n]; + j->code_bits -= n; + j->code_buffer <<= n; + #endif + // the following test is probably a random branch that won't + // predict well. I tried to table accelerate it but failed. + // maybe it's compiling as a conditional move? + if (k < m) + return (-1 << n) + k + 1; + else + return k; +} + +// given a value that's at position X in the zigzag stream, +// where does it appear in the 8x8 matrix coded as row-major? +static uint8 dezigzag[64+15] = +{ + 0, 1, 8, 16, 9, 2, 3, 10, + 17, 24, 32, 25, 18, 11, 4, 5, + 12, 19, 26, 33, 40, 48, 41, 34, + 27, 20, 13, 6, 7, 14, 21, 28, + 35, 42, 49, 56, 57, 50, 43, 36, + 29, 22, 15, 23, 30, 37, 44, 51, + 58, 59, 52, 45, 38, 31, 39, 46, + 53, 60, 61, 54, 47, 55, 62, 63, + // let corrupt input sample past end + 63, 63, 63, 63, 63, 63, 63, 63, + 63, 63, 63, 63, 63, 63, 63 +}; + +// decode one 64-entry block-- +static int decode_block(jpeg *j, short data[64], huffman *hdc, huffman *hac, int b) +{ + int diff,dc,k; + int t = decode(j, hdc); + if (t < 0) return e("bad huffman code","Corrupt JPEG"); + + // 0 all the ac values now so we can do it 32-bits at a time + memset(data,0,64*sizeof(data[0])); + + diff = t ? extend_receive(j, t) : 0; + dc = j->img_comp[b].dc_pred + diff; + j->img_comp[b].dc_pred = dc; + data[0] = (short) dc; + + // decode AC components, see JPEG spec + k = 1; + do { + int r,s; + int rs = decode(j, hac); + if (rs < 0) return e("bad huffman code","Corrupt JPEG"); + s = rs & 15; + r = rs >> 4; + if (s == 0) { + if (rs != 0xf0) break; // end block + k += 16; + } else { + k += r; + // decode into unzigzag'd location + data[dezigzag[k++]] = (short) extend_receive(j,s); + } + } while (k < 64); + return 1; +} + +// take a -128..127 value and clamp it and convert to 0..255 +stbi_inline static uint8 clamp(int x) +{ + // trick to use a single test to catch both cases + if ((unsigned int) x > 255) { + if (x < 0) return 0; + if (x > 255) return 255; + } + return (uint8) x; +} + +#define f2f(x) (int) (((x) * 4096 + 0.5)) +#define fsh(x) ((x) << 12) + +// derived from jidctint -- DCT_ISLOW +#define IDCT_1D(s0,s1,s2,s3,s4,s5,s6,s7) \ + int t0,t1,t2,t3,p1,p2,p3,p4,p5,x0,x1,x2,x3; \ + p2 = s2; \ + p3 = s6; \ + p1 = (p2+p3) * f2f(0.5411961f); \ + t2 = p1 + p3*f2f(-1.847759065f); \ + t3 = p1 + p2*f2f( 0.765366865f); \ + p2 = s0; \ + p3 = s4; \ + t0 = fsh(p2+p3); \ + t1 = fsh(p2-p3); \ + x0 = t0+t3; \ + x3 = t0-t3; \ + x1 = t1+t2; \ + x2 = t1-t2; \ + t0 = s7; \ + t1 = s5; \ + t2 = s3; \ + t3 = s1; \ + p3 = t0+t2; \ + p4 = t1+t3; \ + p1 = t0+t3; \ + p2 = t1+t2; \ + p5 = (p3+p4)*f2f( 1.175875602f); \ + t0 = t0*f2f( 0.298631336f); \ + t1 = t1*f2f( 2.053119869f); \ + t2 = t2*f2f( 3.072711026f); \ + t3 = t3*f2f( 1.501321110f); \ + p1 = p5 + p1*f2f(-0.899976223f); \ + p2 = p5 + p2*f2f(-2.562915447f); \ + p3 = p3*f2f(-1.961570560f); \ + p4 = p4*f2f(-0.390180644f); \ + t3 += p1+p4; \ + t2 += p2+p3; \ + t1 += p2+p4; \ + t0 += p1+p3; + +#ifdef STBI_SIMD +typedef unsigned short stbi_dequantize_t; +#else +typedef uint8 stbi_dequantize_t; +#endif + +// .344 seconds on 3*anemones.jpg +static void idct_block(uint8 *out, int out_stride, short data[64], stbi_dequantize_t *dequantize) +{ + int i,val[64],*v=val; + stbi_dequantize_t *dq = dequantize; + uint8 *o; + short *d = data; + + // columns + for (i=0; i < 8; ++i,++d,++dq, ++v) { + // if all zeroes, shortcut -- this avoids dequantizing 0s and IDCTing + if (d[ 8]==0 && d[16]==0 && d[24]==0 && d[32]==0 + && d[40]==0 && d[48]==0 && d[56]==0) { + // no shortcut 0 seconds + // (1|2|3|4|5|6|7)==0 0 seconds + // all separate -0.047 seconds + // 1 && 2|3 && 4|5 && 6|7: -0.047 seconds + int dcterm = d[0] * dq[0] << 2; + v[0] = v[8] = v[16] = v[24] = v[32] = v[40] = v[48] = v[56] = dcterm; + } else { + IDCT_1D(d[ 0]*dq[ 0],d[ 8]*dq[ 8],d[16]*dq[16],d[24]*dq[24], + d[32]*dq[32],d[40]*dq[40],d[48]*dq[48],d[56]*dq[56]) + // constants scaled things up by 1<<12; let's bring them back + // down, but keep 2 extra bits of precision + x0 += 512; x1 += 512; x2 += 512; x3 += 512; + v[ 0] = (x0+t3) >> 10; + v[56] = (x0-t3) >> 10; + v[ 8] = (x1+t2) >> 10; + v[48] = (x1-t2) >> 10; + v[16] = (x2+t1) >> 10; + v[40] = (x2-t1) >> 10; + v[24] = (x3+t0) >> 10; + v[32] = (x3-t0) >> 10; + } + } + + for (i=0, v=val, o=out; i < 8; ++i,v+=8,o+=out_stride) { + // no fast case since the first 1D IDCT spread components out + IDCT_1D(v[0],v[1],v[2],v[3],v[4],v[5],v[6],v[7]) + // constants scaled things up by 1<<12, plus we had 1<<2 from first + // loop, plus horizontal and vertical each scale by sqrt(8) so together + // we've got an extra 1<<3, so 1<<17 total we need to remove. + // so we want to round that, which means adding 0.5 * 1<<17, + // aka 65536. Also, we'll end up with -128 to 127 that we want + // to encode as 0..255 by adding 128, so we'll add that before the shift + x0 += 65536 + (128<<17); + x1 += 65536 + (128<<17); + x2 += 65536 + (128<<17); + x3 += 65536 + (128<<17); + // tried computing the shifts into temps, or'ing the temps to see + // if any were out of range, but that was slower + o[0] = clamp((x0+t3) >> 17); + o[7] = clamp((x0-t3) >> 17); + o[1] = clamp((x1+t2) >> 17); + o[6] = clamp((x1-t2) >> 17); + o[2] = clamp((x2+t1) >> 17); + o[5] = clamp((x2-t1) >> 17); + o[3] = clamp((x3+t0) >> 17); + o[4] = clamp((x3-t0) >> 17); + } +} + +#ifdef STBI_SIMD +static stbi_idct_8x8 stbi_idct_installed = idct_block; + +void stbi_install_idct(stbi_idct_8x8 func) +{ + stbi_idct_installed = func; +} +#endif + +#define MARKER_none 0xff +// if there's a pending marker from the entropy stream, return that +// otherwise, fetch from the stream and get a marker. if there's no +// marker, return 0xff, which is never a valid marker value +static uint8 get_marker(jpeg *j) +{ + uint8 x; + if (j->marker != MARKER_none) { x = j->marker; j->marker = MARKER_none; return x; } + x = get8u(j->s); + if (x != 0xff) return MARKER_none; + while (x == 0xff) + x = get8u(j->s); + return x; +} + +// in each scan, we'll have scan_n components, and the order +// of the components is specified by order[] +#define RESTART(x) ((x) >= 0xd0 && (x) <= 0xd7) + +// after a restart interval, reset the entropy decoder and +// the dc prediction +static void reset(jpeg *j) +{ + j->code_bits = 0; + j->code_buffer = 0; + j->nomore = 0; + j->img_comp[0].dc_pred = j->img_comp[1].dc_pred = j->img_comp[2].dc_pred = 0; + j->marker = MARKER_none; + j->todo = j->restart_interval ? j->restart_interval : 0x7fffffff; + // no more than 1<<31 MCUs if no restart_interal? that's plenty safe, + // since we don't even allow 1<<30 pixels +} + +static int parse_entropy_coded_data(jpeg *z) +{ + reset(z); + if (z->scan_n == 1) { + int i,j; + #ifdef STBI_SIMD + __declspec(align(16)) + #endif + short data[64]; + int n = z->order[0]; + // non-interleaved data, we just need to process one block at a time, + // in trivial scanline order + // number of blocks to do just depends on how many actual "pixels" this + // component has, independent of interleaved MCU blocking and such + int w = (z->img_comp[n].x+7) >> 3; + int h = (z->img_comp[n].y+7) >> 3; + for (j=0; j < h; ++j) { + for (i=0; i < w; ++i) { + if (!decode_block(z, data, z->huff_dc+z->img_comp[n].hd, z->huff_ac+z->img_comp[n].ha, n)) return 0; + #ifdef STBI_SIMD + stbi_idct_installed(z->img_comp[n].data+z->img_comp[n].w2*j*8+i*8, z->img_comp[n].w2, data, z->dequant2[z->img_comp[n].tq]); + #else + idct_block(z->img_comp[n].data+z->img_comp[n].w2*j*8+i*8, z->img_comp[n].w2, data, z->dequant[z->img_comp[n].tq]); + #endif + // every data block is an MCU, so countdown the restart interval + if (--z->todo <= 0) { + if (z->code_bits < 24) grow_buffer_unsafe(z); + // if it's NOT a restart, then just bail, so we get corrupt data + // rather than no data + if (!RESTART(z->marker)) return 1; + reset(z); + } + } + } + } else { // interleaved! + int i,j,k,x,y; + short data[64]; + for (j=0; j < z->img_mcu_y; ++j) { + for (i=0; i < z->img_mcu_x; ++i) { + // scan an interleaved mcu... process scan_n components in order + for (k=0; k < z->scan_n; ++k) { + int n = z->order[k]; + // scan out an mcu's worth of this component; that's just determined + // by the basic H and V specified for the component + for (y=0; y < z->img_comp[n].v; ++y) { + for (x=0; x < z->img_comp[n].h; ++x) { + int x2 = (i*z->img_comp[n].h + x)*8; + int y2 = (j*z->img_comp[n].v + y)*8; + if (!decode_block(z, data, z->huff_dc+z->img_comp[n].hd, z->huff_ac+z->img_comp[n].ha, n)) return 0; + #ifdef STBI_SIMD + stbi_idct_installed(z->img_comp[n].data+z->img_comp[n].w2*y2+x2, z->img_comp[n].w2, data, z->dequant2[z->img_comp[n].tq]); + #else + idct_block(z->img_comp[n].data+z->img_comp[n].w2*y2+x2, z->img_comp[n].w2, data, z->dequant[z->img_comp[n].tq]); + #endif + } + } + } + // after all interleaved components, that's an interleaved MCU, + // so now count down the restart interval + if (--z->todo <= 0) { + if (z->code_bits < 24) grow_buffer_unsafe(z); + // if it's NOT a restart, then just bail, so we get corrupt data + // rather than no data + if (!RESTART(z->marker)) return 1; + reset(z); + } + } + } + } + return 1; +} + +static int process_marker(jpeg *z, int m) +{ + int L; + switch (m) { + case MARKER_none: // no marker found + return e("expected marker","Corrupt JPEG"); + + case 0xC2: // SOF - progressive + return e("progressive jpeg","JPEG format not supported (progressive)"); + + case 0xDD: // DRI - specify restart interval + if (get16(z->s) != 4) return e("bad DRI len","Corrupt JPEG"); + z->restart_interval = get16(z->s); + return 1; + + case 0xDB: // DQT - define quantization table + L = get16(z->s)-2; + while (L > 0) { + int q = get8(z->s); + int p = q >> 4; + int t = q & 15,i; + if (p != 0) return e("bad DQT type","Corrupt JPEG"); + if (t > 3) return e("bad DQT table","Corrupt JPEG"); + for (i=0; i < 64; ++i) + z->dequant[t][dezigzag[i]] = get8u(z->s); + #ifdef STBI_SIMD + for (i=0; i < 64; ++i) + z->dequant2[t][i] = z->dequant[t][i]; + #endif + L -= 65; + } + return L==0; + + case 0xC4: // DHT - define huffman table + L = get16(z->s)-2; + while (L > 0) { + uint8 *v; + int sizes[16],i,m=0; + int q = get8(z->s); + int tc = q >> 4; + int th = q & 15; + if (tc > 1 || th > 3) return e("bad DHT header","Corrupt JPEG"); + for (i=0; i < 16; ++i) { + sizes[i] = get8(z->s); + m += sizes[i]; + } + L -= 17; + if (tc == 0) { + if (!build_huffman(z->huff_dc+th, sizes)) return 0; + v = z->huff_dc[th].values; + } else { + if (!build_huffman(z->huff_ac+th, sizes)) return 0; + v = z->huff_ac[th].values; + } + for (i=0; i < m; ++i) + v[i] = get8u(z->s); + L -= m; + } + return L==0; + } + // check for comment block or APP blocks + if ((m >= 0xE0 && m <= 0xEF) || m == 0xFE) { + skip(z->s, get16(z->s)-2); + return 1; + } + return 0; +} + +// after we see SOS +static int process_scan_header(jpeg *z) +{ + int i; + int Ls = get16(z->s); + z->scan_n = get8(z->s); + if (z->scan_n < 1 || z->scan_n > 4 || z->scan_n > (int) z->s->img_n) return e("bad SOS component count","Corrupt JPEG"); + if (Ls != 6+2*z->scan_n) return e("bad SOS len","Corrupt JPEG"); + for (i=0; i < z->scan_n; ++i) { + int id = get8(z->s), which; + int q = get8(z->s); + for (which = 0; which < z->s->img_n; ++which) + if (z->img_comp[which].id == id) + break; + if (which == z->s->img_n) return 0; + z->img_comp[which].hd = q >> 4; if (z->img_comp[which].hd > 3) return e("bad DC huff","Corrupt JPEG"); + z->img_comp[which].ha = q & 15; if (z->img_comp[which].ha > 3) return e("bad AC huff","Corrupt JPEG"); + z->order[i] = which; + } + if (get8(z->s) != 0) return e("bad SOS","Corrupt JPEG"); + get8(z->s); // should be 63, but might be 0 + if (get8(z->s) != 0) return e("bad SOS","Corrupt JPEG"); + + return 1; +} + +static int process_frame_header(jpeg *z, int scan) +{ + stbi *s = z->s; + int Lf,p,i,q, h_max=1,v_max=1,c; + Lf = get16(s); if (Lf < 11) return e("bad SOF len","Corrupt JPEG"); // JPEG + p = get8(s); if (p != 8) return e("only 8-bit","JPEG format not supported: 8-bit only"); // JPEG baseline + s->img_y = get16(s); if (s->img_y == 0) return e("no header height", "JPEG format not supported: delayed height"); // Legal, but we don't handle it--but neither does IJG + s->img_x = get16(s); if (s->img_x == 0) return e("0 width","Corrupt JPEG"); // JPEG requires + c = get8(s); + if (c != 3 && c != 1) return e("bad component count","Corrupt JPEG"); // JFIF requires + s->img_n = c; + for (i=0; i < c; ++i) { + z->img_comp[i].data = NULL; + z->img_comp[i].linebuf = NULL; + } + + if (Lf != 8+3*s->img_n) return e("bad SOF len","Corrupt JPEG"); + + for (i=0; i < s->img_n; ++i) { + z->img_comp[i].id = get8(s); + if (z->img_comp[i].id != i+1) // JFIF requires + if (z->img_comp[i].id != i) // some version of jpegtran outputs non-JFIF-compliant files! + return e("bad component ID","Corrupt JPEG"); + q = get8(s); + z->img_comp[i].h = (q >> 4); if (!z->img_comp[i].h || z->img_comp[i].h > 4) return e("bad H","Corrupt JPEG"); + z->img_comp[i].v = q & 15; if (!z->img_comp[i].v || z->img_comp[i].v > 4) return e("bad V","Corrupt JPEG"); + z->img_comp[i].tq = get8(s); if (z->img_comp[i].tq > 3) return e("bad TQ","Corrupt JPEG"); + } + + if (scan != SCAN_load) return 1; + + if ((1 << 30) / s->img_x / s->img_n < s->img_y) return e("too large", "Image too large to decode"); + + for (i=0; i < s->img_n; ++i) { + if (z->img_comp[i].h > h_max) h_max = z->img_comp[i].h; + if (z->img_comp[i].v > v_max) v_max = z->img_comp[i].v; + } + + // compute interleaved mcu info + z->img_h_max = h_max; + z->img_v_max = v_max; + z->img_mcu_w = h_max * 8; + z->img_mcu_h = v_max * 8; + z->img_mcu_x = (s->img_x + z->img_mcu_w-1) / z->img_mcu_w; + z->img_mcu_y = (s->img_y + z->img_mcu_h-1) / z->img_mcu_h; + + for (i=0; i < s->img_n; ++i) { + // number of effective pixels (e.g. for non-interleaved MCU) + z->img_comp[i].x = (s->img_x * z->img_comp[i].h + h_max-1) / h_max; + z->img_comp[i].y = (s->img_y * z->img_comp[i].v + v_max-1) / v_max; + // to simplify generation, we'll allocate enough memory to decode + // the bogus oversized data from using interleaved MCUs and their + // big blocks (e.g. a 16x16 iMCU on an image of width 33); we won't + // discard the extra data until colorspace conversion + z->img_comp[i].w2 = z->img_mcu_x * z->img_comp[i].h * 8; + z->img_comp[i].h2 = z->img_mcu_y * z->img_comp[i].v * 8; + z->img_comp[i].raw_data = malloc(z->img_comp[i].w2 * z->img_comp[i].h2+15); + if (z->img_comp[i].raw_data == NULL) { + for(--i; i >= 0; --i) { + free(z->img_comp[i].raw_data); + z->img_comp[i].data = NULL; + } + return e("outofmem", "Out of memory"); + } + // align blocks for installable-idct using mmx/sse + z->img_comp[i].data = (uint8*) (((size_t) z->img_comp[i].raw_data + 15) & ~15); + z->img_comp[i].linebuf = NULL; + } + + return 1; +} + +// use comparisons since in some cases we handle more than one case (e.g. SOF) +#define DNL(x) ((x) == 0xdc) +#define SOI(x) ((x) == 0xd8) +#define EOI(x) ((x) == 0xd9) +#define SOF(x) ((x) == 0xc0 || (x) == 0xc1) +#define SOS(x) ((x) == 0xda) + +static int decode_jpeg_header(jpeg *z, int scan) +{ + int m; + z->marker = MARKER_none; // initialize cached marker to empty + m = get_marker(z); + if (!SOI(m)) return e("no SOI","Corrupt JPEG"); + if (scan == SCAN_type) return 1; + m = get_marker(z); + while (!SOF(m)) { + if (!process_marker(z,m)) return 0; + m = get_marker(z); + while (m == MARKER_none) { + // some files have extra padding after their blocks, so ok, we'll scan + if (at_eof(z->s)) return e("no SOF", "Corrupt JPEG"); + m = get_marker(z); + } + } + if (!process_frame_header(z, scan)) return 0; + return 1; +} + +static int decode_jpeg_image(jpeg *j) +{ + int m; + j->restart_interval = 0; + if (!decode_jpeg_header(j, SCAN_load)) return 0; + m = get_marker(j); + while (!EOI(m)) { + if (SOS(m)) { + if (!process_scan_header(j)) return 0; + if (!parse_entropy_coded_data(j)) return 0; + if (j->marker == MARKER_none ) { + // handle 0s at the end of image data from IP Kamera 9060 + while (!at_eof(j->s)) { + int x = get8(j->s); + if (x == 255) { + j->marker = get8u(j->s); + break; + } else if (x != 0) { + return 0; + } + } + // if we reach eof without hitting a marker, get_marker() below will fail and we'll eventually return 0 + } + } else { + if (!process_marker(j, m)) return 0; + } + m = get_marker(j); + } + return 1; +} + +// static jfif-centered resampling (across block boundaries) + +typedef uint8 *(*resample_row_func)(uint8 *out, uint8 *in0, uint8 *in1, + int w, int hs); + +#define div4(x) ((uint8) ((x) >> 2)) + +static uint8 *resample_row_1(uint8 *out, uint8 *in_near, uint8 *in_far, int w, int hs) +{ + STBI_NOTUSED(out); + STBI_NOTUSED(in_far); + STBI_NOTUSED(w); + STBI_NOTUSED(hs); + return in_near; +} + +static uint8* resample_row_v_2(uint8 *out, uint8 *in_near, uint8 *in_far, int w, int hs) +{ + // need to generate two samples vertically for every one in input + int i; + STBI_NOTUSED(hs); + for (i=0; i < w; ++i) + out[i] = div4(3*in_near[i] + in_far[i] + 2); + return out; +} + +static uint8* resample_row_h_2(uint8 *out, uint8 *in_near, uint8 *in_far, int w, int hs) +{ + // need to generate two samples horizontally for every one in input + int i; + uint8 *input = in_near; + + if (w == 1) { + // if only one sample, can't do any interpolation + out[0] = out[1] = input[0]; + return out; + } + + out[0] = input[0]; + out[1] = div4(input[0]*3 + input[1] + 2); + for (i=1; i < w-1; ++i) { + int n = 3*input[i]+2; + out[i*2+0] = div4(n+input[i-1]); + out[i*2+1] = div4(n+input[i+1]); + } + out[i*2+0] = div4(input[w-2]*3 + input[w-1] + 2); + out[i*2+1] = input[w-1]; + + STBI_NOTUSED(in_far); + STBI_NOTUSED(hs); + + return out; +} + +#define div16(x) ((uint8) ((x) >> 4)) + +static uint8 *resample_row_hv_2(uint8 *out, uint8 *in_near, uint8 *in_far, int w, int hs) +{ + // need to generate 2x2 samples for every one in input + int i,t0,t1; + if (w == 1) { + out[0] = out[1] = div4(3*in_near[0] + in_far[0] + 2); + return out; + } + + t1 = 3*in_near[0] + in_far[0]; + out[0] = div4(t1+2); + for (i=1; i < w; ++i) { + t0 = t1; + t1 = 3*in_near[i]+in_far[i]; + out[i*2-1] = div16(3*t0 + t1 + 8); + out[i*2 ] = div16(3*t1 + t0 + 8); + } + out[w*2-1] = div4(t1+2); + + STBI_NOTUSED(hs); + + return out; +} + +static uint8 *resample_row_generic(uint8 *out, uint8 *in_near, uint8 *in_far, int w, int hs) +{ + // resample with nearest-neighbor + int i,j; + in_far = in_far; + for (i=0; i < w; ++i) + for (j=0; j < hs; ++j) + out[i*hs+j] = in_near[i]; + return out; +} + +#define float2fixed(x) ((int) ((x) * 65536 + 0.5)) + +// 0.38 seconds on 3*anemones.jpg (0.25 with processor = Pro) +// VC6 without processor=Pro is generating multiple LEAs per multiply! +static void YCbCr_to_RGB_row(uint8 *out, const uint8 *y, const uint8 *pcb, const uint8 *pcr, int count, int step) +{ + int i; + for (i=0; i < count; ++i) { + int y_fixed = (y[i] << 16) + 32768; // rounding + int r,g,b; + int cr = pcr[i] - 128; + int cb = pcb[i] - 128; + r = y_fixed + cr*float2fixed(1.40200f); + g = y_fixed - cr*float2fixed(0.71414f) - cb*float2fixed(0.34414f); + b = y_fixed + cb*float2fixed(1.77200f); + r >>= 16; + g >>= 16; + b >>= 16; + if ((unsigned) r > 255) { if (r < 0) r = 0; else r = 255; } + if ((unsigned) g > 255) { if (g < 0) g = 0; else g = 255; } + if ((unsigned) b > 255) { if (b < 0) b = 0; else b = 255; } + out[0] = (uint8)r; + out[1] = (uint8)g; + out[2] = (uint8)b; + out[3] = 255; + out += step; + } +} + +#ifdef STBI_SIMD +static stbi_YCbCr_to_RGB_run stbi_YCbCr_installed = YCbCr_to_RGB_row; + +void stbi_install_YCbCr_to_RGB(stbi_YCbCr_to_RGB_run func) +{ + stbi_YCbCr_installed = func; +} +#endif + + +// clean up the temporary component buffers +static void cleanup_jpeg(jpeg *j) +{ + int i; + for (i=0; i < j->s->img_n; ++i) { + if (j->img_comp[i].data) { + free(j->img_comp[i].raw_data); + j->img_comp[i].data = NULL; + } + if (j->img_comp[i].linebuf) { + free(j->img_comp[i].linebuf); + j->img_comp[i].linebuf = NULL; + } + } +} + +typedef struct +{ + resample_row_func resample; + uint8 *line0,*line1; + int hs,vs; // expansion factor in each axis + int w_lores; // horizontal pixels pre-expansion + int ystep; // how far through vertical expansion we are + int ypos; // which pre-expansion row we're on +} stbi_resample; + +static uint8 *load_jpeg_image(jpeg *z, int *out_x, int *out_y, int *comp, int req_comp) +{ + int n, decode_n; + // validate req_comp + if (req_comp < 0 || req_comp > 4) return epuc("bad req_comp", "Internal error"); + z->s->img_n = 0; + + // load a jpeg image from whichever source + if (!decode_jpeg_image(z)) { cleanup_jpeg(z); return NULL; } + + // determine actual number of components to generate + n = req_comp ? req_comp : z->s->img_n; + + if (z->s->img_n == 3 && n < 3) + decode_n = 1; + else + decode_n = z->s->img_n; + + // resample and color-convert + { + int k; + uint i,j; + uint8 *output; + uint8 *coutput[4]; + + stbi_resample res_comp[4]; + + for (k=0; k < decode_n; ++k) { + stbi_resample *r = &res_comp[k]; + + // allocate line buffer big enough for upsampling off the edges + // with upsample factor of 4 + z->img_comp[k].linebuf = (uint8 *) malloc(z->s->img_x + 3); + if (!z->img_comp[k].linebuf) { cleanup_jpeg(z); return epuc("outofmem", "Out of memory"); } + + r->hs = z->img_h_max / z->img_comp[k].h; + r->vs = z->img_v_max / z->img_comp[k].v; + r->ystep = r->vs >> 1; + r->w_lores = (z->s->img_x + r->hs-1) / r->hs; + r->ypos = 0; + r->line0 = r->line1 = z->img_comp[k].data; + + if (r->hs == 1 && r->vs == 1) r->resample = resample_row_1; + else if (r->hs == 1 && r->vs == 2) r->resample = resample_row_v_2; + else if (r->hs == 2 && r->vs == 1) r->resample = resample_row_h_2; + else if (r->hs == 2 && r->vs == 2) r->resample = resample_row_hv_2; + else r->resample = resample_row_generic; + } + + // can't error after this so, this is safe + output = (uint8 *) malloc(n * z->s->img_x * z->s->img_y + 1); + if (!output) { cleanup_jpeg(z); return epuc("outofmem", "Out of memory"); } + + // now go ahead and resample + for (j=0; j < z->s->img_y; ++j) { + uint8 *out = output + n * z->s->img_x * j; + for (k=0; k < decode_n; ++k) { + stbi_resample *r = &res_comp[k]; + int y_bot = r->ystep >= (r->vs >> 1); + coutput[k] = r->resample(z->img_comp[k].linebuf, + y_bot ? r->line1 : r->line0, + y_bot ? r->line0 : r->line1, + r->w_lores, r->hs); + if (++r->ystep >= r->vs) { + r->ystep = 0; + r->line0 = r->line1; + if (++r->ypos < z->img_comp[k].y) + r->line1 += z->img_comp[k].w2; + } + } + if (n >= 3) { + uint8 *y = coutput[0]; + if (z->s->img_n == 3) { + #ifdef STBI_SIMD + stbi_YCbCr_installed(out, y, coutput[1], coutput[2], z->s.img_x, n); + #else + YCbCr_to_RGB_row(out, y, coutput[1], coutput[2], z->s->img_x, n); + #endif + } else + for (i=0; i < z->s->img_x; ++i) { + out[0] = out[1] = out[2] = y[i]; + out[3] = 255; // not used if n==3 + out += n; + } + } else { + uint8 *y = coutput[0]; + if (n == 1) + for (i=0; i < z->s->img_x; ++i) out[i] = y[i]; + else + for (i=0; i < z->s->img_x; ++i) *out++ = y[i], *out++ = 255; + } + } + cleanup_jpeg(z); + *out_x = z->s->img_x; + *out_y = z->s->img_y; + if (comp) *comp = z->s->img_n; // report original components, not output + return output; + } +} + +static unsigned char *stbi_jpeg_load(stbi *s, int *x, int *y, int *comp, int req_comp) +{ + jpeg j; + j.s = s; + return load_jpeg_image(&j, x,y,comp,req_comp); +} + +static int stbi_jpeg_test(stbi *s) +{ + int r; + jpeg j; + j.s = s; + r = decode_jpeg_header(&j, SCAN_type); + stbi_rewind(s); + return r; +} + +static int stbi_jpeg_info_raw(jpeg *j, int *x, int *y, int *comp) +{ + if (!decode_jpeg_header(j, SCAN_header)) { + stbi_rewind( j->s ); + return 0; + } + if (x) *x = j->s->img_x; + if (y) *y = j->s->img_y; + if (comp) *comp = j->s->img_n; + return 1; +} + +static int stbi_jpeg_info(stbi *s, int *x, int *y, int *comp) +{ + jpeg j; + j.s = s; + return stbi_jpeg_info_raw(&j, x, y, comp); +} + +// public domain zlib decode v0.2 Sean Barrett 2006-11-18 +// simple implementation +// - all input must be provided in an upfront buffer +// - all output is written to a single output buffer (can malloc/realloc) +// performance +// - fast huffman + +// fast-way is faster to check than jpeg huffman, but slow way is slower +#define ZFAST_BITS 9 // accelerate all cases in default tables +#define ZFAST_MASK ((1 << ZFAST_BITS) - 1) + +// zlib-style huffman encoding +// (jpegs packs from left, zlib from right, so can't share code) +typedef struct +{ + uint16 fast[1 << ZFAST_BITS]; + uint16 firstcode[16]; + int maxcode[17]; + uint16 firstsymbol[16]; + uint8 size[288]; + uint16 value[288]; +} zhuffman; + +stbi_inline static int bitreverse16(int n) +{ + n = ((n & 0xAAAA) >> 1) | ((n & 0x5555) << 1); + n = ((n & 0xCCCC) >> 2) | ((n & 0x3333) << 2); + n = ((n & 0xF0F0) >> 4) | ((n & 0x0F0F) << 4); + n = ((n & 0xFF00) >> 8) | ((n & 0x00FF) << 8); + return n; +} + +stbi_inline static int bit_reverse(int v, int bits) +{ + assert(bits <= 16); + // to bit reverse n bits, reverse 16 and shift + // e.g. 11 bits, bit reverse and shift away 5 + return bitreverse16(v) >> (16-bits); +} + +static int zbuild_huffman(zhuffman *z, uint8 *sizelist, int num) +{ + int i,k=0; + int code, next_code[16], sizes[17]; + + // DEFLATE spec for generating codes + memset(sizes, 0, sizeof(sizes)); + memset(z->fast, 255, sizeof(z->fast)); + for (i=0; i < num; ++i) + ++sizes[sizelist[i]]; + sizes[0] = 0; + for (i=1; i < 16; ++i) + assert(sizes[i] <= (1 << i)); + code = 0; + for (i=1; i < 16; ++i) { + next_code[i] = code; + z->firstcode[i] = (uint16) code; + z->firstsymbol[i] = (uint16) k; + code = (code + sizes[i]); + if (sizes[i]) + if (code-1 >= (1 << i)) return e("bad codelengths","Corrupt JPEG"); + z->maxcode[i] = code << (16-i); // preshift for inner loop + code <<= 1; + k += sizes[i]; + } + z->maxcode[16] = 0x10000; // sentinel + for (i=0; i < num; ++i) { + int s = sizelist[i]; + if (s) { + int c = next_code[s] - z->firstcode[s] + z->firstsymbol[s]; + z->size[c] = (uint8)s; + z->value[c] = (uint16)i; + if (s <= ZFAST_BITS) { + int k = bit_reverse(next_code[s],s); + while (k < (1 << ZFAST_BITS)) { + z->fast[k] = (uint16) c; + k += (1 << s); + } + } + ++next_code[s]; + } + } + return 1; +} + +// zlib-from-memory implementation for PNG reading +// because PNG allows splitting the zlib stream arbitrarily, +// and it's annoying structurally to have PNG call ZLIB call PNG, +// we require PNG read all the IDATs and combine them into a single +// memory buffer + +typedef struct +{ + uint8 *zbuffer, *zbuffer_end; + int num_bits; + uint32 code_buffer; + + char *zout; + char *zout_start; + char *zout_end; + int z_expandable; + + zhuffman z_length, z_distance; +} zbuf; + +stbi_inline static int zget8(zbuf *z) +{ + if (z->zbuffer >= z->zbuffer_end) return 0; + return *z->zbuffer++; +} + +static void fill_bits(zbuf *z) +{ + do { + assert(z->code_buffer < (1U << z->num_bits)); + z->code_buffer |= zget8(z) << z->num_bits; + z->num_bits += 8; + } while (z->num_bits <= 24); +} + +stbi_inline static unsigned int zreceive(zbuf *z, int n) +{ + unsigned int k; + if (z->num_bits < n) fill_bits(z); + k = z->code_buffer & ((1 << n) - 1); + z->code_buffer >>= n; + z->num_bits -= n; + return k; +} + +stbi_inline static int zhuffman_decode(zbuf *a, zhuffman *z) +{ + int b,s,k; + if (a->num_bits < 16) fill_bits(a); + b = z->fast[a->code_buffer & ZFAST_MASK]; + if (b < 0xffff) { + s = z->size[b]; + a->code_buffer >>= s; + a->num_bits -= s; + return z->value[b]; + } + + // not resolved by fast table, so compute it the slow way + // use jpeg approach, which requires MSbits at top + k = bit_reverse(a->code_buffer, 16); + for (s=ZFAST_BITS+1; ; ++s) + if (k < z->maxcode[s]) + break; + if (s == 16) return -1; // invalid code! + // code size is s, so: + b = (k >> (16-s)) - z->firstcode[s] + z->firstsymbol[s]; + assert(z->size[b] == s); + a->code_buffer >>= s; + a->num_bits -= s; + return z->value[b]; +} + +static int expand(zbuf *z, int n) // need to make room for n bytes +{ + char *q; + int cur, limit; + if (!z->z_expandable) return e("output buffer limit","Corrupt PNG"); + cur = (int) (z->zout - z->zout_start); + limit = (int) (z->zout_end - z->zout_start); + while (cur + n > limit) + limit *= 2; + q = (char *) realloc(z->zout_start, limit); + if (q == NULL) return e("outofmem", "Out of memory"); + z->zout_start = q; + z->zout = q + cur; + z->zout_end = q + limit; + return 1; +} + +static int length_base[31] = { + 3,4,5,6,7,8,9,10,11,13, + 15,17,19,23,27,31,35,43,51,59, + 67,83,99,115,131,163,195,227,258,0,0 }; + +static int length_extra[31]= +{ 0,0,0,0,0,0,0,0,1,1,1,1,2,2,2,2,3,3,3,3,4,4,4,4,5,5,5,5,0,0,0 }; + +static int dist_base[32] = { 1,2,3,4,5,7,9,13,17,25,33,49,65,97,129,193, +257,385,513,769,1025,1537,2049,3073,4097,6145,8193,12289,16385,24577,0,0}; + +static int dist_extra[32] = +{ 0,0,0,0,1,1,2,2,3,3,4,4,5,5,6,6,7,7,8,8,9,9,10,10,11,11,12,12,13,13}; + +static int parse_huffman_block(zbuf *a) +{ + for(;;) { + int z = zhuffman_decode(a, &a->z_length); + if (z < 256) { + if (z < 0) return e("bad huffman code","Corrupt PNG"); // error in huffman codes + if (a->zout >= a->zout_end) if (!expand(a, 1)) return 0; + *a->zout++ = (char) z; + } else { + uint8 *p; + int len,dist; + if (z == 256) return 1; + z -= 257; + len = length_base[z]; + if (length_extra[z]) len += zreceive(a, length_extra[z]); + z = zhuffman_decode(a, &a->z_distance); + if (z < 0) return e("bad huffman code","Corrupt PNG"); + dist = dist_base[z]; + if (dist_extra[z]) dist += zreceive(a, dist_extra[z]); + if (a->zout - a->zout_start < dist) return e("bad dist","Corrupt PNG"); + if (a->zout + len > a->zout_end) if (!expand(a, len)) return 0; + p = (uint8 *) (a->zout - dist); + while (len--) + *a->zout++ = *p++; + } + } +} + +static int compute_huffman_codes(zbuf *a) +{ + static uint8 length_dezigzag[19] = { 16,17,18,0,8,7,9,6,10,5,11,4,12,3,13,2,14,1,15 }; + zhuffman z_codelength; + uint8 lencodes[286+32+137];//padding for maximum single op + uint8 codelength_sizes[19]; + int i,n; + + int hlit = zreceive(a,5) + 257; + int hdist = zreceive(a,5) + 1; + int hclen = zreceive(a,4) + 4; + + memset(codelength_sizes, 0, sizeof(codelength_sizes)); + for (i=0; i < hclen; ++i) { + int s = zreceive(a,3); + codelength_sizes[length_dezigzag[i]] = (uint8) s; + } + if (!zbuild_huffman(&z_codelength, codelength_sizes, 19)) return 0; + + n = 0; + while (n < hlit + hdist) { + int c = zhuffman_decode(a, &z_codelength); + assert(c >= 0 && c < 19); + if (c < 16) + lencodes[n++] = (uint8) c; + else if (c == 16) { + c = zreceive(a,2)+3; + memset(lencodes+n, lencodes[n-1], c); + n += c; + } else if (c == 17) { + c = zreceive(a,3)+3; + memset(lencodes+n, 0, c); + n += c; + } else { + assert(c == 18); + c = zreceive(a,7)+11; + memset(lencodes+n, 0, c); + n += c; + } + } + if (n != hlit+hdist) return e("bad codelengths","Corrupt PNG"); + if (!zbuild_huffman(&a->z_length, lencodes, hlit)) return 0; + if (!zbuild_huffman(&a->z_distance, lencodes+hlit, hdist)) return 0; + return 1; +} + +static int parse_uncompressed_block(zbuf *a) +{ + uint8 header[4]; + int len,nlen,k; + if (a->num_bits & 7) + zreceive(a, a->num_bits & 7); // discard + // drain the bit-packed data into header + k = 0; + while (a->num_bits > 0) { + header[k++] = (uint8) (a->code_buffer & 255); // wtf this warns? + a->code_buffer >>= 8; + a->num_bits -= 8; + } + assert(a->num_bits == 0); + // now fill header the normal way + while (k < 4) + header[k++] = (uint8) zget8(a); + len = header[1] * 256 + header[0]; + nlen = header[3] * 256 + header[2]; + if (nlen != (len ^ 0xffff)) return e("zlib corrupt","Corrupt PNG"); + if (a->zbuffer + len > a->zbuffer_end) return e("read past buffer","Corrupt PNG"); + if (a->zout + len > a->zout_end) + if (!expand(a, len)) return 0; + memcpy(a->zout, a->zbuffer, len); + a->zbuffer += len; + a->zout += len; + return 1; +} + +static int parse_zlib_header(zbuf *a) +{ + int cmf = zget8(a); + int cm = cmf & 15; + /* int cinfo = cmf >> 4; */ + int flg = zget8(a); + if ((cmf*256+flg) % 31 != 0) return e("bad zlib header","Corrupt PNG"); // zlib spec + if (flg & 32) return e("no preset dict","Corrupt PNG"); // preset dictionary not allowed in png + if (cm != 8) return e("bad compression","Corrupt PNG"); // DEFLATE required for png + // window = 1 << (8 + cinfo)... but who cares, we fully buffer output + return 1; +} + +// @TODO: should statically initialize these for optimal thread safety +static uint8 default_length[288], default_distance[32]; +static void init_defaults(void) +{ + int i; // use <= to match clearly with spec + for (i=0; i <= 143; ++i) default_length[i] = 8; + for ( ; i <= 255; ++i) default_length[i] = 9; + for ( ; i <= 279; ++i) default_length[i] = 7; + for ( ; i <= 287; ++i) default_length[i] = 8; + + for (i=0; i <= 31; ++i) default_distance[i] = 5; +} + +int stbi_png_partial; // a quick hack to only allow decoding some of a PNG... I should implement real streaming support instead +static int parse_zlib(zbuf *a, int parse_header) +{ + int final, type; + if (parse_header) + if (!parse_zlib_header(a)) return 0; + a->num_bits = 0; + a->code_buffer = 0; + do { + final = zreceive(a,1); + type = zreceive(a,2); + if (type == 0) { + if (!parse_uncompressed_block(a)) return 0; + } else if (type == 3) { + return 0; + } else { + if (type == 1) { + // use fixed code lengths + if (!default_distance[31]) init_defaults(); + if (!zbuild_huffman(&a->z_length , default_length , 288)) return 0; + if (!zbuild_huffman(&a->z_distance, default_distance, 32)) return 0; + } else { + if (!compute_huffman_codes(a)) return 0; + } + if (!parse_huffman_block(a)) return 0; + } + if (stbi_png_partial && a->zout - a->zout_start > 65536) + break; + } while (!final); + return 1; +} + +static int do_zlib(zbuf *a, char *obuf, int olen, int exp, int parse_header) +{ + a->zout_start = obuf; + a->zout = obuf; + a->zout_end = obuf + olen; + a->z_expandable = exp; + + return parse_zlib(a, parse_header); +} + +char *stbi_zlib_decode_malloc_guesssize(const char *buffer, int len, int initial_size, int *outlen) +{ + zbuf a; + char *p = (char *) malloc(initial_size); + if (p == NULL) return NULL; + a.zbuffer = (uint8 *) buffer; + a.zbuffer_end = (uint8 *) buffer + len; + if (do_zlib(&a, p, initial_size, 1, 1)) { + if (outlen) *outlen = (int) (a.zout - a.zout_start); + return a.zout_start; + } else { + free(a.zout_start); + return NULL; + } +} + +char *stbi_zlib_decode_malloc(char const *buffer, int len, int *outlen) +{ + return stbi_zlib_decode_malloc_guesssize(buffer, len, 16384, outlen); +} + +char *stbi_zlib_decode_malloc_guesssize_headerflag(const char *buffer, int len, int initial_size, int *outlen, int parse_header) +{ + zbuf a; + char *p = (char *) malloc(initial_size); + if (p == NULL) return NULL; + a.zbuffer = (uint8 *) buffer; + a.zbuffer_end = (uint8 *) buffer + len; + if (do_zlib(&a, p, initial_size, 1, parse_header)) { + if (outlen) *outlen = (int) (a.zout - a.zout_start); + return a.zout_start; + } else { + free(a.zout_start); + return NULL; + } +} + +int stbi_zlib_decode_buffer(char *obuffer, int olen, char const *ibuffer, int ilen) +{ + zbuf a; + a.zbuffer = (uint8 *) ibuffer; + a.zbuffer_end = (uint8 *) ibuffer + ilen; + if (do_zlib(&a, obuffer, olen, 0, 1)) + return (int) (a.zout - a.zout_start); + else + return -1; +} + +char *stbi_zlib_decode_noheader_malloc(char const *buffer, int len, int *outlen) +{ + zbuf a; + char *p = (char *) malloc(16384); + if (p == NULL) return NULL; + a.zbuffer = (uint8 *) buffer; + a.zbuffer_end = (uint8 *) buffer+len; + if (do_zlib(&a, p, 16384, 1, 0)) { + if (outlen) *outlen = (int) (a.zout - a.zout_start); + return a.zout_start; + } else { + free(a.zout_start); + return NULL; + } +} + +int stbi_zlib_decode_noheader_buffer(char *obuffer, int olen, const char *ibuffer, int ilen) +{ + zbuf a; + a.zbuffer = (uint8 *) ibuffer; + a.zbuffer_end = (uint8 *) ibuffer + ilen; + if (do_zlib(&a, obuffer, olen, 0, 0)) + return (int) (a.zout - a.zout_start); + else + return -1; +} + +// public domain "baseline" PNG decoder v0.10 Sean Barrett 2006-11-18 +// simple implementation +// - only 8-bit samples +// - no CRC checking +// - allocates lots of intermediate memory +// - avoids problem of streaming data between subsystems +// - avoids explicit window management +// performance +// - uses stb_zlib, a PD zlib implementation with fast huffman decoding + + +typedef struct +{ + uint32 length; + uint32 type; +} chunk; + +#define PNG_TYPE(a,b,c,d) (((a) << 24) + ((b) << 16) + ((c) << 8) + (d)) + +static chunk get_chunk_header(stbi *s) +{ + chunk c; + c.length = get32(s); + c.type = get32(s); + return c; +} + +static int check_png_header(stbi *s) +{ + static uint8 png_sig[8] = { 137,80,78,71,13,10,26,10 }; + int i; + for (i=0; i < 8; ++i) + if (get8u(s) != png_sig[i]) return e("bad png sig","Not a PNG"); + return 1; +} + +typedef struct +{ + stbi *s; + uint8 *idata, *expanded, *out; +} png; + + +enum { + F_none=0, F_sub=1, F_up=2, F_avg=3, F_paeth=4, + F_avg_first, F_paeth_first +}; + +static uint8 first_row_filter[5] = +{ + F_none, F_sub, F_none, F_avg_first, F_paeth_first +}; + +static int paeth(int a, int b, int c) +{ + int p = a + b - c; + int pa = abs(p-a); + int pb = abs(p-b); + int pc = abs(p-c); + if (pa <= pb && pa <= pc) return a; + if (pb <= pc) return b; + return c; +} + +// create the png data from post-deflated data +static int create_png_image_raw(png *a, uint8 *raw, uint32 raw_len, int out_n, uint32 x, uint32 y) +{ + stbi *s = a->s; + uint32 i,j,stride = x*out_n; + int k; + int img_n = s->img_n; // copy it into a local for later + assert(out_n == s->img_n || out_n == s->img_n+1); + if (stbi_png_partial) y = 1; + a->out = (uint8 *) malloc(x * y * out_n); + if (!a->out) return e("outofmem", "Out of memory"); + if (!stbi_png_partial) { + if (s->img_x == x && s->img_y == y) { + if (raw_len != (img_n * x + 1) * y) return e("not enough pixels","Corrupt PNG"); + } else { // interlaced: + if (raw_len < (img_n * x + 1) * y) return e("not enough pixels","Corrupt PNG"); + } + } + for (j=0; j < y; ++j) { + uint8 *cur = a->out + stride*j; + uint8 *prior = cur - stride; + int filter = *raw++; + if (filter > 4) return e("invalid filter","Corrupt PNG"); + // if first row, use special filter that doesn't sample previous row + if (j == 0) filter = first_row_filter[filter]; + // handle first pixel explicitly + for (k=0; k < img_n; ++k) { + switch (filter) { + case F_none : cur[k] = raw[k]; break; + case F_sub : cur[k] = raw[k]; break; + case F_up : cur[k] = raw[k] + prior[k]; break; + case F_avg : cur[k] = raw[k] + (prior[k]>>1); break; + case F_paeth : cur[k] = (uint8) (raw[k] + paeth(0,prior[k],0)); break; + case F_avg_first : cur[k] = raw[k]; break; + case F_paeth_first: cur[k] = raw[k]; break; + } + } + if (img_n != out_n) cur[img_n] = 255; + raw += img_n; + cur += out_n; + prior += out_n; + // this is a little gross, so that we don't switch per-pixel or per-component + if (img_n == out_n) { + #define CASE(f) \ + case f: \ + for (i=x-1; i >= 1; --i, raw+=img_n,cur+=img_n,prior+=img_n) \ + for (k=0; k < img_n; ++k) + switch (filter) { + CASE(F_none) cur[k] = raw[k]; break; + CASE(F_sub) cur[k] = raw[k] + cur[k-img_n]; break; + CASE(F_up) cur[k] = raw[k] + prior[k]; break; + CASE(F_avg) cur[k] = raw[k] + ((prior[k] + cur[k-img_n])>>1); break; + CASE(F_paeth) cur[k] = (uint8) (raw[k] + paeth(cur[k-img_n],prior[k],prior[k-img_n])); break; + CASE(F_avg_first) cur[k] = raw[k] + (cur[k-img_n] >> 1); break; + CASE(F_paeth_first) cur[k] = (uint8) (raw[k] + paeth(cur[k-img_n],0,0)); break; + } + #undef CASE + } else { + assert(img_n+1 == out_n); + #define CASE(f) \ + case f: \ + for (i=x-1; i >= 1; --i, cur[img_n]=255,raw+=img_n,cur+=out_n,prior+=out_n) \ + for (k=0; k < img_n; ++k) + switch (filter) { + CASE(F_none) cur[k] = raw[k]; break; + CASE(F_sub) cur[k] = raw[k] + cur[k-out_n]; break; + CASE(F_up) cur[k] = raw[k] + prior[k]; break; + CASE(F_avg) cur[k] = raw[k] + ((prior[k] + cur[k-out_n])>>1); break; + CASE(F_paeth) cur[k] = (uint8) (raw[k] + paeth(cur[k-out_n],prior[k],prior[k-out_n])); break; + CASE(F_avg_first) cur[k] = raw[k] + (cur[k-out_n] >> 1); break; + CASE(F_paeth_first) cur[k] = (uint8) (raw[k] + paeth(cur[k-out_n],0,0)); break; + } + #undef CASE + } + } + return 1; +} + +static int create_png_image(png *a, uint8 *raw, uint32 raw_len, int out_n, int interlaced) +{ + uint8 *final; + int p; + int save; + if (!interlaced) + return create_png_image_raw(a, raw, raw_len, out_n, a->s->img_x, a->s->img_y); + save = stbi_png_partial; + stbi_png_partial = 0; + + // de-interlacing + final = (uint8 *) malloc(a->s->img_x * a->s->img_y * out_n); + for (p=0; p < 7; ++p) { + int xorig[] = { 0,4,0,2,0,1,0 }; + int yorig[] = { 0,0,4,0,2,0,1 }; + int xspc[] = { 8,8,4,4,2,2,1 }; + int yspc[] = { 8,8,8,4,4,2,2 }; + int i,j,x,y; + // pass1_x[4] = 0, pass1_x[5] = 1, pass1_x[12] = 1 + x = (a->s->img_x - xorig[p] + xspc[p]-1) / xspc[p]; + y = (a->s->img_y - yorig[p] + yspc[p]-1) / yspc[p]; + if (x && y) { + if (!create_png_image_raw(a, raw, raw_len, out_n, x, y)) { + free(final); + return 0; + } + for (j=0; j < y; ++j) + for (i=0; i < x; ++i) + memcpy(final + (j*yspc[p]+yorig[p])*a->s->img_x*out_n + (i*xspc[p]+xorig[p])*out_n, + a->out + (j*x+i)*out_n, out_n); + free(a->out); + raw += (x*out_n+1)*y; + raw_len -= (x*out_n+1)*y; + } + } + a->out = final; + + stbi_png_partial = save; + return 1; +} + +static int compute_transparency(png *z, uint8 tc[3], int out_n) +{ + stbi *s = z->s; + uint32 i, pixel_count = s->img_x * s->img_y; + uint8 *p = z->out; + + // compute color-based transparency, assuming we've + // already got 255 as the alpha value in the output + assert(out_n == 2 || out_n == 4); + + if (out_n == 2) { + for (i=0; i < pixel_count; ++i) { + p[1] = (p[0] == tc[0] ? 0 : 255); + p += 2; + } + } else { + for (i=0; i < pixel_count; ++i) { + if (p[0] == tc[0] && p[1] == tc[1] && p[2] == tc[2]) + p[3] = 0; + p += 4; + } + } + return 1; +} + +static int expand_palette(png *a, uint8 *palette, int len, int pal_img_n) +{ + uint32 i, pixel_count = a->s->img_x * a->s->img_y; + uint8 *p, *temp_out, *orig = a->out; + + p = (uint8 *) malloc(pixel_count * pal_img_n); + if (p == NULL) return e("outofmem", "Out of memory"); + + // between here and free(out) below, exitting would leak + temp_out = p; + + if (pal_img_n == 3) { + for (i=0; i < pixel_count; ++i) { + int n = orig[i]*4; + p[0] = palette[n ]; + p[1] = palette[n+1]; + p[2] = palette[n+2]; + p += 3; + } + } else { + for (i=0; i < pixel_count; ++i) { + int n = orig[i]*4; + p[0] = palette[n ]; + p[1] = palette[n+1]; + p[2] = palette[n+2]; + p[3] = palette[n+3]; + p += 4; + } + } + free(a->out); + a->out = temp_out; + + STBI_NOTUSED(len); + + return 1; +} + +static int stbi_unpremultiply_on_load = 0; +static int stbi_de_iphone_flag = 0; + +void stbi_set_unpremultiply_on_load(int flag_true_if_should_unpremultiply) +{ + stbi_unpremultiply_on_load = flag_true_if_should_unpremultiply; +} +void stbi_convert_iphone_png_to_rgb(int flag_true_if_should_convert) +{ + stbi_de_iphone_flag = flag_true_if_should_convert; +} + +static void stbi_de_iphone(png *z) +{ + stbi *s = z->s; + uint32 i, pixel_count = s->img_x * s->img_y; + uint8 *p = z->out; + + if (s->img_out_n == 3) { // convert bgr to rgb + for (i=0; i < pixel_count; ++i) { + uint8 t = p[0]; + p[0] = p[2]; + p[2] = t; + p += 3; + } + } else { + assert(s->img_out_n == 4); + if (stbi_unpremultiply_on_load) { + // convert bgr to rgb and unpremultiply + for (i=0; i < pixel_count; ++i) { + uint8 a = p[3]; + uint8 t = p[0]; + if (a) { + p[0] = p[2] * 255 / a; + p[1] = p[1] * 255 / a; + p[2] = t * 255 / a; + } else { + p[0] = p[2]; + p[2] = t; + } + p += 4; + } + } else { + // convert bgr to rgb + for (i=0; i < pixel_count; ++i) { + uint8 t = p[0]; + p[0] = p[2]; + p[2] = t; + p += 4; + } + } + } +} + +static int parse_png_file(png *z, int scan, int req_comp) +{ + uint8 palette[1024], pal_img_n=0; + uint8 has_trans=0, tc[3]; + uint32 ioff=0, idata_limit=0, i, pal_len=0; + int first=1,k,interlace=0, iphone=0; + stbi *s = z->s; + + z->expanded = NULL; + z->idata = NULL; + z->out = NULL; + + if (!check_png_header(s)) return 0; + + if (scan == SCAN_type) return 1; + + for (;;) { + chunk c = get_chunk_header(s); + switch (c.type) { + case PNG_TYPE('C','g','B','I'): + iphone = stbi_de_iphone_flag; + skip(s, c.length); + break; + case PNG_TYPE('I','H','D','R'): { + int depth,color,comp,filter; + if (!first) return e("multiple IHDR","Corrupt PNG"); + first = 0; + if (c.length != 13) return e("bad IHDR len","Corrupt PNG"); + s->img_x = get32(s); if (s->img_x > (1 << 24)) return e("too large","Very large image (corrupt?)"); + s->img_y = get32(s); if (s->img_y > (1 << 24)) return e("too large","Very large image (corrupt?)"); + depth = get8(s); if (depth != 8) return e("8bit only","PNG not supported: 8-bit only"); + color = get8(s); if (color > 6) return e("bad ctype","Corrupt PNG"); + if (color == 3) pal_img_n = 3; else if (color & 1) return e("bad ctype","Corrupt PNG"); + comp = get8(s); if (comp) return e("bad comp method","Corrupt PNG"); + filter= get8(s); if (filter) return e("bad filter method","Corrupt PNG"); + interlace = get8(s); if (interlace>1) return e("bad interlace method","Corrupt PNG"); + if (!s->img_x || !s->img_y) return e("0-pixel image","Corrupt PNG"); + if (!pal_img_n) { + s->img_n = (color & 2 ? 3 : 1) + (color & 4 ? 1 : 0); + if ((1 << 30) / s->img_x / s->img_n < s->img_y) return e("too large", "Image too large to decode"); + if (scan == SCAN_header) return 1; + } else { + // if paletted, then pal_n is our final components, and + // img_n is # components to decompress/filter. + s->img_n = 1; + if ((1 << 30) / s->img_x / 4 < s->img_y) return e("too large","Corrupt PNG"); + // if SCAN_header, have to scan to see if we have a tRNS + } + break; + } + + case PNG_TYPE('P','L','T','E'): { + if (first) return e("first not IHDR", "Corrupt PNG"); + if (c.length > 256*3) return e("invalid PLTE","Corrupt PNG"); + pal_len = c.length / 3; + if (pal_len * 3 != c.length) return e("invalid PLTE","Corrupt PNG"); + for (i=0; i < pal_len; ++i) { + palette[i*4+0] = get8u(s); + palette[i*4+1] = get8u(s); + palette[i*4+2] = get8u(s); + palette[i*4+3] = 255; + } + break; + } + + case PNG_TYPE('t','R','N','S'): { + if (first) return e("first not IHDR", "Corrupt PNG"); + if (z->idata) return e("tRNS after IDAT","Corrupt PNG"); + if (pal_img_n) { + if (scan == SCAN_header) { s->img_n = 4; return 1; } + if (pal_len == 0) return e("tRNS before PLTE","Corrupt PNG"); + if (c.length > pal_len) return e("bad tRNS len","Corrupt PNG"); + pal_img_n = 4; + for (i=0; i < c.length; ++i) + palette[i*4+3] = get8u(s); + } else { + if (!(s->img_n & 1)) return e("tRNS with alpha","Corrupt PNG"); + if (c.length != (uint32) s->img_n*2) return e("bad tRNS len","Corrupt PNG"); + has_trans = 1; + for (k=0; k < s->img_n; ++k) + tc[k] = (uint8) get16(s); // non 8-bit images will be larger + } + break; + } + + case PNG_TYPE('I','D','A','T'): { + if (first) return e("first not IHDR", "Corrupt PNG"); + if (pal_img_n && !pal_len) return e("no PLTE","Corrupt PNG"); + if (scan == SCAN_header) { s->img_n = pal_img_n; return 1; } + if (ioff + c.length > idata_limit) { + uint8 *p; + if (idata_limit == 0) idata_limit = c.length > 4096 ? c.length : 4096; + while (ioff + c.length > idata_limit) + idata_limit *= 2; + p = (uint8 *) realloc(z->idata, idata_limit); if (p == NULL) return e("outofmem", "Out of memory"); + z->idata = p; + } + if (!getn(s, z->idata+ioff,c.length)) return e("outofdata","Corrupt PNG"); + ioff += c.length; + break; + } + + case PNG_TYPE('I','E','N','D'): { + uint32 raw_len; + if (first) return e("first not IHDR", "Corrupt PNG"); + if (scan != SCAN_load) return 1; + if (z->idata == NULL) return e("no IDAT","Corrupt PNG"); + z->expanded = (uint8 *) stbi_zlib_decode_malloc_guesssize_headerflag((char *) z->idata, ioff, 16384, (int *) &raw_len, !iphone); + if (z->expanded == NULL) return 0; // zlib should set error + free(z->idata); z->idata = NULL; + if ((req_comp == s->img_n+1 && req_comp != 3 && !pal_img_n) || has_trans) + s->img_out_n = s->img_n+1; + else + s->img_out_n = s->img_n; + if (!create_png_image(z, z->expanded, raw_len, s->img_out_n, interlace)) return 0; + if (has_trans) + if (!compute_transparency(z, tc, s->img_out_n)) return 0; + if (iphone && s->img_out_n > 2) + stbi_de_iphone(z); + if (pal_img_n) { + // pal_img_n == 3 or 4 + s->img_n = pal_img_n; // record the actual colors we had + s->img_out_n = pal_img_n; + if (req_comp >= 3) s->img_out_n = req_comp; + if (!expand_palette(z, palette, pal_len, s->img_out_n)) + return 0; + } + free(z->expanded); z->expanded = NULL; + return 1; + } + + default: + // if critical, fail + if (first) return e("first not IHDR", "Corrupt PNG"); + if ((c.type & (1 << 29)) == 0) { + #ifndef STBI_NO_FAILURE_STRINGS + // not threadsafe + static char invalid_chunk[] = "XXXX chunk not known"; + invalid_chunk[0] = (uint8) (c.type >> 24); + invalid_chunk[1] = (uint8) (c.type >> 16); + invalid_chunk[2] = (uint8) (c.type >> 8); + invalid_chunk[3] = (uint8) (c.type >> 0); + #endif + return e(invalid_chunk, "PNG not supported: unknown chunk type"); + } + skip(s, c.length); + break; + } + // end of chunk, read and skip CRC + get32(s); + } +} + +static unsigned char *do_png(png *p, int *x, int *y, int *n, int req_comp) +{ + unsigned char *result=NULL; + if (req_comp < 0 || req_comp > 4) return epuc("bad req_comp", "Internal error"); + if (parse_png_file(p, SCAN_load, req_comp)) { + result = p->out; + p->out = NULL; + if (req_comp && req_comp != p->s->img_out_n) { + result = convert_format(result, p->s->img_out_n, req_comp, p->s->img_x, p->s->img_y); + p->s->img_out_n = req_comp; + if (result == NULL) return result; + } + *x = p->s->img_x; + *y = p->s->img_y; + if (n) *n = p->s->img_n; + } + free(p->out); p->out = NULL; + free(p->expanded); p->expanded = NULL; + free(p->idata); p->idata = NULL; + + return result; +} + +static unsigned char *stbi_png_load(stbi *s, int *x, int *y, int *comp, int req_comp) +{ + png p; + p.s = s; + return do_png(&p, x,y,comp,req_comp); +} + +static int stbi_png_test(stbi *s) +{ + int r; + r = check_png_header(s); + stbi_rewind(s); + return r; +} + +static int stbi_png_info_raw(png *p, int *x, int *y, int *comp) +{ + if (!parse_png_file(p, SCAN_header, 0)) { + stbi_rewind( p->s ); + return 0; + } + if (x) *x = p->s->img_x; + if (y) *y = p->s->img_y; + if (comp) *comp = p->s->img_n; + return 1; +} + +static int stbi_png_info(stbi *s, int *x, int *y, int *comp) +{ + png p; + p.s = s; + return stbi_png_info_raw(&p, x, y, comp); +} + +// Microsoft/Windows BMP image + +static int bmp_test(stbi *s) +{ + int sz; + if (get8(s) != 'B') return 0; + if (get8(s) != 'M') return 0; + get32le(s); // discard filesize + get16le(s); // discard reserved + get16le(s); // discard reserved + get32le(s); // discard data offset + sz = get32le(s); + if (sz == 12 || sz == 40 || sz == 56 || sz == 108) return 1; + return 0; +} + +static int stbi_bmp_test(stbi *s) +{ + int r = bmp_test(s); + stbi_rewind(s); + return r; +} + + +// returns 0..31 for the highest set bit +static int high_bit(unsigned int z) +{ + int n=0; + if (z == 0) return -1; + if (z >= 0x10000) n += 16, z >>= 16; + if (z >= 0x00100) n += 8, z >>= 8; + if (z >= 0x00010) n += 4, z >>= 4; + if (z >= 0x00004) n += 2, z >>= 2; + if (z >= 0x00002) n += 1, z >>= 1; + return n; +} + +static int bitcount(unsigned int a) +{ + a = (a & 0x55555555) + ((a >> 1) & 0x55555555); // max 2 + a = (a & 0x33333333) + ((a >> 2) & 0x33333333); // max 4 + a = (a + (a >> 4)) & 0x0f0f0f0f; // max 8 per 4, now 8 bits + a = (a + (a >> 8)); // max 16 per 8 bits + a = (a + (a >> 16)); // max 32 per 8 bits + return a & 0xff; +} + +static int shiftsigned(int v, int shift, int bits) +{ + int result; + int z=0; + + if (shift < 0) v <<= -shift; + else v >>= shift; + result = v; + + z = bits; + while (z < 8) { + result += v >> z; + z += bits; + } + return result; +} + +static stbi_uc *bmp_load(stbi *s, int *x, int *y, int *comp, int req_comp) +{ + uint8 *out; + unsigned int mr=0,mg=0,mb=0,ma=0, fake_a=0; + stbi_uc pal[256][4]; + int psize=0,i,j,compress=0,width; + int bpp, flip_vertically, pad, target, offset, hsz; + if (get8(s) != 'B' || get8(s) != 'M') return epuc("not BMP", "Corrupt BMP"); + get32le(s); // discard filesize + get16le(s); // discard reserved + get16le(s); // discard reserved + offset = get32le(s); + hsz = get32le(s); + if (hsz != 12 && hsz != 40 && hsz != 56 && hsz != 108) return epuc("unknown BMP", "BMP type not supported: unknown"); + if (hsz == 12) { + s->img_x = get16le(s); + s->img_y = get16le(s); + } else { + s->img_x = get32le(s); + s->img_y = get32le(s); + } + if (get16le(s) != 1) return epuc("bad BMP", "bad BMP"); + bpp = get16le(s); + if (bpp == 1) return epuc("monochrome", "BMP type not supported: 1-bit"); + flip_vertically = ((int) s->img_y) > 0; + s->img_y = abs((int) s->img_y); + if (hsz == 12) { + if (bpp < 24) + psize = (offset - 14 - 24) / 3; + } else { + compress = get32le(s); + if (compress == 1 || compress == 2) return epuc("BMP RLE", "BMP type not supported: RLE"); + get32le(s); // discard sizeof + get32le(s); // discard hres + get32le(s); // discard vres + get32le(s); // discard colorsused + get32le(s); // discard max important + if (hsz == 40 || hsz == 56) { + if (hsz == 56) { + get32le(s); + get32le(s); + get32le(s); + get32le(s); + } + if (bpp == 16 || bpp == 32) { + mr = mg = mb = 0; + if (compress == 0) { + if (bpp == 32) { + mr = 0xffu << 16; + mg = 0xffu << 8; + mb = 0xffu << 0; + ma = 0xffu << 24; + fake_a = 1; // @TODO: check for cases like alpha value is all 0 and switch it to 255 + } else { + mr = 31u << 10; + mg = 31u << 5; + mb = 31u << 0; + } + } else if (compress == 3) { + mr = get32le(s); + mg = get32le(s); + mb = get32le(s); + // not documented, but generated by photoshop and handled by mspaint + if (mr == mg && mg == mb) { + // ?!?!? + return epuc("bad BMP", "bad BMP"); + } + } else + return epuc("bad BMP", "bad BMP"); + } + } else { + assert(hsz == 108); + mr = get32le(s); + mg = get32le(s); + mb = get32le(s); + ma = get32le(s); + get32le(s); // discard color space + for (i=0; i < 12; ++i) + get32le(s); // discard color space parameters + } + if (bpp < 16) + psize = (offset - 14 - hsz) >> 2; + } + s->img_n = ma ? 4 : 3; + if (req_comp && req_comp >= 3) // we can directly decode 3 or 4 + target = req_comp; + else + target = s->img_n; // if they want monochrome, we'll post-convert + out = (stbi_uc *) malloc(target * s->img_x * s->img_y); + if (!out) return epuc("outofmem", "Out of memory"); + if (bpp < 16) { + int z=0; + if (psize == 0 || psize > 256) { free(out); return epuc("invalid", "Corrupt BMP"); } + for (i=0; i < psize; ++i) { + pal[i][2] = get8u(s); + pal[i][1] = get8u(s); + pal[i][0] = get8u(s); + if (hsz != 12) get8(s); + pal[i][3] = 255; + } + skip(s, offset - 14 - hsz - psize * (hsz == 12 ? 3 : 4)); + if (bpp == 4) width = (s->img_x + 1) >> 1; + else if (bpp == 8) width = s->img_x; + else { free(out); return epuc("bad bpp", "Corrupt BMP"); } + pad = (-width)&3; + for (j=0; j < (int) s->img_y; ++j) { + for (i=0; i < (int) s->img_x; i += 2) { + int v=get8(s),v2=0; + if (bpp == 4) { + v2 = v & 15; + v >>= 4; + } + out[z++] = pal[v][0]; + out[z++] = pal[v][1]; + out[z++] = pal[v][2]; + if (target == 4) out[z++] = 255; + if (i+1 == (int) s->img_x) break; + v = (bpp == 8) ? get8(s) : v2; + out[z++] = pal[v][0]; + out[z++] = pal[v][1]; + out[z++] = pal[v][2]; + if (target == 4) out[z++] = 255; + } + skip(s, pad); + } + } else { + int rshift=0,gshift=0,bshift=0,ashift=0,rcount=0,gcount=0,bcount=0,acount=0; + int z = 0; + int easy=0; + skip(s, offset - 14 - hsz); + if (bpp == 24) width = 3 * s->img_x; + else if (bpp == 16) width = 2*s->img_x; + else /* bpp = 32 and pad = 0 */ width=0; + pad = (-width) & 3; + if (bpp == 24) { + easy = 1; + } else if (bpp == 32) { + if (mb == 0xff && mg == 0xff00 && mr == 0x00ff0000 && ma == 0xff000000) + easy = 2; + } + if (!easy) { + if (!mr || !mg || !mb) { free(out); return epuc("bad masks", "Corrupt BMP"); } + // right shift amt to put high bit in position #7 + rshift = high_bit(mr)-7; rcount = bitcount(mr); + gshift = high_bit(mg)-7; gcount = bitcount(mr); + bshift = high_bit(mb)-7; bcount = bitcount(mr); + ashift = high_bit(ma)-7; acount = bitcount(mr); + } + for (j=0; j < (int) s->img_y; ++j) { + if (easy) { + for (i=0; i < (int) s->img_x; ++i) { + int a; + out[z+2] = get8u(s); + out[z+1] = get8u(s); + out[z+0] = get8u(s); + z += 3; + a = (easy == 2 ? get8(s) : 255); + if (target == 4) out[z++] = (uint8) a; + } + } else { + for (i=0; i < (int) s->img_x; ++i) { + uint32 v = (bpp == 16 ? get16le(s) : get32le(s)); + int a; + out[z++] = (uint8) shiftsigned(v & mr, rshift, rcount); + out[z++] = (uint8) shiftsigned(v & mg, gshift, gcount); + out[z++] = (uint8) shiftsigned(v & mb, bshift, bcount); + a = (ma ? shiftsigned(v & ma, ashift, acount) : 255); + if (target == 4) out[z++] = (uint8) a; + } + } + skip(s, pad); + } + } + if (flip_vertically) { + stbi_uc t; + for (j=0; j < (int) s->img_y>>1; ++j) { + stbi_uc *p1 = out + j *s->img_x*target; + stbi_uc *p2 = out + (s->img_y-1-j)*s->img_x*target; + for (i=0; i < (int) s->img_x*target; ++i) { + t = p1[i], p1[i] = p2[i], p2[i] = t; + } + } + } + + if (req_comp && req_comp != target) { + out = convert_format(out, target, req_comp, s->img_x, s->img_y); + if (out == NULL) return out; // convert_format frees input on failure + } + + *x = s->img_x; + *y = s->img_y; + if (comp) *comp = s->img_n; + return out; +} + +static stbi_uc *stbi_bmp_load(stbi *s,int *x, int *y, int *comp, int req_comp) +{ + return bmp_load(s, x,y,comp,req_comp); +} + + +// Targa Truevision - TGA +// by Jonathan Dummer + +static int tga_info(stbi *s, int *x, int *y, int *comp) +{ + int tga_w, tga_h, tga_comp; + int sz; + get8u(s); // discard Offset + sz = get8u(s); // color type + if( sz > 1 ) { + stbi_rewind(s); + return 0; // only RGB or indexed allowed + } + sz = get8u(s); // image type + // only RGB or grey allowed, +/- RLE + if ((sz != 1) && (sz != 2) && (sz != 3) && (sz != 9) && (sz != 10) && (sz != 11)) return 0; + skip(s,9); + tga_w = get16le(s); + if( tga_w < 1 ) { + stbi_rewind(s); + return 0; // test width + } + tga_h = get16le(s); + if( tga_h < 1 ) { + stbi_rewind(s); + return 0; // test height + } + sz = get8(s); // bits per pixel + // only RGB or RGBA or grey allowed + if ((sz != 8) && (sz != 16) && (sz != 24) && (sz != 32)) { + stbi_rewind(s); + return 0; + } + tga_comp = sz; + if (x) *x = tga_w; + if (y) *y = tga_h; + if (comp) *comp = tga_comp / 8; + return 1; // seems to have passed everything +} + +int stbi_tga_info(stbi *s, int *x, int *y, int *comp) +{ + return tga_info(s, x, y, comp); +} + +static int tga_test(stbi *s) +{ + int sz; + get8u(s); // discard Offset + sz = get8u(s); // color type + if ( sz > 1 ) return 0; // only RGB or indexed allowed + sz = get8u(s); // image type + if ( (sz != 1) && (sz != 2) && (sz != 3) && (sz != 9) && (sz != 10) && (sz != 11) ) return 0; // only RGB or grey allowed, +/- RLE + get16(s); // discard palette start + get16(s); // discard palette length + get8(s); // discard bits per palette color entry + get16(s); // discard x origin + get16(s); // discard y origin + if ( get16(s) < 1 ) return 0; // test width + if ( get16(s) < 1 ) return 0; // test height + sz = get8(s); // bits per pixel + if ( (sz != 8) && (sz != 16) && (sz != 24) && (sz != 32) ) return 0; // only RGB or RGBA or grey allowed + return 1; // seems to have passed everything +} + +static int stbi_tga_test(stbi *s) +{ + int res = tga_test(s); + stbi_rewind(s); + return res; +} + +static stbi_uc *tga_load(stbi *s, int *x, int *y, int *comp, int req_comp) +{ + // read in the TGA header stuff + int tga_offset = get8u(s); + int tga_indexed = get8u(s); + int tga_image_type = get8u(s); + int tga_is_RLE = 0; + int tga_palette_start = get16le(s); + int tga_palette_len = get16le(s); + int tga_palette_bits = get8u(s); + int tga_x_origin = get16le(s); + int tga_y_origin = get16le(s); + int tga_width = get16le(s); + int tga_height = get16le(s); + int tga_bits_per_pixel = get8u(s); + int tga_inverted = get8u(s); + // image data + unsigned char *tga_data; + unsigned char *tga_palette = NULL; + int i, j; + unsigned char raw_data[4]; + unsigned char trans_data[4]; + int RLE_count = 0; + int RLE_repeating = 0; + int read_next_pixel = 1; + + // do a tiny bit of precessing + if ( tga_image_type >= 8 ) + { + tga_image_type -= 8; + tga_is_RLE = 1; + } + /* int tga_alpha_bits = tga_inverted & 15; */ + tga_inverted = 1 - ((tga_inverted >> 5) & 1); + + // error check + if ( //(tga_indexed) || + (tga_width < 1) || (tga_height < 1) || + (tga_image_type < 1) || (tga_image_type > 3) || + ((tga_bits_per_pixel != 8) && (tga_bits_per_pixel != 16) && + (tga_bits_per_pixel != 24) && (tga_bits_per_pixel != 32)) + ) + { + return NULL; // we don't report this as a bad TGA because we don't even know if it's TGA + } + + // If I'm paletted, then I'll use the number of bits from the palette + if ( tga_indexed ) + { + tga_bits_per_pixel = tga_palette_bits; + } + + // tga info + *x = tga_width; + *y = tga_height; + if ( (req_comp < 1) || (req_comp > 4) ) + { + // just use whatever the file was + req_comp = tga_bits_per_pixel / 8; + *comp = req_comp; + } else + { + // force a new number of components + *comp = tga_bits_per_pixel/8; + } + tga_data = (unsigned char*)malloc( tga_width * tga_height * req_comp ); + if (!tga_data) return epuc("outofmem", "Out of memory"); + + // skip to the data's starting position (offset usually = 0) + skip(s, tga_offset ); + // do I need to load a palette? + if ( tga_indexed ) + { + // any data to skip? (offset usually = 0) + skip(s, tga_palette_start ); + // load the palette + tga_palette = (unsigned char*)malloc( tga_palette_len * tga_palette_bits / 8 ); + if (!tga_palette) return epuc("outofmem", "Out of memory"); + if (!getn(s, tga_palette, tga_palette_len * tga_palette_bits / 8 )) { + free(tga_data); + free(tga_palette); + return epuc("bad palette", "Corrupt TGA"); + } + } + // load the data + trans_data[0] = trans_data[1] = trans_data[2] = trans_data[3] = 0; + for (i=0; i < tga_width * tga_height; ++i) + { + // if I'm in RLE mode, do I need to get a RLE chunk? + if ( tga_is_RLE ) + { + if ( RLE_count == 0 ) + { + // yep, get the next byte as a RLE command + int RLE_cmd = get8u(s); + RLE_count = 1 + (RLE_cmd & 127); + RLE_repeating = RLE_cmd >> 7; + read_next_pixel = 1; + } else if ( !RLE_repeating ) + { + read_next_pixel = 1; + } + } else + { + read_next_pixel = 1; + } + // OK, if I need to read a pixel, do it now + if ( read_next_pixel ) + { + // load however much data we did have + if ( tga_indexed ) + { + // read in 1 byte, then perform the lookup + int pal_idx = get8u(s); + if ( pal_idx >= tga_palette_len ) + { + // invalid index + pal_idx = 0; + } + pal_idx *= tga_bits_per_pixel / 8; + for (j = 0; j*8 < tga_bits_per_pixel; ++j) + { + raw_data[j] = tga_palette[pal_idx+j]; + } + } else + { + // read in the data raw + for (j = 0; j*8 < tga_bits_per_pixel; ++j) + { + raw_data[j] = get8u(s); + } + } + // convert raw to the intermediate format + switch (tga_bits_per_pixel) + { + case 8: + // Luminous => RGBA + trans_data[0] = raw_data[0]; + trans_data[1] = raw_data[0]; + trans_data[2] = raw_data[0]; + trans_data[3] = 255; + break; + case 16: + // Luminous,Alpha => RGBA + trans_data[0] = raw_data[0]; + trans_data[1] = raw_data[0]; + trans_data[2] = raw_data[0]; + trans_data[3] = raw_data[1]; + break; + case 24: + // BGR => RGBA + trans_data[0] = raw_data[2]; + trans_data[1] = raw_data[1]; + trans_data[2] = raw_data[0]; + trans_data[3] = 255; + break; + case 32: + // BGRA => RGBA + trans_data[0] = raw_data[2]; + trans_data[1] = raw_data[1]; + trans_data[2] = raw_data[0]; + trans_data[3] = raw_data[3]; + break; + } + // clear the reading flag for the next pixel + read_next_pixel = 0; + } // end of reading a pixel + // convert to final format + switch (req_comp) + { + case 1: + // RGBA => Luminance + tga_data[i*req_comp+0] = compute_y(trans_data[0],trans_data[1],trans_data[2]); + break; + case 2: + // RGBA => Luminance,Alpha + tga_data[i*req_comp+0] = compute_y(trans_data[0],trans_data[1],trans_data[2]); + tga_data[i*req_comp+1] = trans_data[3]; + break; + case 3: + // RGBA => RGB + tga_data[i*req_comp+0] = trans_data[0]; + tga_data[i*req_comp+1] = trans_data[1]; + tga_data[i*req_comp+2] = trans_data[2]; + break; + case 4: + // RGBA => RGBA + tga_data[i*req_comp+0] = trans_data[0]; + tga_data[i*req_comp+1] = trans_data[1]; + tga_data[i*req_comp+2] = trans_data[2]; + tga_data[i*req_comp+3] = trans_data[3]; + break; + } + // in case we're in RLE mode, keep counting down + --RLE_count; + } + // do I need to invert the image? + if ( tga_inverted ) + { + for (j = 0; j*2 < tga_height; ++j) + { + int index1 = j * tga_width * req_comp; + int index2 = (tga_height - 1 - j) * tga_width * req_comp; + for (i = tga_width * req_comp; i > 0; --i) + { + unsigned char temp = tga_data[index1]; + tga_data[index1] = tga_data[index2]; + tga_data[index2] = temp; + ++index1; + ++index2; + } + } + } + // clear my palette, if I had one + if ( tga_palette != NULL ) + { + free( tga_palette ); + } + // the things I do to get rid of an error message, and yet keep + // Microsoft's C compilers happy... [8^( + tga_palette_start = tga_palette_len = tga_palette_bits = + tga_x_origin = tga_y_origin = 0; + // OK, done + return tga_data; +} + +static stbi_uc *stbi_tga_load(stbi *s, int *x, int *y, int *comp, int req_comp) +{ + return tga_load(s,x,y,comp,req_comp); +} + + +// ************************************************************************************************* +// Photoshop PSD loader -- PD by Thatcher Ulrich, integration by Nicolas Schulz, tweaked by STB + +static int psd_test(stbi *s) +{ + if (get32(s) != 0x38425053) return 0; // "8BPS" + else return 1; +} + +static int stbi_psd_test(stbi *s) +{ + int r = psd_test(s); + stbi_rewind(s); + return r; +} + +static stbi_uc *psd_load(stbi *s, int *x, int *y, int *comp, int req_comp) +{ + int pixelCount; + int channelCount, compression; + int channel, i, count, len; + int w,h; + uint8 *out; + + // Check identifier + if (get32(s) != 0x38425053) // "8BPS" + return epuc("not PSD", "Corrupt PSD image"); + + // Check file type version. + if (get16(s) != 1) + return epuc("wrong version", "Unsupported version of PSD image"); + + // Skip 6 reserved bytes. + skip(s, 6 ); + + // Read the number of channels (R, G, B, A, etc). + channelCount = get16(s); + if (channelCount < 0 || channelCount > 16) + return epuc("wrong channel count", "Unsupported number of channels in PSD image"); + + // Read the rows and columns of the image. + h = get32(s); + w = get32(s); + + // Make sure the depth is 8 bits. + if (get16(s) != 8) + return epuc("unsupported bit depth", "PSD bit depth is not 8 bit"); + + // Make sure the color mode is RGB. + // Valid options are: + // 0: Bitmap + // 1: Grayscale + // 2: Indexed color + // 3: RGB color + // 4: CMYK color + // 7: Multichannel + // 8: Duotone + // 9: Lab color + if (get16(s) != 3) + return epuc("wrong color format", "PSD is not in RGB color format"); + + // Skip the Mode Data. (It's the palette for indexed color; other info for other modes.) + skip(s,get32(s) ); + + // Skip the image resources. (resolution, pen tool paths, etc) + skip(s, get32(s) ); + + // Skip the reserved data. + skip(s, get32(s) ); + + // Find out if the data is compressed. + // Known values: + // 0: no compression + // 1: RLE compressed + compression = get16(s); + if (compression > 1) + return epuc("bad compression", "PSD has an unknown compression format"); + + // Create the destination image. + out = (stbi_uc *) malloc(4 * w*h); + if (!out) return epuc("outofmem", "Out of memory"); + pixelCount = w*h; + + // Initialize the data to zero. + //memset( out, 0, pixelCount * 4 ); + + // Finally, the image data. + if (compression) { + // RLE as used by .PSD and .TIFF + // Loop until you get the number of unpacked bytes you are expecting: + // Read the next source byte into n. + // If n is between 0 and 127 inclusive, copy the next n+1 bytes literally. + // Else if n is between -127 and -1 inclusive, copy the next byte -n+1 times. + // Else if n is 128, noop. + // Endloop + + // The RLE-compressed data is preceeded by a 2-byte data count for each row in the data, + // which we're going to just skip. + skip(s, h * channelCount * 2 ); + + // Read the RLE data by channel. + for (channel = 0; channel < 4; channel++) { + uint8 *p; + + p = out+channel; + if (channel >= channelCount) { + // Fill this channel with default data. + for (i = 0; i < pixelCount; i++) *p = (channel == 3 ? 255 : 0), p += 4; + } else { + // Read the RLE data. + count = 0; + while (count < pixelCount) { + len = get8(s); + if (len == 128) { + // No-op. + } else if (len < 128) { + // Copy next len+1 bytes literally. + len++; + count += len; + while (len) { + *p = get8u(s); + p += 4; + len--; + } + } else if (len > 128) { + uint8 val; + // Next -len+1 bytes in the dest are replicated from next source byte. + // (Interpret len as a negative 8-bit int.) + len ^= 0x0FF; + len += 2; + val = get8u(s); + count += len; + while (len) { + *p = val; + p += 4; + len--; + } + } + } + } + } + + } else { + // We're at the raw image data. It's each channel in order (Red, Green, Blue, Alpha, ...) + // where each channel consists of an 8-bit value for each pixel in the image. + + // Read the data by channel. + for (channel = 0; channel < 4; channel++) { + uint8 *p; + + p = out + channel; + if (channel > channelCount) { + // Fill this channel with default data. + for (i = 0; i < pixelCount; i++) *p = channel == 3 ? 255 : 0, p += 4; + } else { + // Read the data. + for (i = 0; i < pixelCount; i++) + *p = get8u(s), p += 4; + } + } + } + + if (req_comp && req_comp != 4) { + out = convert_format(out, 4, req_comp, w, h); + if (out == NULL) return out; // convert_format frees input on failure + } + + if (comp) *comp = channelCount; + *y = h; + *x = w; + + return out; +} + +static stbi_uc *stbi_psd_load(stbi *s, int *x, int *y, int *comp, int req_comp) +{ + return psd_load(s,x,y,comp,req_comp); +} + +// ************************************************************************************************* +// Softimage PIC loader +// by Tom Seddon +// +// See http://softimage.wiki.softimage.com/index.php/INFO:_PIC_file_format +// See http://ozviz.wasp.uwa.edu.au/~pbourke/dataformats/softimagepic/ + +static int pic_is4(stbi *s,const char *str) +{ + int i; + for (i=0; i<4; ++i) + if (get8(s) != (stbi_uc)str[i]) + return 0; + + return 1; +} + +static int pic_test(stbi *s) +{ + int i; + + if (!pic_is4(s,"\x53\x80\xF6\x34")) + return 0; + + for(i=0;i<84;++i) + get8(s); + + if (!pic_is4(s,"PICT")) + return 0; + + return 1; +} + +typedef struct +{ + stbi_uc size,type,channel; +} pic_packet_t; + +static stbi_uc *pic_readval(stbi *s, int channel, stbi_uc *dest) +{ + int mask=0x80, i; + + for (i=0; i<4; ++i, mask>>=1) { + if (channel & mask) { + if (at_eof(s)) return epuc("bad file","PIC file too short"); + dest[i]=get8u(s); + } + } + + return dest; +} + +static void pic_copyval(int channel,stbi_uc *dest,const stbi_uc *src) +{ + int mask=0x80,i; + + for (i=0;i<4; ++i, mask>>=1) + if (channel&mask) + dest[i]=src[i]; +} + +static stbi_uc *pic_load2(stbi *s,int width,int height,int *comp, stbi_uc *result) +{ + int act_comp=0,num_packets=0,y,chained; + pic_packet_t packets[10]; + + // this will (should...) cater for even some bizarre stuff like having data + // for the same channel in multiple packets. + do { + pic_packet_t *packet; + + if (num_packets==sizeof(packets)/sizeof(packets[0])) + return epuc("bad format","too many packets"); + + packet = &packets[num_packets++]; + + chained = get8(s); + packet->size = get8u(s); + packet->type = get8u(s); + packet->channel = get8u(s); + + act_comp |= packet->channel; + + if (at_eof(s)) return epuc("bad file","file too short (reading packets)"); + if (packet->size != 8) return epuc("bad format","packet isn't 8bpp"); + } while (chained); + + *comp = (act_comp & 0x10 ? 4 : 3); // has alpha channel? + + for(y=0; ytype) { + default: + return epuc("bad format","packet has bad compression type"); + + case 0: {//uncompressed + int x; + + for(x=0;xchannel,dest)) + return 0; + break; + } + + case 1://Pure RLE + { + int left=width, i; + + while (left>0) { + stbi_uc count,value[4]; + + count=get8u(s); + if (at_eof(s)) return epuc("bad file","file too short (pure read count)"); + + if (count > left) + count = (uint8) left; + + if (!pic_readval(s,packet->channel,value)) return 0; + + for(i=0; ichannel,dest,value); + left -= count; + } + } + break; + + case 2: {//Mixed RLE + int left=width; + while (left>0) { + int count = get8(s), i; + if (at_eof(s)) return epuc("bad file","file too short (mixed read count)"); + + if (count >= 128) { // Repeated + stbi_uc value[4]; + int i; + + if (count==128) + count = get16(s); + else + count -= 127; + if (count > left) + return epuc("bad file","scanline overrun"); + + if (!pic_readval(s,packet->channel,value)) + return 0; + + for(i=0;ichannel,dest,value); + } else { // Raw + ++count; + if (count>left) return epuc("bad file","scanline overrun"); + + for(i=0;ichannel,dest)) + return 0; + } + left-=count; + } + break; + } + } + } + } + + return result; +} + +static stbi_uc *pic_load(stbi *s,int *px,int *py,int *comp,int req_comp) +{ + stbi_uc *result; + int i, x,y; + + for (i=0; i<92; ++i) + get8(s); + + x = get16(s); + y = get16(s); + if (at_eof(s)) return epuc("bad file","file too short (pic header)"); + if ((1 << 28) / x < y) return epuc("too large", "Image too large to decode"); + + get32(s); //skip `ratio' + get16(s); //skip `fields' + get16(s); //skip `pad' + + // intermediate buffer is RGBA + result = (stbi_uc *) malloc(x*y*4); + memset(result, 0xff, x*y*4); + + if (!pic_load2(s,x,y,comp, result)) { + free(result); + result=0; + } + *px = x; + *py = y; + if (req_comp == 0) req_comp = *comp; + result=convert_format(result,4,req_comp,x,y); + + return result; +} + +static int stbi_pic_test(stbi *s) +{ + int r = pic_test(s); + stbi_rewind(s); + return r; +} + +static stbi_uc *stbi_pic_load(stbi *s, int *x, int *y, int *comp, int req_comp) +{ + return pic_load(s,x,y,comp,req_comp); +} + +// ************************************************************************************************* +// GIF loader -- public domain by Jean-Marc Lienher -- simplified/shrunk by stb +typedef struct stbi_gif_lzw_struct { + int16 prefix; + uint8 first; + uint8 suffix; +} stbi_gif_lzw; + +typedef struct stbi_gif_struct +{ + int w,h; + stbi_uc *out; // output buffer (always 4 components) + int flags, bgindex, ratio, transparent, eflags; + uint8 pal[256][4]; + uint8 lpal[256][4]; + stbi_gif_lzw codes[4096]; + uint8 *color_table; + int parse, step; + int lflags; + int start_x, start_y; + int max_x, max_y; + int cur_x, cur_y; + int line_size; +} stbi_gif; + +static int gif_test(stbi *s) +{ + int sz; + if (get8(s) != 'G' || get8(s) != 'I' || get8(s) != 'F' || get8(s) != '8') return 0; + sz = get8(s); + if (sz != '9' && sz != '7') return 0; + if (get8(s) != 'a') return 0; + return 1; +} + +static int stbi_gif_test(stbi *s) +{ + int r = gif_test(s); + stbi_rewind(s); + return r; +} + +static void stbi_gif_parse_colortable(stbi *s, uint8 pal[256][4], int num_entries, int transp) +{ + int i; + for (i=0; i < num_entries; ++i) { + pal[i][2] = get8u(s); + pal[i][1] = get8u(s); + pal[i][0] = get8u(s); + pal[i][3] = transp ? 0 : 255; + } +} + +static int stbi_gif_header(stbi *s, stbi_gif *g, int *comp, int is_info) +{ + uint8 version; + if (get8(s) != 'G' || get8(s) != 'I' || get8(s) != 'F' || get8(s) != '8') + return e("not GIF", "Corrupt GIF"); + + version = get8u(s); + if (version != '7' && version != '9') return e("not GIF", "Corrupt GIF"); + if (get8(s) != 'a') return e("not GIF", "Corrupt GIF"); + + failure_reason = ""; + g->w = get16le(s); + g->h = get16le(s); + g->flags = get8(s); + g->bgindex = get8(s); + g->ratio = get8(s); + g->transparent = -1; + + if (comp != 0) *comp = 4; // can't actually tell whether it's 3 or 4 until we parse the comments + + if (is_info) return 1; + + if (g->flags & 0x80) + stbi_gif_parse_colortable(s,g->pal, 2 << (g->flags & 7), -1); + + return 1; +} + +static int stbi_gif_info_raw(stbi *s, int *x, int *y, int *comp) +{ + stbi_gif g; + if (!stbi_gif_header(s, &g, comp, 1)) { + stbi_rewind( s ); + return 0; + } + if (x) *x = g.w; + if (y) *y = g.h; + return 1; +} + +static void stbi_out_gif_code(stbi_gif *g, uint16 code) +{ + uint8 *p, *c; + + // recurse to decode the prefixes, since the linked-list is backwards, + // and working backwards through an interleaved image would be nasty + if (g->codes[code].prefix >= 0) + stbi_out_gif_code(g, g->codes[code].prefix); + + if (g->cur_y >= g->max_y) return; + + p = &g->out[g->cur_x + g->cur_y]; + c = &g->color_table[g->codes[code].suffix * 4]; + + if (c[3] >= 128) { + p[0] = c[2]; + p[1] = c[1]; + p[2] = c[0]; + p[3] = c[3]; + } + g->cur_x += 4; + + if (g->cur_x >= g->max_x) { + g->cur_x = g->start_x; + g->cur_y += g->step; + + while (g->cur_y >= g->max_y && g->parse > 0) { + g->step = (1 << g->parse) * g->line_size; + g->cur_y = g->start_y + (g->step >> 1); + --g->parse; + } + } +} + +static uint8 *stbi_process_gif_raster(stbi *s, stbi_gif *g) +{ + uint8 lzw_cs; + int32 len, code; + uint32 first; + int32 codesize, codemask, avail, oldcode, bits, valid_bits, clear; + stbi_gif_lzw *p; + + lzw_cs = get8u(s); + clear = 1 << lzw_cs; + first = 1; + codesize = lzw_cs + 1; + codemask = (1 << codesize) - 1; + bits = 0; + valid_bits = 0; + for (code = 0; code < clear; code++) { + g->codes[code].prefix = -1; + g->codes[code].first = (uint8) code; + g->codes[code].suffix = (uint8) code; + } + + // support no starting clear code + avail = clear+2; + oldcode = -1; + + len = 0; + for(;;) { + if (valid_bits < codesize) { + if (len == 0) { + len = get8(s); // start new block + if (len == 0) + return g->out; + } + --len; + bits |= (int32) get8(s) << valid_bits; + valid_bits += 8; + } else { + int32 code = bits & codemask; + bits >>= codesize; + valid_bits -= codesize; + // @OPTIMIZE: is there some way we can accelerate the non-clear path? + if (code == clear) { // clear code + codesize = lzw_cs + 1; + codemask = (1 << codesize) - 1; + avail = clear + 2; + oldcode = -1; + first = 0; + } else if (code == clear + 1) { // end of stream code + skip(s, len); + while ((len = get8(s)) > 0) + skip(s,len); + return g->out; + } else if (code <= avail) { + if (first) return epuc("no clear code", "Corrupt GIF"); + + if (oldcode >= 0) { + p = &g->codes[avail++]; + if (avail > 4096) return epuc("too many codes", "Corrupt GIF"); + p->prefix = (int16) oldcode; + p->first = g->codes[oldcode].first; + p->suffix = (code == avail) ? p->first : g->codes[code].first; + } else if (code == avail) + return epuc("illegal code in raster", "Corrupt GIF"); + + stbi_out_gif_code(g, (uint16) code); + + if ((avail & codemask) == 0 && avail <= 0x0FFF) { + codesize++; + codemask = (1 << codesize) - 1; + } + + oldcode = code; + } else { + return epuc("illegal code in raster", "Corrupt GIF"); + } + } + } +} + +static void stbi_fill_gif_background(stbi_gif *g) +{ + int i; + uint8 *c = g->pal[g->bgindex]; + // @OPTIMIZE: write a dword at a time + for (i = 0; i < g->w * g->h * 4; i += 4) { + uint8 *p = &g->out[i]; + p[0] = c[2]; + p[1] = c[1]; + p[2] = c[0]; + p[3] = c[3]; + } +} + +// this function is designed to support animated gifs, although stb_image doesn't support it +static uint8 *stbi_gif_load_next(stbi *s, stbi_gif *g, int *comp, int req_comp) +{ + int i; + uint8 *old_out = 0; + + if (g->out == 0) { + if (!stbi_gif_header(s, g, comp,0)) return 0; // failure_reason set by stbi_gif_header + g->out = (uint8 *) malloc(4 * g->w * g->h); + if (g->out == 0) return epuc("outofmem", "Out of memory"); + stbi_fill_gif_background(g); + } else { + // animated-gif-only path + if (((g->eflags & 0x1C) >> 2) == 3) { + old_out = g->out; + g->out = (uint8 *) malloc(4 * g->w * g->h); + if (g->out == 0) return epuc("outofmem", "Out of memory"); + memcpy(g->out, old_out, g->w*g->h*4); + } + } + + for (;;) { + switch (get8(s)) { + case 0x2C: /* Image Descriptor */ + { + int32 x, y, w, h; + uint8 *o; + + x = get16le(s); + y = get16le(s); + w = get16le(s); + h = get16le(s); + if (((x + w) > (g->w)) || ((y + h) > (g->h))) + return epuc("bad Image Descriptor", "Corrupt GIF"); + + g->line_size = g->w * 4; + g->start_x = x * 4; + g->start_y = y * g->line_size; + g->max_x = g->start_x + w * 4; + g->max_y = g->start_y + h * g->line_size; + g->cur_x = g->start_x; + g->cur_y = g->start_y; + + g->lflags = get8(s); + + if (g->lflags & 0x40) { + g->step = 8 * g->line_size; // first interlaced spacing + g->parse = 3; + } else { + g->step = g->line_size; + g->parse = 0; + } + + if (g->lflags & 0x80) { + stbi_gif_parse_colortable(s,g->lpal, 2 << (g->lflags & 7), g->eflags & 0x01 ? g->transparent : -1); + g->color_table = (uint8 *) g->lpal; + } else if (g->flags & 0x80) { + for (i=0; i < 256; ++i) // @OPTIMIZE: reset only the previous transparent + g->pal[i][3] = 255; + if (g->transparent >= 0 && (g->eflags & 0x01)) + g->pal[g->transparent][3] = 0; + g->color_table = (uint8 *) g->pal; + } else + return epuc("missing color table", "Corrupt GIF"); + + o = stbi_process_gif_raster(s, g); + if (o == NULL) return NULL; + + if (req_comp && req_comp != 4) + o = convert_format(o, 4, req_comp, g->w, g->h); + return o; + } + + case 0x21: // Comment Extension. + { + int len; + if (get8(s) == 0xF9) { // Graphic Control Extension. + len = get8(s); + if (len == 4) { + g->eflags = get8(s); + get16le(s); // delay + g->transparent = get8(s); + } else { + skip(s, len); + break; + } + } + while ((len = get8(s)) != 0) + skip(s, len); + break; + } + + case 0x3B: // gif stream termination code + return (uint8 *) 1; + + default: + return epuc("unknown code", "Corrupt GIF"); + } + } +} + +static stbi_uc *stbi_gif_load(stbi *s, int *x, int *y, int *comp, int req_comp) +{ + uint8 *u = 0; + stbi_gif g={0}; + + u = stbi_gif_load_next(s, &g, comp, req_comp); + if (u == (void *) 1) u = 0; // end of animated gif marker + if (u) { + *x = g.w; + *y = g.h; + } + + return u; +} + +static int stbi_gif_info(stbi *s, int *x, int *y, int *comp) +{ + return stbi_gif_info_raw(s,x,y,comp); +} + + +// ************************************************************************************************* +// Radiance RGBE HDR loader +// originally by Nicolas Schulz +#ifndef STBI_NO_HDR +static int hdr_test(stbi *s) +{ + const char *signature = "#?RADIANCE\n"; + int i; + for (i=0; signature[i]; ++i) + if (get8(s) != signature[i]) + return 0; + return 1; +} + +static int stbi_hdr_test(stbi* s) +{ + int r = hdr_test(s); + stbi_rewind(s); + return r; +} + +#define HDR_BUFLEN 1024 +static char *hdr_gettoken(stbi *z, char *buffer) +{ + int len=0; + char c = '\0'; + + c = (char) get8(z); + + while (!at_eof(z) && c != '\n') { + buffer[len++] = c; + if (len == HDR_BUFLEN-1) { + // flush to end of line + while (!at_eof(z) && get8(z) != '\n') + ; + break; + } + c = (char) get8(z); + } + + buffer[len] = 0; + return buffer; +} + +static void hdr_convert(float *output, stbi_uc *input, int req_comp) +{ + if ( input[3] != 0 ) { + float f1; + // Exponent + f1 = (float) ldexp(1.0f, input[3] - (int)(128 + 8)); + if (req_comp <= 2) + output[0] = (input[0] + input[1] + input[2]) * f1 / 3; + else { + output[0] = input[0] * f1; + output[1] = input[1] * f1; + output[2] = input[2] * f1; + } + if (req_comp == 2) output[1] = 1; + if (req_comp == 4) output[3] = 1; + } else { + switch (req_comp) { + case 4: output[3] = 1; /* fallthrough */ + case 3: output[0] = output[1] = output[2] = 0; + break; + case 2: output[1] = 1; /* fallthrough */ + case 1: output[0] = 0; + break; + } + } +} + +static float *hdr_load(stbi *s, int *x, int *y, int *comp, int req_comp) +{ + char buffer[HDR_BUFLEN]; + char *token; + int valid = 0; + int width, height; + stbi_uc *scanline; + float *hdr_data; + int len; + unsigned char count, value; + int i, j, k, c1,c2, z; + + + // Check identifier + if (strcmp(hdr_gettoken(s,buffer), "#?RADIANCE") != 0) + return epf("not HDR", "Corrupt HDR image"); + + // Parse header + for(;;) { + token = hdr_gettoken(s,buffer); + if (token[0] == 0) break; + if (strcmp(token, "FORMAT=32-bit_rle_rgbe") == 0) valid = 1; + } + + if (!valid) return epf("unsupported format", "Unsupported HDR format"); + + // Parse width and height + // can't use sscanf() if we're not using stdio! + token = hdr_gettoken(s,buffer); + if (strncmp(token, "-Y ", 3)) return epf("unsupported data layout", "Unsupported HDR format"); + token += 3; + height = strtol(token, &token, 10); + while (*token == ' ') ++token; + if (strncmp(token, "+X ", 3)) return epf("unsupported data layout", "Unsupported HDR format"); + token += 3; + width = strtol(token, NULL, 10); + + *x = width; + *y = height; + + *comp = 3; + if (req_comp == 0) req_comp = 3; + + // Read data + hdr_data = (float *) malloc(height * width * req_comp * sizeof(float)); + + // Load image data + // image data is stored as some number of sca + if ( width < 8 || width >= 32768) { + // Read flat data + for (j=0; j < height; ++j) { + for (i=0; i < width; ++i) { + stbi_uc rgbe[4]; + main_decode_loop: + getn(s, rgbe, 4); + hdr_convert(hdr_data + j * width * req_comp + i * req_comp, rgbe, req_comp); + } + } + } else { + // Read RLE-encoded data + scanline = NULL; + + for (j = 0; j < height; ++j) { + c1 = get8(s); + c2 = get8(s); + len = get8(s); + if (c1 != 2 || c2 != 2 || (len & 0x80)) { + // not run-length encoded, so we have to actually use THIS data as a decoded + // pixel (note this can't be a valid pixel--one of RGB must be >= 128) + uint8 rgbe[4]; + rgbe[0] = (uint8) c1; + rgbe[1] = (uint8) c2; + rgbe[2] = (uint8) len; + rgbe[3] = (uint8) get8u(s); + hdr_convert(hdr_data, rgbe, req_comp); + i = 1; + j = 0; + free(scanline); + goto main_decode_loop; // yes, this makes no sense + } + len <<= 8; + len |= get8(s); + if (len != width) { free(hdr_data); free(scanline); return epf("invalid decoded scanline length", "corrupt HDR"); } + if (scanline == NULL) scanline = (stbi_uc *) malloc(width * 4); + + for (k = 0; k < 4; ++k) { + i = 0; + while (i < width) { + count = get8u(s); + if (count > 128) { + // Run + value = get8u(s); + count -= 128; + for (z = 0; z < count; ++z) + scanline[i++ * 4 + k] = value; + } else { + // Dump + for (z = 0; z < count; ++z) + scanline[i++ * 4 + k] = get8u(s); + } + } + } + for (i=0; i < width; ++i) + hdr_convert(hdr_data+(j*width + i)*req_comp, scanline + i*4, req_comp); + } + free(scanline); + } + + return hdr_data; +} + +static float *stbi_hdr_load(stbi *s, int *x, int *y, int *comp, int req_comp) +{ + return hdr_load(s,x,y,comp,req_comp); +} + +static int stbi_hdr_info(stbi *s, int *x, int *y, int *comp) +{ + char buffer[HDR_BUFLEN]; + char *token; + int valid = 0; + + if (strcmp(hdr_gettoken(s,buffer), "#?RADIANCE") != 0) { + stbi_rewind( s ); + return 0; + } + + for(;;) { + token = hdr_gettoken(s,buffer); + if (token[0] == 0) break; + if (strcmp(token, "FORMAT=32-bit_rle_rgbe") == 0) valid = 1; + } + + if (!valid) { + stbi_rewind( s ); + return 0; + } + token = hdr_gettoken(s,buffer); + if (strncmp(token, "-Y ", 3)) { + stbi_rewind( s ); + return 0; + } + token += 3; + *y = strtol(token, &token, 10); + while (*token == ' ') ++token; + if (strncmp(token, "+X ", 3)) { + stbi_rewind( s ); + return 0; + } + token += 3; + *x = strtol(token, NULL, 10); + *comp = 3; + return 1; +} +#endif // STBI_NO_HDR + +static int stbi_bmp_info(stbi *s, int *x, int *y, int *comp) +{ + int hsz; + if (get8(s) != 'B' || get8(s) != 'M') { + stbi_rewind( s ); + return 0; + } + skip(s,12); + hsz = get32le(s); + if (hsz != 12 && hsz != 40 && hsz != 56 && hsz != 108) { + stbi_rewind( s ); + return 0; + } + if (hsz == 12) { + *x = get16le(s); + *y = get16le(s); + } else { + *x = get32le(s); + *y = get32le(s); + } + if (get16le(s) != 1) { + stbi_rewind( s ); + return 0; + } + *comp = get16le(s) / 8; + return 1; +} + +static int stbi_psd_info(stbi *s, int *x, int *y, int *comp) +{ + int channelCount; + if (get32(s) != 0x38425053) { + stbi_rewind( s ); + return 0; + } + if (get16(s) != 1) { + stbi_rewind( s ); + return 0; + } + skip(s, 6); + channelCount = get16(s); + if (channelCount < 0 || channelCount > 16) { + stbi_rewind( s ); + return 0; + } + *y = get32(s); + *x = get32(s); + if (get16(s) != 8) { + stbi_rewind( s ); + return 0; + } + if (get16(s) != 3) { + stbi_rewind( s ); + return 0; + } + *comp = 4; + return 1; +} + +static int stbi_pic_info(stbi *s, int *x, int *y, int *comp) +{ + int act_comp=0,num_packets=0,chained; + pic_packet_t packets[10]; + + skip(s, 92); + + *x = get16(s); + *y = get16(s); + if (at_eof(s)) return 0; + if ( (*x) != 0 && (1 << 28) / (*x) < (*y)) { + stbi_rewind( s ); + return 0; + } + + skip(s, 8); + + do { + pic_packet_t *packet; + + if (num_packets==sizeof(packets)/sizeof(packets[0])) + return 0; + + packet = &packets[num_packets++]; + chained = get8(s); + packet->size = get8u(s); + packet->type = get8u(s); + packet->channel = get8u(s); + act_comp |= packet->channel; + + if (at_eof(s)) { + stbi_rewind( s ); + return 0; + } + if (packet->size != 8) { + stbi_rewind( s ); + return 0; + } + } while (chained); + + *comp = (act_comp & 0x10 ? 4 : 3); + + return 1; +} + +static int stbi_info_main(stbi *s, int *x, int *y, int *comp) +{ + if (stbi_jpeg_info(s, x, y, comp)) + return 1; + if (stbi_png_info(s, x, y, comp)) + return 1; + if (stbi_gif_info(s, x, y, comp)) + return 1; + if (stbi_bmp_info(s, x, y, comp)) + return 1; + if (stbi_psd_info(s, x, y, comp)) + return 1; + if (stbi_pic_info(s, x, y, comp)) + return 1; + #ifndef STBI_NO_HDR + if (stbi_hdr_info(s, x, y, comp)) + return 1; + #endif + // test tga last because it's a crappy test! + if (stbi_tga_info(s, x, y, comp)) + return 1; + return e("unknown image type", "Image not of any known type, or corrupt"); +} + +#ifndef STBI_NO_STDIO +int stbi_info(char const *filename, int *x, int *y, int *comp) +{ + FILE *f = fopen(filename, "rb"); + int result; + if (!f) return e("can't fopen", "Unable to open file"); + result = stbi_info_from_file(f, x, y, comp); + fclose(f); + return result; +} + +int stbi_info_from_file(FILE *f, int *x, int *y, int *comp) +{ + int r; + stbi s; + long pos = ftell(f); + start_file(&s, f); + r = stbi_info_main(&s,x,y,comp); + fseek(f,pos,SEEK_SET); + return r; +} +#endif // !STBI_NO_STDIO + +int stbi_info_from_memory(stbi_uc const *buffer, int len, int *x, int *y, int *comp) +{ + stbi s; + start_mem(&s,buffer,len); + return stbi_info_main(&s,x,y,comp); +} + +int stbi_info_from_callbacks(stbi_io_callbacks const *c, void *user, int *x, int *y, int *comp) +{ + stbi s; + start_callbacks(&s, (stbi_io_callbacks *) c, user); + return stbi_info_main(&s,x,y,comp); +} + +#endif // STBI_HEADER_FILE_ONLY + +/* + revision history: + 1.33 (2011-07-14) + make stbi_is_hdr work in STBI_NO_HDR (as specified), minor compiler-friendly improvements + 1.32 (2011-07-13) + support for "info" function for all supported filetypes (SpartanJ) + 1.31 (2011-06-20) + a few more leak fixes, bug in PNG handling (SpartanJ) + 1.30 (2011-06-11) + added ability to load files via callbacks to accomidate custom input streams (Ben Wenger) + removed deprecated format-specific test/load functions + removed support for installable file formats (stbi_loader) -- would have been broken for IO callbacks anyway + error cases in bmp and tga give messages and don't leak (Raymond Barbiero, grisha) + fix inefficiency in decoding 32-bit BMP (David Woo) + 1.29 (2010-08-16) + various warning fixes from Aurelien Pocheville + 1.28 (2010-08-01) + fix bug in GIF palette transparency (SpartanJ) + 1.27 (2010-08-01) + cast-to-uint8 to fix warnings + 1.26 (2010-07-24) + fix bug in file buffering for PNG reported by SpartanJ + 1.25 (2010-07-17) + refix trans_data warning (Won Chun) + 1.24 (2010-07-12) + perf improvements reading from files on platforms with lock-heavy fgetc() + minor perf improvements for jpeg + deprecated type-specific functions so we'll get feedback if they're needed + attempt to fix trans_data warning (Won Chun) + 1.23 fixed bug in iPhone support + 1.22 (2010-07-10) + removed image *writing* support + stbi_info support from Jetro Lauha + GIF support from Jean-Marc Lienher + iPhone PNG-extensions from James Brown + warning-fixes from Nicolas Schulz and Janez Zemva (i.e. Janez (U+017D)emva) + 1.21 fix use of 'uint8' in header (reported by jon blow) + 1.20 added support for Softimage PIC, by Tom Seddon + 1.19 bug in interlaced PNG corruption check (found by ryg) + 1.18 2008-08-02 + fix a threading bug (local mutable static) + 1.17 support interlaced PNG + 1.16 major bugfix - convert_format converted one too many pixels + 1.15 initialize some fields for thread safety + 1.14 fix threadsafe conversion bug + header-file-only version (#define STBI_HEADER_FILE_ONLY before including) + 1.13 threadsafe + 1.12 const qualifiers in the API + 1.11 Support installable IDCT, colorspace conversion routines + 1.10 Fixes for 64-bit (don't use "unsigned long") + optimized upsampling by Fabian "ryg" Giesen + 1.09 Fix format-conversion for PSD code (bad global variables!) + 1.08 Thatcher Ulrich's PSD code integrated by Nicolas Schulz + 1.07 attempt to fix C++ warning/errors again + 1.06 attempt to fix C++ warning/errors again + 1.05 fix TGA loading to return correct *comp and use good luminance calc + 1.04 default float alpha is 1, not 255; use 'void *' for stbi_image_free + 1.03 bugfixes to STBI_NO_STDIO, STBI_NO_HDR + 1.02 support for (subset of) HDR files, float interface for preferred access to them + 1.01 fix bug: possible bug in handling right-side up bmps... not sure + fix bug: the stbi_bmp_load() and stbi_tga_load() functions didn't work at all + 1.00 interface to zlib that skips zlib header + 0.99 correct handling of alpha in palette + 0.98 TGA loader by lonesock; dynamically add loaders (untested) + 0.97 jpeg errors on too large a file; also catch another malloc failure + 0.96 fix detection of invalid v value - particleman@mollyrocket forum + 0.95 during header scan, seek to markers in case of padding + 0.94 STBI_NO_STDIO to disable stdio usage; rename all #defines the same + 0.93 handle jpegtran output; verbose errors + 0.92 read 4,8,16,24,32-bit BMP files of several formats + 0.91 output 24-bit Windows 3.0 BMP files + 0.90 fix a few more warnings; bump version number to approach 1.0 + 0.61 bugfixes due to Marc LeBlanc, Christopher Lloyd + 0.60 fix compiling as c++ + 0.59 fix warnings: merge Dave Moore's -Wall fixes + 0.58 fix bug: zlib uncompressed mode len/nlen was wrong endian + 0.57 fix bug: jpg last huffman symbol before marker was >9 bits but less than 16 available + 0.56 fix bug: zlib uncompressed mode len vs. nlen + 0.55 fix bug: restart_interval not initialized to 0 + 0.54 allow NULL for 'int *comp' + 0.53 fix bug in png 3->4; speedup png decoding + 0.52 png handles req_comp=3,4 directly; minor cleanup; jpeg comments + 0.51 obey req_comp requests, 1-component jpegs return as 1-component, + on 'test' only check type, not whether we support this variant + 0.50 first released version +*/ diff --git a/Demos/OpenGL/stb_image.h b/Demos/OpenGL/stb_image.h new file mode 100644 index 000000000..9df58d601 --- /dev/null +++ b/Demos/OpenGL/stb_image.h @@ -0,0 +1,332 @@ +/* stbi-1.33 - public domain JPEG/PNG reader - http://nothings.org/stb_image.c + when you control the images you're loading + no warranty implied; use at your own risk + + QUICK NOTES: + Primarily of interest to game developers and other people who can + avoid problematic images and only need the trivial interface + + JPEG baseline (no JPEG progressive) + PNG 8-bit only + + TGA (not sure what subset, if a subset) + BMP non-1bpp, non-RLE + PSD (composited view only, no extra channels) + + GIF (*comp always reports as 4-channel) + HDR (radiance rgbE format) + PIC (Softimage PIC) + + - decode from memory or through FILE (define STBI_NO_STDIO to remove code) + - decode from arbitrary I/O callbacks + - overridable dequantizing-IDCT, YCbCr-to-RGB conversion (define STBI_SIMD) + + Latest revisions: + 1.33 (2011-07-14) minor fixes suggested by Dave Moore + 1.32 (2011-07-13) info support for all filetypes (SpartanJ) + 1.31 (2011-06-19) a few more leak fixes, bug in PNG handling (SpartanJ) + 1.30 (2011-06-11) added ability to load files via io callbacks (Ben Wenger) + 1.29 (2010-08-16) various warning fixes from Aurelien Pocheville + 1.28 (2010-08-01) fix bug in GIF palette transparency (SpartanJ) + 1.27 (2010-08-01) cast-to-uint8 to fix warnings (Laurent Gomila) + allow trailing 0s at end of image data (Laurent Gomila) + 1.26 (2010-07-24) fix bug in file buffering for PNG reported by SpartanJ + + See end of file for full revision history. + + TODO: + stbi_info support for BMP,PSD,HDR,PIC + + + ============================ Contributors ========================= + + Image formats Optimizations & bugfixes + Sean Barrett (jpeg, png, bmp) Fabian "ryg" Giesen + Nicolas Schulz (hdr, psd) + Jonathan Dummer (tga) Bug fixes & warning fixes + Jean-Marc Lienher (gif) Marc LeBlanc + Tom Seddon (pic) Christpher Lloyd + Thatcher Ulrich (psd) Dave Moore + Won Chun + the Horde3D community + Extensions, features Janez Zemva + Jetro Lauha (stbi_info) Jonathan Blow + James "moose2000" Brown (iPhone PNG) Laurent Gomila + Ben "Disch" Wenger (io callbacks) Aruelien Pocheville + Martin "SpartanJ" Golini Ryamond Barbiero + David Woo + + + If your name should be here but isn't, let Sean know. + +*/ + +#ifndef STBI_INCLUDE_STB_IMAGE_H +#define STBI_INCLUDE_STB_IMAGE_H + +// To get a header file for this, either cut and paste the header, +// or create stb_image.h, #define STBI_HEADER_FILE_ONLY, and +// then include stb_image.c from it. + +//// begin header file //////////////////////////////////////////////////// +// +// Limitations: +// - no jpeg progressive support +// - non-HDR formats support 8-bit samples only (jpeg, png) +// - no delayed line count (jpeg) -- IJG doesn't support either +// - no 1-bit BMP +// - GIF always returns *comp=4 +// +// Basic usage (see HDR discussion below): +// int x,y,n; +// unsigned char *data = stbi_load(filename, &x, &y, &n, 0); +// // ... process data if not NULL ... +// // ... x = width, y = height, n = # 8-bit components per pixel ... +// // ... replace '0' with '1'..'4' to force that many components per pixel +// // ... but 'n' will always be the number that it would have been if you said 0 +// stbi_image_free(data) +// +// Standard parameters: +// int *x -- outputs image width in pixels +// int *y -- outputs image height in pixels +// int *comp -- outputs # of image components in image file +// int req_comp -- if non-zero, # of image components requested in result +// +// The return value from an image loader is an 'unsigned char *' which points +// to the pixel data. The pixel data consists of *y scanlines of *x pixels, +// with each pixel consisting of N interleaved 8-bit components; the first +// pixel pointed to is top-left-most in the image. There is no padding between +// image scanlines or between pixels, regardless of format. The number of +// components N is 'req_comp' if req_comp is non-zero, or *comp otherwise. +// If req_comp is non-zero, *comp has the number of components that _would_ +// have been output otherwise. E.g. if you set req_comp to 4, you will always +// get RGBA output, but you can check *comp to easily see if it's opaque. +// +// An output image with N components has the following components interleaved +// in this order in each pixel: +// +// N=#comp components +// 1 grey +// 2 grey, alpha +// 3 red, green, blue +// 4 red, green, blue, alpha +// +// If image loading fails for any reason, the return value will be NULL, +// and *x, *y, *comp will be unchanged. The function stbi_failure_reason() +// can be queried for an extremely brief, end-user unfriendly explanation +// of why the load failed. Define STBI_NO_FAILURE_STRINGS to avoid +// compiling these strings at all, and STBI_FAILURE_USERMSG to get slightly +// more user-friendly ones. +// +// Paletted PNG, BMP, GIF, and PIC images are automatically depalettized. +// +// =========================================================================== +// +// iPhone PNG support: +// +// By default we convert iphone-formatted PNGs back to RGB; nominally they +// would silently load as BGR, except the existing code should have just +// failed on such iPhone PNGs. But you can disable this conversion by +// by calling stbi_convert_iphone_png_to_rgb(0), in which case +// you will always just get the native iphone "format" through. +// +// Call stbi_set_unpremultiply_on_load(1) as well to force a divide per +// pixel to remove any premultiplied alpha *only* if the image file explicitly +// says there's premultiplied data (currently only happens in iPhone images, +// and only if iPhone convert-to-rgb processing is on). +// +// =========================================================================== +// +// HDR image support (disable by defining STBI_NO_HDR) +// +// stb_image now supports loading HDR images in general, and currently +// the Radiance .HDR file format, although the support is provided +// generically. You can still load any file through the existing interface; +// if you attempt to load an HDR file, it will be automatically remapped to +// LDR, assuming gamma 2.2 and an arbitrary scale factor defaulting to 1; +// both of these constants can be reconfigured through this interface: +// +// stbi_hdr_to_ldr_gamma(2.2f); +// stbi_hdr_to_ldr_scale(1.0f); +// +// (note, do not use _inverse_ constants; stbi_image will invert them +// appropriately). +// +// Additionally, there is a new, parallel interface for loading files as +// (linear) floats to preserve the full dynamic range: +// +// float *data = stbi_loadf(filename, &x, &y, &n, 0); +// +// If you load LDR images through this interface, those images will +// be promoted to floating point values, run through the inverse of +// constants corresponding to the above: +// +// stbi_ldr_to_hdr_scale(1.0f); +// stbi_ldr_to_hdr_gamma(2.2f); +// +// Finally, given a filename (or an open file or memory block--see header +// file for details) containing image data, you can query for the "most +// appropriate" interface to use (that is, whether the image is HDR or +// not), using: +// +// stbi_is_hdr(char *filename); +// +// =========================================================================== +// +// I/O callbacks +// +// I/O callbacks allow you to read from arbitrary sources, like packaged +// files or some other source. Data read from callbacks are processed +// through a small internal buffer (currently 128 bytes) to try to reduce +// overhead. +// +// The three functions you must define are "read" (reads some bytes of data), +// "skip" (skips some bytes of data), "eof" (reports if the stream is at the end). + + +#ifndef STBI_NO_STDIO + +#if defined(_MSC_VER) && _MSC_VER >= 0x1400 +#define _CRT_SECURE_NO_WARNINGS // suppress bogus warnings about fopen() +#endif + +#include +#endif + +#define STBI_VERSION 1 + +enum +{ + STBI_default = 0, // only used for req_comp + + STBI_grey = 1, + STBI_grey_alpha = 2, + STBI_rgb = 3, + STBI_rgb_alpha = 4 +}; + +typedef unsigned char stbi_uc; + +#ifdef __cplusplus +extern "C" { +#endif + +////////////////////////////////////////////////////////////////////////////// +// +// PRIMARY API - works on images of any type +// + +// +// load image by filename, open file, or memory buffer +// + +extern stbi_uc *stbi_load_from_memory(stbi_uc const *buffer, int len, int *x, int *y, int *comp, int req_comp); + +#ifndef STBI_NO_STDIO +extern stbi_uc *stbi_load (char const *filename, int *x, int *y, int *comp, int req_comp); +extern stbi_uc *stbi_load_from_file (FILE *f, int *x, int *y, int *comp, int req_comp); +// for stbi_load_from_file, file pointer is left pointing immediately after image +#endif + +typedef struct +{ + int (*read) (void *user,char *data,int size); // fill 'data' with 'size' bytes. return number of bytes actually read + void (*skip) (void *user,unsigned n); // skip the next 'n' bytes + int (*eof) (void *user); // returns nonzero if we are at end of file/data +} stbi_io_callbacks; + +extern stbi_uc *stbi_load_from_callbacks (stbi_io_callbacks const *clbk, void *user, int *x, int *y, int *comp, int req_comp); + +#ifndef STBI_NO_HDR + extern float *stbi_loadf_from_memory(stbi_uc const *buffer, int len, int *x, int *y, int *comp, int req_comp); + + #ifndef STBI_NO_STDIO + extern float *stbi_loadf (char const *filename, int *x, int *y, int *comp, int req_comp); + extern float *stbi_loadf_from_file (FILE *f, int *x, int *y, int *comp, int req_comp); + #endif + + extern float *stbi_loadf_from_callbacks (stbi_io_callbacks const *clbk, void *user, int *x, int *y, int *comp, int req_comp); + + extern void stbi_hdr_to_ldr_gamma(float gamma); + extern void stbi_hdr_to_ldr_scale(float scale); + + extern void stbi_ldr_to_hdr_gamma(float gamma); + extern void stbi_ldr_to_hdr_scale(float scale); +#endif // STBI_NO_HDR + +// stbi_is_hdr is always defined +extern int stbi_is_hdr_from_callbacks(stbi_io_callbacks const *clbk, void *user); +extern int stbi_is_hdr_from_memory(stbi_uc const *buffer, int len); +#ifndef STBI_NO_STDIO +extern int stbi_is_hdr (char const *filename); +extern int stbi_is_hdr_from_file(FILE *f); +#endif // STBI_NO_STDIO + + +// get a VERY brief reason for failure +// NOT THREADSAFE +extern const char *stbi_failure_reason (void); + +// free the loaded image -- this is just free() +extern void stbi_image_free (void *retval_from_stbi_load); + +// get image dimensions & components without fully decoding +extern int stbi_info_from_memory(stbi_uc const *buffer, int len, int *x, int *y, int *comp); +extern int stbi_info_from_callbacks(stbi_io_callbacks const *clbk, void *user, int *x, int *y, int *comp); + +#ifndef STBI_NO_STDIO +extern int stbi_info (char const *filename, int *x, int *y, int *comp); +extern int stbi_info_from_file (FILE *f, int *x, int *y, int *comp); + +#endif + + + +// for image formats that explicitly notate that they have premultiplied alpha, +// we just return the colors as stored in the file. set this flag to force +// unpremultiplication. results are undefined if the unpremultiply overflow. +extern void stbi_set_unpremultiply_on_load(int flag_true_if_should_unpremultiply); + +// indicate whether we should process iphone images back to canonical format, +// or just pass them through "as-is" +extern void stbi_convert_iphone_png_to_rgb(int flag_true_if_should_convert); + + +// ZLIB client - used by PNG, available for other purposes + +extern char *stbi_zlib_decode_malloc_guesssize(const char *buffer, int len, int initial_size, int *outlen); +extern char *stbi_zlib_decode_malloc(const char *buffer, int len, int *outlen); +extern int stbi_zlib_decode_buffer(char *obuffer, int olen, const char *ibuffer, int ilen); + +extern char *stbi_zlib_decode_noheader_malloc(const char *buffer, int len, int *outlen); +extern int stbi_zlib_decode_noheader_buffer(char *obuffer, int olen, const char *ibuffer, int ilen); + + +// define faster low-level operations (typically SIMD support) +#ifdef STBI_SIMD +typedef void (*stbi_idct_8x8)(stbi_uc *out, int out_stride, short data[64], unsigned short *dequantize); +// compute an integer IDCT on "input" +// input[x] = data[x] * dequantize[x] +// write results to 'out': 64 samples, each run of 8 spaced by 'out_stride' +// CLAMP results to 0..255 +typedef void (*stbi_YCbCr_to_RGB_run)(stbi_uc *output, stbi_uc const *y, stbi_uc const *cb, stbi_uc const *cr, int count, int step); +// compute a conversion from YCbCr to RGB +// 'count' pixels +// write pixels to 'output'; each pixel is 'step' bytes (either 3 or 4; if 4, write '255' as 4th), order R,G,B +// y: Y input channel +// cb: Cb input channel; scale/biased to be 0..255 +// cr: Cr input channel; scale/biased to be 0..255 + +extern void stbi_install_idct(stbi_idct_8x8 func); +extern void stbi_install_YCbCr_to_RGB(stbi_YCbCr_to_RGB_run func); +#endif // STBI_SIMD + + +#ifdef __cplusplus +} +#endif + +// +// +//// end header file ///////////////////////////////////////////////////// +#endif // STBI_INCLUDE_STB_IMAGE_H diff --git a/Demos/ParticlesOpenCL/CMakeLists.txt b/Demos/ParticlesOpenCL/CMakeLists.txt index a16ecfca7..369414d1a 100644 --- a/Demos/ParticlesOpenCL/CMakeLists.txt +++ b/Demos/ParticlesOpenCL/CMakeLists.txt @@ -2,6 +2,10 @@ IF(BUILD_MINICL_OPENCL_DEMOS) SUBDIRS( MiniCL ) ENDIF() +IF(BUILD_INTEL_OPENCL_DEMOS) + SUBDIRS(Intel) +ENDIF() + IF(BUILD_AMD_OPENCL_DEMOS) SUBDIRS(AMD) ENDIF() diff --git a/Demos/ParticlesOpenCL/btParticlesDemoDynamicsWorld.cpp b/Demos/ParticlesOpenCL/btParticlesDemoDynamicsWorld.cpp index 098b456cc..88e3d62e4 100644 --- a/Demos/ParticlesOpenCL/btParticlesDemoDynamicsWorld.cpp +++ b/Demos/ParticlesOpenCL/btParticlesDemoDynamicsWorld.cpp @@ -339,8 +339,12 @@ void btParticlesDynamicsWorld::initCLKernels(int argc, char** argv) { // m_cxMainContext = clCreateContextFromType(0, CL_DEVICE_TYPE_ALL, NULL, NULL, &ciErrNum); +#ifdef USE_INTEL_OPENCL + m_cxMainContext = btOclCommon::createContextFromType(CL_DEVICE_TYPE_ALL, &ciErrNum); +#else m_cxMainContext = btOclCommon::createContextFromType(CL_DEVICE_TYPE_GPU, &ciErrNum); - //m_cxMainContext = btOclCommon::createContextFromType(CL_DEVICE_TYPE_ALL, &ciErrNum); +#endif + oclCHECKERROR(ciErrNum, CL_SUCCESS); m_cdDevice = btOclGetMaxFlopsDev(m_cxMainContext); diff --git a/Demos/SharedOpenCL/btOclCommon.cpp b/Demos/SharedOpenCL/btOclCommon.cpp index a169c5752..4fc221792 100644 --- a/Demos/SharedOpenCL/btOclCommon.cpp +++ b/Demos/SharedOpenCL/btOclCommon.cpp @@ -21,6 +21,8 @@ subject to the following restrictions: static char* spPlatformVendor = #if defined(CL_PLATFORM_MINI_CL) "MiniCL, SCEA"; +#elif defined(CL_PLATFORM_INTEL) +"Intel(R) Corporation"; #elif defined(CL_PLATFORM_AMD) "Advanced Micro Devices, Inc."; #elif defined(CL_PLATFORM_NVIDIA) diff --git a/Demos/SharedOpenCL/btOclUtils.cpp b/Demos/SharedOpenCL/btOclUtils.cpp index a8aca18a4..8e2b1caf4 100644 --- a/Demos/SharedOpenCL/btOclUtils.cpp +++ b/Demos/SharedOpenCL/btOclUtils.cpp @@ -100,7 +100,10 @@ cl_device_id btOclGetMaxFlopsDev(cl_context cxMainContext) } else if( device_type == CL_DEVICE_TYPE_GPU ) { // Approximation to GPU compute power // As long as this beats the CPU number that's the important thing, really -#if defined(CL_PLATFORM_AMD) +#if defined(CL_PLATFORM_INTEL) + // SSE - 4, AVX1,2 - 8 : TODO: detect AVX? + SIMDmultiplier = 4; +#elif defined(CL_PLATFORM_AMD) // 16 processing elements, 5 ALUs each SIMDmultiplier = 80; #elif defined(CL_PLATFORM_NVIDIA) diff --git a/LICENSE b/LICENSE index ba24a53c2..794842d9b 100644 --- a/LICENSE +++ b/LICENSE @@ -1,6 +1,6 @@ /* Bullet Continuous Collision Detection and Physics Library -Copyright (c) 2003-2006 Erwin Coumans http://continuousphysics.com/Bullet/ +Copyright (c) 2003-2011 Erwin Coumans http://bulletphysics.org This software is provided 'as-is', without any express or implied warranty. In no event will the authors be held liable for any damages arising from the use of this software. @@ -14,6 +14,4 @@ subject to the following restrictions: */ All files in the Bullet/src folder are under this Zlib license. -Optional Extras/GIMPACT and Extras/GIMPACTBullet is also under ZLib license. Other optional external libraries in Extras/Demos have own license,see respective files. - -This means Bullet can freely be used in any software, including commercial and console software. A Playstation 3 optimized version is available through Sony. +Files in the Extras and Demos folder may have a different license, see the respective files. diff --git a/bullet_logo.png b/bullet_logo.png new file mode 100644 index 0000000000000000000000000000000000000000..d3a1b4b5588fbed303a9a15051b560a26af5dde2 GIT binary patch literal 3380 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 KMNUMnLSTZl?!Ko0 literal 0 HcmV?d00001 diff --git a/src/BulletCollision/BroadphaseCollision/btQuantizedBvh.h b/src/BulletCollision/BroadphaseCollision/btQuantizedBvh.h index bedb100af..579cc9a5c 100644 --- a/src/BulletCollision/BroadphaseCollision/btQuantizedBvh.h +++ b/src/BulletCollision/BroadphaseCollision/btQuantizedBvh.h @@ -107,9 +107,9 @@ ATTRIBUTE_ALIGNED16 (struct) btOptimizedBvhNode //for child nodes int m_subPart; int m_triangleIndex; - int m_padding[5];//bad, due to alignment - +//pad the size to 64 bytes + char m_padding[20]; }; diff --git a/src/BulletMultiThreaded/GpuSoftBodySolvers/OpenCL/CMakeLists.txt b/src/BulletMultiThreaded/GpuSoftBodySolvers/OpenCL/CMakeLists.txt index d298956ce..64b029fa3 100644 --- a/src/BulletMultiThreaded/GpuSoftBodySolvers/OpenCL/CMakeLists.txt +++ b/src/BulletMultiThreaded/GpuSoftBodySolvers/OpenCL/CMakeLists.txt @@ -1,5 +1,9 @@ SUBDIRS( MiniCL ) +IF(BUILD_INTEL_OPENCL_DEMOS) + SUBDIRS(Intel) +ENDIF() + IF(BUILD_AMD_OPENCL_DEMOS) SUBDIRS(AMD) ENDIF()