Bill Anderson <wja@ilm.com>
Wojciech Jarosz <wjarosz@ucsd.edu>
Andrew Kunz <akunz@ilm.com>
+Piotr Stanczyk <pstanczyk@ilm.com>
+Peter Hillman <peterh@weta.co.nz>
+Nick Porcino <nick.porcino@gmail.com>
+Kimball Thurston
Contributors:
-------------
Greg Ward <gward@lmi.net>
Joseph Goldstone <joseph@lp.com>
Loren Carpenter, Pixar Animation Studios
+Nicholas Yue <yue.nicholas@gmail.com>
+Yunfeng Bai (ILM)
+Pascal Jette (Autodesk)
+Karl Rasche, DreamWorks Animation <Karl.Rasche@dreamworks.com>
Win32 build system:
-------------------
project(openexr CXX)
-if(UNIX)
- if(APPLE)
- set(HAVE_POSIX_SEMAPHORES 0) # Unnamed semaphores are not supported: https://github.com/opencv/opencv/issues/9361
+
+if(NOT HAVE_CXX11)
+ ocv_check_compiler_flag(CXX "-std=c++11" HAVE_STD_CXX11 "${OpenCV_SOURCE_DIR}/cmake/checks/cxx11.cpp")
+ if(HAVE_STD_CXX11)
+ set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -std=c++11")
else()
- include(CheckIncludeFile)
- check_include_file(semaphore.h HAVE_POSIX_SEMAPHORES)
+ if(BUILD_OPENEXR)
+ message(WARNING "OpenCV: builtin OpenEXR requires C++11 support. OpenEXR is disabled.")
+ endif()
+ return()
endif()
endif()
+
+
+set(ILMBASE_VERSION_MAJOR "2")
+set(ILMBASE_VERSION_MINOR "3")
+set(ILMBASE_VERSION_PATCH "0")
+
+set(ILMBASE_VERSION "${ILMBASE_VERSION_MAJOR}.${ILMBASE_VERSION_MINOR}.${ILMBASE_VERSION_PATCH}")
+set(ILMBASE_VERSION_API ${ILMBASE_VERSION_MAJOR}_${ILMBASE_VERSION_MINOR})
+
+set(OPENEXR_VERSION_MAJOR "2")
+set(OPENEXR_VERSION_MINOR "3")
+set(OPENEXR_VERSION_PATCH "0")
+
+set(OPENEXR_VERSION "${OPENEXR_VERSION_MAJOR}.${OPENEXR_VERSION_MINOR}.${OPENEXR_VERSION_PATCH}")
+set(OPENEXR_VERSION_API ${OPENEXR_VERSION_MAJOR}_${OPENEXR_VERSION_MINOR})
+
+set(OPENEXR_VERSION "${OPENEXR_VERSION}" PARENT_SCOPE)
+
+if(WIN32)
+ set(HAVE_COMPLETE_IOMANIP 1)
+ set(OPENEXR_IMF_HAVE_COMPLETE_IOMANIP 1)
+ set(PLATFORM_WINDOWS 1)
+elseif(APPLE)
+ set(HAVE_POSIX_SEMAPHORES 0) # Unnamed semaphores are not supported: https://github.com/opencv/opencv/issues/9361
+ if(DARWIN)
+ set(OPENEXR_IMF_HAVE_DARWIN 1)
+ endif()
+elseif(UNIX)
+ include(CheckIncludeFile)
+ check_include_file(semaphore.h HAVE_POSIX_SEMAPHORES)
+endif()
+
+set(ILMBASE_VERSION_API "opencv")
+set(ILMBASE_INTERNAL_NAMESPACE_CUSTOM 1)
+set(IMATH_INTERNAL_NAMESPACE "Imath_${ILMBASE_VERSION_API}")
+set(IEX_INTERNAL_NAMESPACE "Iex_${ILMBASE_VERSION_API}")
+set(ILMTHREAD_INTERNAL_NAMESPACE "IlmThread_${ILMBASE_VERSION_API}")
+
+set(ILMBASE_NAMESPACE_CUSTOM 0)
+set(IMATH_NAMESPACE "Imath")
+set(IEX_NAMESPACE "Iex")
+set(ILMTHREAD_NAMESPACE "IlmThread")
+set(ILMBASE_VERSION_STRING "\"${ILMBASE_VERSION}\"" )
+set(ILMBASE_PACKAGE_STRING "\"IlmBase ${ILMBASE_VERSION}\"" )
+
+
+set(OPENEXR_VERSION_API "opencv")
+set(OPENEXR_IMF_INTERNAL_NAMESPACE_CUSTOM 1)
+set(OPENEXR_IMF_INTERNAL_NAMESPACE "Imf_${ILMBASE_VERSION_API}")
+set(OPENEXR_IMF_NAMESPACE_CUSTOM 0)
+set(OPENEXR_IMF_NAMESPACE "Imf")
+
+set(OPENEXR_VERSION_STRING "\"${OPENEXR_VERSION}\"" )
+set(OPENEXR_PACKAGE_STRING "\"OpenEXR ${OPENEXR_VERSION}\"" )
+
+
configure_file("${CMAKE_CURRENT_SOURCE_DIR}/IlmBaseConfig.h.cmakein"
"${CMAKE_CURRENT_BINARY_DIR}/IlmBaseConfig.h" @ONLY)
configure_file("${CMAKE_CURRENT_SOURCE_DIR}/OpenEXRConfig.h.cmakein"
"${CMAKE_CURRENT_SOURCE_DIR}/Iex"
"${CMAKE_CURRENT_SOURCE_DIR}/IlmThread"
"${CMAKE_CURRENT_SOURCE_DIR}/Imath"
- "${CMAKE_CURRENT_SOURCE_DIR}/IlmImf")
+ "${CMAKE_CURRENT_SOURCE_DIR}/IlmImf"
+ "${CMAKE_CURRENT_BINARY_DIR}")
ocv_include_directories("${CMAKE_CURRENT_BINARY_DIR}" ${ZLIB_INCLUDE_DIRS} ${OPENEXR_INCLUDE_PATHS})
file(GLOB lib_hdrs Half/*.h Iex/Iex*.h IlmThread/IlmThread*.h Imath/Imath*.h IlmImf/*.h)
list(APPEND lib_hdrs "${CMAKE_CURRENT_BINARY_DIR}/IlmBaseConfig.h" "${CMAKE_CURRENT_BINARY_DIR}/OpenEXRConfig.h")
-ocv_list_filterout(lib_srcs IlmImf/b44ExpLogTable.cpp)
-
if(WIN32)
ocv_list_filterout(lib_srcs Posix.*cpp)
else()
-Wdeprecated-declarations -Wmisleading-indentation -Wdeprecated
-Wsuggest-override -Winconsistent-missing-override
-Wimplicit-fallthrough
+ -Wtautological-compare # clang
+ -Wmissing-prototypes # gcc/clang
+ -Wreorder
+ -Wunused-result
)
if(CV_GCC AND CMAKE_CXX_COMPILER_VERSION VERSION_GREATER 8.0)
ocv_warnings_disable(CMAKE_CXX_FLAGS -Wclass-memaccess)
ocv_install_target(IlmImf EXPORT OpenCVModules ARCHIVE DESTINATION ${OPENCV_3P_LIB_INSTALL_PATH} COMPONENT dev)
endif()
-ocv_install_3rdparty_licenses(openexr LICENSE AUTHORS.ilmbase AUTHORS.openexr fix_msvc2013_errors.patch)
+ocv_install_3rdparty_licenses(openexr LICENSE AUTHORS.ilmbase AUTHORS.openexr)
set(OPENEXR_INCLUDE_PATHS ${OPENEXR_INCLUDE_PATHS} PARENT_SCOPE)
-set(OPENEXR_VERSION "1.7.1" PARENT_SCOPE)
+Version 2.x.x
+ * Bumped version to track OpenEXR
+ (Piotr Stanczyk)
+
+Version 2.0.1
+ * Bumped version to track OpenEXR
+ (Piotr Stanczyk)
+
+Version 2.0.0
+ * Bumped version to track OpenEXR
+ (Piotr Stanczyk)
+ * Numerous minor fixes, missing includes etc
+
+Version 1.1.0.beta.1
+ * Added new module PyIlmBase : python bindings for IlmBase
+ (Nick Rasmussen)
+ * Added git specific files
+ (Piotr Stanczyk)
+ * Minor fixes for newer gcc versions and OS X.
+ (misc)
+ * Preparation for OpenEXR v2 release { remove message for final release }
+ (Piotr Stanczyk)
+ * Updated the so verison to 10
+ (Piotr Stanczyk)
+ * Initial use of the CMake build system
+ (Nicholas Yue)
+
Version 1.0.3
* Added support for enabling/disabling large stack optimisations, used in
halfFunction.h.
+Version 2.0.1
+ * Temporarily turning off optimisation code path
+ (Piotr Stanczyk)
+ * Added additional tests for future optimisation refactoring
+ (Piotr Stanczyk / Peter Hillman)
+ * Fixes for StringVectors
+ (Peter Hillman)
+ * Additional checks for type mismatches
+ (Peter Hillman)
+ * Fix for Composite Deep Scanline
+ (Brendan Bolles)
+
+Version 2.0.0
+ * Updated Documentation
+ (Peter Hillman)
+ * Updated Namespacing mechanism
+ (Piotr Stanczyk)
+ * Fixes for succd & predd
+ (Peter Hillman)
+ * Fixes for FPE control registers
+ (Piotr Stanczyk)
+ * Additional checks and tests on DeepImages, scanlines and tiles
+ (Peter Hillman)
+ * Folded in Autodesk read optimisations for RGB(A) files
+ (Pascal Jette, Peter Hillman)
+ * Updated the bootstrap scripts to use libtoolize if glibtoolize isn't available on darwin.
+ (Nick Rasmussen)
+ * Numerous minor fixes, missing includes etc
+
+Version 2.0.0.beta.1:
+* Please read the separate file for v2 additions and changes.
+ * Added git specific files
+ (Piotr Stanczyk)
+ * Updated the so verison to 20
+ (Piotr Stanczyk)
+ * Initial use of the CMake build system
+ (Nicholas Yue)
+
Version 1.7.1:
- * Updated the .so verison to 7.
+ * Updated the .so verison to 7.
(Piotr Stanczyk)
Version 1.7.0:
//
{
- 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 1024, 2048, 3072, 4096, 5120, 6144, 7168,
- 8192, 9216, 10240, 11264, 12288, 13312, 14336, 15360,
- 16384, 17408, 18432, 19456, 20480, 21504, 22528, 23552,
- 24576, 25600, 26624, 27648, 28672, 29696, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 33792, 34816, 35840, 36864, 37888, 38912, 39936,
- 40960, 41984, 43008, 44032, 45056, 46080, 47104, 48128,
- 49152, 50176, 51200, 52224, 53248, 54272, 55296, 56320,
- 57344, 58368, 59392, 60416, 61440, 62464, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 1024, 2048, 3072, 4096, 5120, 6144, 7168,
+ 8192, 9216, 10240, 11264, 12288, 13312, 14336, 15360,
+ 16384, 17408, 18432, 19456, 20480, 21504, 22528, 23552,
+ 24576, 25600, 26624, 27648, 28672, 29696, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 33792, 34816, 35840, 36864, 37888, 38912, 39936,
+ 40960, 41984, 43008, 44032, 45056, 46080, 47104, 48128,
+ 49152, 50176, 51200, 52224, 53248, 54272, 55296, 56320,
+ 57344, 58368, 59392, 60416, 61440, 62464, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0,
};
//
// Copyright (c) 2002, Industrial Light & Magic, a division of Lucas
// Digital Ltd. LLC
-//
+//
// All rights reserved.
-//
+//
// Redistribution and use in source and binary forms, with or without
// modification, are permitted provided that the following conditions are
// met:
// distribution.
// * Neither the name of Industrial Light & Magic nor the names of
// its contributors may be used to endorse or promote products derived
-// from this software without specific prior written permission.
-//
+// from this software without specific prior written permission.
+//
// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
// Lookup tables for half-to-float and float-to-half conversion
//-------------------------------------------------------------
-HALF_EXPORT_CONST half::uif half::_toFloat[1 << 16] =
-#include "toFloat.h"
-HALF_EXPORT_CONST unsigned short half::_eLut[1 << 9] =
-#include "eLut.h"
-
+HALF_EXPORT const half::uif half::_toFloat[1 << 16] =
+ #include "toFloat.h"
+HALF_EXPORT const unsigned short half::_eLut[1 << 9] =
+ #include "eLut.h"
//-----------------------------------------------
// Overflow handler for float-to-half conversion;
// which may be trapped by the operating system.
//-----------------------------------------------
-float
+HALF_EXPORT float
half::overflow ()
{
volatile float f = 1e10;
- for (int i = 0; i < 10; i++)
- f *= f; // this will overflow before
- // the forÂloop terminates
+ for (int i = 0; i < 10; i++)
+ f *= f; // this will overflow before
+ // the forÂloop terminates
return f;
}
// zeroes, denormalized numbers and exponent overflows.
//-----------------------------------------------------
-short
+HALF_EXPORT short
half::convert (int i)
{
//
// of float and half (127 versus 15).
//
- register int s = (i >> 16) & 0x00008000;
- register int e = ((i >> 23) & 0x000000ff) - (127 - 15);
- register int m = i & 0x007fffff;
+ int s = (i >> 16) & 0x00008000;
+ int e = ((i >> 23) & 0x000000ff) - (127 - 15);
+ int m = i & 0x007fffff;
//
// Now reassemble s, e and m into a half:
if (e <= 0)
{
- if (e < -10)
- {
- //
- // E is less than -10. The absolute value of f is
- // less than HALF_MIN (f may be a small normalized
- // float, a denormalized float or a zero).
- //
- // We convert f to a half zero with the same sign as f.
- //
-
- return s;
- }
-
- //
- // E is between -10 and 0. F is a normalized float
- // whose magnitude is less than HALF_NRM_MIN.
- //
- // We convert f to a denormalized half.
- //
-
- //
- // Add an explicit leading 1 to the significand.
- //
-
- m = m | 0x00800000;
-
- //
- // Round to m to the nearest (10+e)-bit value (with e between
- // -10 and 0); in case of a tie, round to the nearest even value.
- //
- // Rounding may cause the significand to overflow and make
- // our number normalized. Because of the way a half's bits
- // are laid out, we don't have to treat this case separately;
- // the code below will handle it correctly.
- //
-
- int t = 14 - e;
- int a = (1 << (t - 1)) - 1;
- int b = (m >> t) & 1;
-
- m = (m + a + b) >> t;
-
- //
- // Assemble the half from s, e (zero) and m.
- //
-
- return s | m;
+ if (e < -10)
+ {
+ //
+ // E is less than -10. The absolute value of f is
+ // less than HALF_MIN (f may be a small normalized
+ // float, a denormalized float or a zero).
+ //
+ // We convert f to a half zero with the same sign as f.
+ //
+
+ return s;
+ }
+
+ //
+ // E is between -10 and 0. F is a normalized float
+ // whose magnitude is less than HALF_NRM_MIN.
+ //
+ // We convert f to a denormalized half.
+ //
+
+ //
+ // Add an explicit leading 1 to the significand.
+ //
+
+ m = m | 0x00800000;
+
+ //
+ // Round to m to the nearest (10+e)-bit value (with e between
+ // -10 and 0); in case of a tie, round to the nearest even value.
+ //
+ // Rounding may cause the significand to overflow and make
+ // our number normalized. Because of the way a half's bits
+ // are laid out, we don't have to treat this case separately;
+ // the code below will handle it correctly.
+ //
+
+ int t = 14 - e;
+ int a = (1 << (t - 1)) - 1;
+ int b = (m >> t) & 1;
+
+ m = (m + a + b) >> t;
+
+ //
+ // Assemble the half from s, e (zero) and m.
+ //
+
+ return s | m;
}
else if (e == 0xff - (127 - 15))
{
- if (m == 0)
- {
- //
- // F is an infinity; convert f to a half
- // infinity with the same sign as f.
- //
-
- return s | 0x7c00;
- }
- else
- {
- //
- // F is a NAN; we produce a half NAN that preserves
- // the sign bit and the 10 leftmost bits of the
- // significand of f, with one exception: If the 10
- // leftmost bits are all zero, the NAN would turn
- // into an infinity, so we have to set at least one
- // bit in the significand.
- //
-
- m >>= 13;
- return s | 0x7c00 | m | (m == 0);
- }
+ if (m == 0)
+ {
+ //
+ // F is an infinity; convert f to a half
+ // infinity with the same sign as f.
+ //
+
+ return s | 0x7c00;
+ }
+ else
+ {
+ //
+ // F is a NAN; we produce a half NAN that preserves
+ // the sign bit and the 10 leftmost bits of the
+ // significand of f, with one exception: If the 10
+ // leftmost bits are all zero, the NAN would turn
+ // into an infinity, so we have to set at least one
+ // bit in the significand.
+ //
+
+ m >>= 13;
+ return s | 0x7c00 | m | (m == 0);
+ }
}
else
{
- //
- // E is greater than zero. F is a normalized float.
- // We try to convert f to a normalized half.
- //
-
- //
- // Round to m to the nearest 10-bit value. In case of
- // a tie, round to the nearest even value.
- //
-
- m = m + 0x00000fff + ((m >> 13) & 1);
-
- if (m & 0x00800000)
- {
- m = 0; // overflow in significand,
- e += 1; // adjust exponent
- }
-
- //
- // Handle exponent overflow
- //
-
- if (e > 30)
- {
- overflow (); // Cause a hardware floating point overflow;
- return s | 0x7c00; // if this returns, the half becomes an
- } // infinity with the same sign as f.
-
- //
- // Assemble the half from s, e and m.
- //
-
- return s | (e << 10) | (m >> 13);
+ //
+ // E is greater than zero. F is a normalized float.
+ // We try to convert f to a normalized half.
+ //
+
+ //
+ // Round to m to the nearest 10-bit value. In case of
+ // a tie, round to the nearest even value.
+ //
+
+ m = m + 0x00000fff + ((m >> 13) & 1);
+
+ if (m & 0x00800000)
+ {
+ m = 0; // overflow in significand,
+ e += 1; // adjust exponent
+ }
+
+ //
+ // Handle exponent overflow
+ //
+
+ if (e > 30)
+ {
+ overflow (); // Cause a hardware floating point overflow;
+ return s | 0x7c00; // if this returns, the half becomes an
+ } // infinity with the same sign as f.
+
+ //
+ // Assemble the half from s, e and m.
+ //
+
+ return s | (e << 10) | (m >> 13);
}
}
// Stream I/O operators
//---------------------
-ostream &
+HALF_EXPORT ostream &
operator << (ostream &os, half h)
{
os << float (h);
}
-istream &
+HALF_EXPORT istream &
operator >> (istream &is, half &h)
{
float f;
// floats and halfs, mostly for debugging
//---------------------------------------
-void
+HALF_EXPORT void
printBits (ostream &os, half h)
{
unsigned short b = h.bits();
for (int i = 15; i >= 0; i--)
{
- os << (((b >> i) & 1)? '1': '0');
+ os << (((b >> i) & 1)? '1': '0');
- if (i == 15 || i == 10)
- os << ' ';
+ if (i == 15 || i == 10)
+ os << ' ';
}
}
-void
+HALF_EXPORT void
printBits (ostream &os, float f)
{
half::uif x;
for (int i = 31; i >= 0; i--)
{
- os << (((x.i >> i) & 1)? '1': '0');
+ os << (((x.i >> i) & 1)? '1': '0');
- if (i == 31 || i == 23)
- os << ' ';
+ if (i == 31 || i == 23)
+ os << ' ';
}
}
-void
+HALF_EXPORT void
printBits (char c[19], half h)
{
unsigned short b = h.bits();
for (int i = 15, j = 0; i >= 0; i--, j++)
{
- c[j] = (((b >> i) & 1)? '1': '0');
+ c[j] = (((b >> i) & 1)? '1': '0');
- if (i == 15 || i == 10)
- c[++j] = ' ';
+ if (i == 15 || i == 10)
+ c[++j] = ' ';
}
-
+
c[18] = 0;
}
-void
+HALF_EXPORT void
printBits (char c[35], float f)
{
half::uif x;
for (int i = 31, j = 0; i >= 0; i--, j++)
{
- c[j] = (((x.i >> i) & 1)? '1': '0');
+ c[j] = (((x.i >> i) & 1)? '1': '0');
- if (i == 31 || i == 23)
- c[++j] = ' ';
+ if (i == 31 || i == 23)
+ c[++j] = ' ';
}
c[34] = 0;
//
// Copyright (c) 2002, Industrial Light & Magic, a division of Lucas
// Digital Ltd. LLC
-//
+//
// All rights reserved.
-//
+//
// Redistribution and use in source and binary forms, with or without
// modification, are permitted provided that the following conditions are
// met:
// distribution.
// * Neither the name of Industrial Light & Magic nor the names of
// its contributors may be used to endorse or promote products derived
-// from this software without specific prior written permission.
-//
+// from this software without specific prior written permission.
+//
// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
#ifndef _HALF_H_
#define _HALF_H_
+#include "halfExport.h" // for definition of HALF_EXPORT
#include <iostream>
-#if defined(OPENEXR_DLL)
- #if defined(HALF_EXPORTS)
- #define HALF_EXPORT __declspec(dllexport)
- #else
- #define HALF_EXPORT __declspec(dllimport)
- #endif
- #define HALF_EXPORT_CONST
-#else
- #define HALF_EXPORT
- #define HALF_EXPORT_CONST const
-#endif
-
-class HALF_EXPORT half
+class half
{
public:
// Access to the internal representation
//--------------------------------------
- unsigned short bits () const;
- void setBits (unsigned short bits);
+ HALF_EXPORT unsigned short bits () const;
+ HALF_EXPORT void setBits (unsigned short bits);
public:
union uif
{
- unsigned int i;
- float f;
+ unsigned int i;
+ float f;
};
private:
- static short convert (int i);
- static float overflow ();
+ HALF_EXPORT static short convert (int i);
+ HALF_EXPORT static float overflow ();
- unsigned short _h;
+ unsigned short _h;
- static HALF_EXPORT_CONST uif _toFloat[1 << 16];
- static HALF_EXPORT_CONST unsigned short _eLut[1 << 9];
+ HALF_EXPORT static const uif _toFloat[1 << 16];
+ HALF_EXPORT static const unsigned short _eLut[1 << 9];
};
+
+
//-----------
// Stream I/O
//-----------
-HALF_EXPORT std::ostream & operator << (std::ostream &os, half h);
-HALF_EXPORT std::istream & operator >> (std::istream &is, half &h);
+HALF_EXPORT std::ostream & operator << (std::ostream &os, half h);
+HALF_EXPORT std::istream & operator >> (std::istream &is, half &h);
//----------
// Debugging
//----------
-HALF_EXPORT void printBits (std::ostream &os, half h);
-HALF_EXPORT void printBits (std::ostream &os, float f);
-HALF_EXPORT void printBits (char c[19], half h);
-HALF_EXPORT void printBits (char c[35], float f);
+HALF_EXPORT void printBits (std::ostream &os, half h);
+HALF_EXPORT void printBits (std::ostream &os, float f);
+HALF_EXPORT void printBits (char c[19], half h);
+HALF_EXPORT void printBits (char c[35], float f);
//-------------------------------------------------------------------------
#define HALF_MAX 65504.0f // Largest positive half
#define HALF_EPSILON 0.00097656f // Smallest positive e for which
- // half (1.0 + e) != half (1.0)
+ // half (1.0 + e) != half (1.0)
#else
#define HALF_MIN 5.96046448e-08 // Smallest positive half
#define HALF_MAX 65504.0 // Largest positive half
#define HALF_EPSILON 0.00097656 // Smallest positive e for which
- // half (1.0 + e) != half (1.0)
+ // half (1.0 + e) != half (1.0)
#endif
#define HALF_MANT_DIG 11 // Number of digits in mantissa
- // (significand + hidden leading 1)
+ // (significand + hidden leading 1)
#define HALF_DIG 2 // Number of base 10 digits that
- // can be represented without change
+ // can be represented without change
+
+#define HALF_DECIMAL_DIG 5 // Number of base-10 digits that are
+ // necessary to uniquely represent all
+ // distinct values
#define HALF_RADIX 2 // Base of the exponent
#define HALF_MIN_EXP -13 // Minimum negative integer such that
- // HALF_RADIX raised to the power of
- // one less than that integer is a
- // normalized half
+ // HALF_RADIX raised to the power of
+ // one less than that integer is a
+ // normalized half
#define HALF_MAX_EXP 16 // Maximum positive integer such that
- // HALF_RADIX raised to the power of
- // one less than that integer is a
- // normalized half
+ // HALF_RADIX raised to the power of
+ // one less than that integer is a
+ // normalized half
#define HALF_MIN_10_EXP -4 // Minimum positive integer such
- // that 10 raised to that power is
- // a normalized half
+ // that 10 raised to that power is
+ // a normalized half
#define HALF_MAX_10_EXP 4 // Maximum positive integer such
- // that 10 raised to that power is
- // a normalized half
+ // that 10 raised to that power is
+ // a normalized half
//---------------------------------------------------------------------------
// floating point number, whose bits are arranged as follows:
//
// 31 (msb)
-// |
+// |
// | 30 23
-// | | |
+// | | |
// | | | 22 0 (lsb)
// | | | | |
// X XXXXXXXX XXXXXXXXXXXXXXXXXXXXXXX
// Here is the bit-layout for a half number, h:
//
// 15 (msb)
-// |
+// |
// | 14 10
// | | |
// | | | 9 0 (lsb)
if (f == 0)
{
- //
- // Common special case - zero.
- // Preserve the zero's sign bit.
- //
+ //
+ // Common special case - zero.
+ // Preserve the zero's sign bit.
+ //
- _h = (x.i >> 16);
+ _h = (x.i >> 16);
}
else
{
- //
- // We extract the combined sign and exponent, e, from our
- // floating-point number, f. Then we convert e to the sign
- // and exponent of the half number via a table lookup.
- //
- // For the most common case, where a normalized half is produced,
- // the table lookup returns a non-zero value; in this case, all
- // we have to do is round f's significand to 10 bits and combine
- // the result with e.
- //
- // For all other cases (overflow, zeroes, denormalized numbers
- // resulting from underflow, infinities and NANs), the table
- // lookup returns zero, and we call a longer, non-inline function
- // to do the float-to-half conversion.
- //
-
- register int e = (x.i >> 23) & 0x000001ff;
-
- e = _eLut[e];
-
- if (e)
- {
- //
- // Simple case - round the significand, m, to 10
- // bits and combine it with the sign and exponent.
- //
-
- register int m = x.i & 0x007fffff;
- _h = e + ((m + 0x00000fff + ((m >> 13) & 1)) >> 13);
- }
- else
- {
- //
- // Difficult case - call a function.
- //
-
- _h = convert (x.i);
- }
+ //
+ // We extract the combined sign and exponent, e, from our
+ // floating-point number, f. Then we convert e to the sign
+ // and exponent of the half number via a table lookup.
+ //
+ // For the most common case, where a normalized half is produced,
+ // the table lookup returns a non-zero value; in this case, all
+ // we have to do is round f's significand to 10 bits and combine
+ // the result with e.
+ //
+ // For all other cases (overflow, zeroes, denormalized numbers
+ // resulting from underflow, infinities and NANs), the table
+ // lookup returns zero, and we call a longer, non-inline function
+ // to do the float-to-half conversion.
+ //
+
+ int e = (x.i >> 23) & 0x000001ff;
+
+ e = _eLut[e];
+
+ if (e)
+ {
+ //
+ // Simple case - round the significand, m, to 10
+ // bits and combine it with the sign and exponent.
+ //
+
+ int m = x.i & 0x007fffff;
+ _h = (unsigned short)(e + ((m + 0x00000fff + ((m >> 13) & 1)) >> 13));
+ }
+ else
+ {
+ //
+ // Difficult case - call a function.
+ //
+
+ _h = convert (x.i);
+ }
}
}
//
if (n >= 10)
- return *this;
+ return *this;
//
// Disassemble h into the sign, s,
if (e >= 0x7c00)
{
- //
- // Overflow occurred -- truncate instead of rounding.
- //
+ //
+ // Overflow occurred -- truncate instead of rounding.
+ //
- e = _h;
- e >>= 10 - n;
- e <<= 10 - n;
+ e = _h;
+ e >>= 10 - n;
+ e <<= 10 - n;
}
//
// Other inline functions
//-----------------------
-inline half
+inline half
half::operator - () const
{
half h;
}
-inline bool
+inline bool
half::isFinite () const
{
unsigned short e = (_h >> 10) & 0x001f;
}
-inline bool
+inline bool
half::isNegative () const
{
return (_h & 0x8000) != 0;
///////////////////////////////////////////////////////////////////////////
//
-// Copyright (c) 2002, Industrial Light & Magic, a division of Lucas
+// Copyright (c) 2008, Industrial Light & Magic, a division of Lucas
// Digital Ltd. LLC
//
// All rights reserved.
//
///////////////////////////////////////////////////////////////////////////
+#ifndef HALFEXPORT_H
+#define HALFEXPORT_H
+#if defined(OPENEXR_DLL)
+ #if defined(HALF_EXPORTS)
+ #define HALF_EXPORT __declspec(dllexport)
+ #else
+ #define HALF_EXPORT __declspec(dllimport)
+ #endif
+ #define HALF_EXPORT_CONST
+#else
+ #define HALF_EXPORT
+ #define HALF_EXPORT_CONST const
+#endif
-#ifndef INCLUDED_IMATHGLU_H
-#define INCLUDED_IMATHGLU_H
-
-#include <GL/gl.h>
-#include <GL/glu.h>
-
-#include "ImathVec.h"
-
-inline
-void
-gluLookAt(const Imath::V3f &pos, const Imath::V3f &interest, const Imath::V3f &up)
-{
- gluLookAt(pos.x, pos.y, pos.z,
- interest.x, interest.y, interest.z,
- up.x, up.y, up.z);
-}
+#endif // #ifndef HALFEXPORT_H
-#endif
//
// Copyright (c) 2002, Industrial Light & Magic, a division of Lucas
// Digital Ltd. LLC
-//
+//
// All rights reserved.
-//
+//
// Redistribution and use in source and binary forms, with or without
// modification, are permitted provided that the following conditions are
// met:
// distribution.
// * Neither the name of Industrial Light & Magic nor the names of
// its contributors may be used to endorse or promote products derived
-// from this software without specific prior written permission.
-//
+// from this software without specific prior written permission.
+//
// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
#include "half.h"
-#include <IlmBaseConfig.h>
-#ifndef ILMBASE_HAVE_LARGE_STACK
+#include "IlmBaseConfig.h"
+#ifndef ILMBASE_HAVE_LARGE_STACK
#include <string.h> // need this for memset
-#else
+#else
#endif
#include <float.h>
template <class Function>
halfFunction (Function f,
- half domainMin = -HALF_MAX,
- half domainMax = HALF_MAX,
- T defaultValue = 0,
- T posInfValue = 0,
- T negInfValue = 0,
- T nanValue = 0);
+ half domainMin = -HALF_MAX,
+ half domainMax = HALF_MAX,
+ T defaultValue = 0,
+ T posInfValue = 0,
+ T negInfValue = 0,
+ T nanValue = 0);
#ifndef ILMBASE_HAVE_LARGE_STACK
- ~halfFunction () { delete [] _lut; }
+ ~halfFunction () { delete [] _lut; }
#endif
-
+
//-----------
// Evaluation
//-----------
T operator () (half x) const;
private:
+
#ifdef ILMBASE_HAVE_LARGE_STACK
T _lut[1 << 16];
#else
template <class T>
template <class Function>
halfFunction<T>::halfFunction (Function f,
- half domainMin,
- half domainMax,
- T defaultValue,
- T posInfValue,
- T negInfValue,
- T nanValue)
+ half domainMin,
+ half domainMax,
+ T defaultValue,
+ T posInfValue,
+ T negInfValue,
+ T nanValue)
{
#ifndef ILMBASE_HAVE_LARGE_STACK
_lut = new T[1<<16];
memset (_lut, 0 , (1<<16) * sizeof(T));
#endif
-
+
for (int i = 0; i < (1 << 16); i++)
{
- half x;
- x.setBits (i);
-
- if (x.isNan())
- _lut[i] = nanValue;
- else if (x.isInfinity())
- _lut[i] = x.isNegative()? negInfValue: posInfValue;
- else if (x < domainMin || x > domainMax)
- _lut[i] = defaultValue;
- else
- _lut[i] = f (x);
+ half x;
+ x.setBits (i);
+
+ if (x.isNan())
+ _lut[i] = nanValue;
+ else if (x.isInfinity())
+ _lut[i] = x.isNegative()? negInfValue: posInfValue;
+ else if (x < domainMin || x > domainMax)
+ _lut[i] = defaultValue;
+ else
+ _lut[i] = f (x);
}
}
//
// Copyright (c) 2002, Industrial Light & Magic, a division of Lucas
// Digital Ltd. LLC
-//
+//
// All rights reserved.
-//
+//
// Redistribution and use in source and binary forms, with or without
// modification, are permitted provided that the following conditions are
// met:
// distribution.
// * Neither the name of Industrial Light & Magic nor the names of
// its contributors may be used to endorse or promote products derived
-// from this software without specific prior written permission.
-//
+// from this software without specific prior written permission.
+//
// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
static const bool traps = true;
static const bool tinyness_before = false;
static const float_round_style round_style = round_to_nearest;
+
+#if __cplusplus >= 201103L
+
+ // C++11 additions.
+ static constexpr int max_digits10 = HALF_DECIMAL_DIG;
+ static half lowest () {return -HALF_MAX;}
+
+#endif
+
};
+++ /dev/null
-///////////////////////////////////////////////////////////////////////////
-//
-// Copyright (c) 2002, Industrial Light & Magic, a division of Lucas
-// Digital Ltd. LLC
-//
-// All rights reserved.
-//
-// Redistribution and use in source and binary forms, with or without
-// modification, are permitted provided that the following conditions are
-// met:
-// * Redistributions of source code must retain the above copyright
-// notice, this list of conditions and the following disclaimer.
-// * Redistributions in binary form must reproduce the above
-// copyright notice, this list of conditions and the following disclaimer
-// in the documentation and/or other materials provided with the
-// distribution.
-// * Neither the name of Industrial Light & Magic nor the names of
-// its contributors may be used to endorse or promote products derived
-// from this software without specific prior written permission.
-//
-// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
-// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
-// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
-// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
-// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
-// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
-// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
-// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
-// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
-// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
-// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
-//
-///////////////////////////////////////////////////////////////////////////
-
-
-
-
-//---------------------------------------------------------------------------
-//
-// toFloat
-//
-// A program to generate the lookup table for half-to-float
-// conversion needed by class half.
-// The program loops over all 65536 possible half numbers,
-// converts each of them to a float, and prints the result.
-//
-//---------------------------------------------------------------------------
-
-
-#include <iostream>
-#include <iomanip>
-
-using namespace std;
-
-//---------------------------------------------------
-// Interpret an unsigned short bit pattern as a half,
-// and convert that half to the corresponding float's
-// bit pattern.
-//---------------------------------------------------
-
-unsigned int
-halfToFloat (unsigned short y)
-{
-
- int s = (y >> 15) & 0x00000001;
- int e = (y >> 10) & 0x0000001f;
- int m = y & 0x000003ff;
-
- if (e == 0)
- {
- if (m == 0)
- {
- //
- // Plus or minus zero
- //
-
- return s << 31;
- }
- else
- {
- //
- // Denormalized number -- renormalize it
- //
-
- while (!(m & 0x00000400))
- {
- m <<= 1;
- e -= 1;
- }
-
- e += 1;
- m &= ~0x00000400;
- }
- }
- else if (e == 31)
- {
- if (m == 0)
- {
- //
- // Positive or negative infinity
- //
-
- return (s << 31) | 0x7f800000;
- }
- else
- {
- //
- // Nan -- preserve sign and significand bits
- //
-
- return (s << 31) | 0x7f800000 | (m << 13);
- }
- }
-
- //
- // Normalized number
- //
-
- e = e + (127 - 15);
- m = m << 13;
-
- //
- // Assemble s, e and m.
- //
-
- return (s << 31) | (e << 23) | m;
-}
-
-
-//---------------------------------------------
-// Main - prints the half-to-float lookup table
-//---------------------------------------------
-
-int
-main ()
-{
- cout.precision (9);
- cout.setf (ios_base::hex, ios_base::basefield);
-
- cout << "//\n"
- "// This is an automatically generated file.\n"
- "// Do not edit.\n"
- "//\n\n";
-
- cout << "{\n ";
-
- const int iMax = (1 << 16);
-
- for (int i = 0; i < iMax; i++)
- {
- cout << "{0x" << setfill ('0') << setw (8) << halfToFloat (i) << "}, ";
-
- if (i % 4 == 3)
- {
- cout << "\n";
-
- if (i < iMax - 1)
- cout << " ";
- }
- }
-
- cout << "};\n";
- return 0;
-}
//
// Copyright (c) 2002, Industrial Light & Magic, a division of Lucas
// Digital Ltd. LLC
-//
+//
// All rights reserved.
-//
+//
// Redistribution and use in source and binary forms, with or without
// modification, are permitted provided that the following conditions are
// met:
// distribution.
// * Neither the name of Industrial Light & Magic nor the names of
// its contributors may be used to endorse or promote products derived
-// from this software without specific prior written permission.
-//
+// from this software without specific prior written permission.
+//
// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
///////////////////////////////////////////////////////////////////////////
//
-// Copyright (c) 2002, Industrial Light & Magic, a division of Lucas
+// Copyright (c) 2002-2012, Industrial Light & Magic, a division of Lucas
// Digital Ltd. LLC
-//
+//
// All rights reserved.
-//
+//
// Redistribution and use in source and binary forms, with or without
// modification, are permitted provided that the following conditions are
// met:
// distribution.
// * Neither the name of Industrial Light & Magic nor the names of
// its contributors may be used to endorse or promote products derived
-// from this software without specific prior written permission.
-//
+// from this software without specific prior written permission.
+//
// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
//
//---------------------------------------------------------------------
+#include "IexExport.h"
#include "IexBaseExc.h"
+#include "IexMacros.h"
-namespace Iex {
-namespace {
+#ifdef PLATFORM_WINDOWS
+#include <windows.h>
+#endif
+#include <stdlib.h>
+
+IEX_INTERNAL_NAMESPACE_SOURCE_ENTER
-StackTracer currentStackTracer = 0;
+namespace {
+
+StackTracer currentStackTracer = 0;
} // namespace
-void
+void
setStackTracer (StackTracer stackTracer)
{
currentStackTracer = stackTracer;
BaseExc::BaseExc (const char* s) throw () :
- std::string (s? s: ""),
+ _message (s? s: ""),
_stackTrace (currentStackTracer? currentStackTracer(): "")
{
// empty
BaseExc::BaseExc (const std::string &s) throw () :
- std::string (s),
+ _message (s),
_stackTrace (currentStackTracer? currentStackTracer(): "")
{
// empty
BaseExc::BaseExc (std::stringstream &s) throw () :
- std::string (s.str()),
+ _message (s.str()),
_stackTrace (currentStackTracer? currentStackTracer(): "")
{
// empty
BaseExc::BaseExc (const BaseExc &be) throw () :
- std::string (be),
+ _message (be._message),
_stackTrace (be._stackTrace)
{
// empty
const char *
BaseExc::what () const throw ()
{
- return c_str();
+ return _message.c_str();
}
BaseExc &
BaseExc::assign (std::stringstream &s)
{
- std::string::assign (s.str());
+ _message.assign (s.str());
return *this;
}
BaseExc &
BaseExc::append (std::stringstream &s)
{
- std::string::append (s.str());
+ _message.append (s.str());
return *this;
}
+const std::string &
+BaseExc::message() const
+{
+ return _message;
+}
-} // namespace Iex
+BaseExc &
+BaseExc::operator = (std::stringstream &s)
+{
+ return assign (s);
+}
+
+
+BaseExc &
+BaseExc::operator += (std::stringstream &s)
+{
+ return append (s);
+}
+
+
+BaseExc &
+BaseExc::assign (const char *s)
+{
+ _message.assign(s);
+ return *this;
+}
+
+
+BaseExc &
+BaseExc::operator = (const char *s)
+{
+ return assign(s);
+}
+
+
+BaseExc &
+BaseExc::append (const char *s)
+{
+ _message.append(s);
+ return *this;
+}
+
+
+BaseExc &
+BaseExc::operator += (const char *s)
+{
+ return append(s);
+}
+
+
+const std::string &
+BaseExc::stackTrace () const
+{
+ return _stackTrace;
+}
+
+
+IEX_INTERNAL_NAMESPACE_SOURCE_EXIT
+
+
+#ifdef PLATFORM_WINDOWS
+
+#pragma optimize("", off)
+void
+iex_debugTrap()
+{
+ if (0 != getenv("IEXDEBUGTHROW"))
+ ::DebugBreak();
+}
+#else
+void
+iex_debugTrap()
+{
+ // how to in Linux?
+ if (0 != ::getenv("IEXDEBUGTHROW"))
+ __builtin_trap();
+}
+#endif
///////////////////////////////////////////////////////////////////////////
//
-// Copyright (c) 2002, Industrial Light & Magic, a division of Lucas
+// Copyright (c) 2002-2012, Industrial Light & Magic, a division of Lucas
// Digital Ltd. LLC
-//
+//
// All rights reserved.
-//
+//
// Redistribution and use in source and binary forms, with or without
// modification, are permitted provided that the following conditions are
// met:
// distribution.
// * Neither the name of Industrial Light & Magic nor the names of
// its contributors may be used to endorse or promote products derived
-// from this software without specific prior written permission.
-//
+// from this software without specific prior written permission.
+//
// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
///////////////////////////////////////////////////////////////////////////
-
#ifndef INCLUDED_IEXBASEEXC_H
#define INCLUDED_IEXBASEEXC_H
+#include "IexNamespace.h"
+#include "IexExport.h"
//----------------------------------------------------------
//
#include <exception>
#include <sstream>
-namespace Iex {
+IEX_INTERNAL_NAMESPACE_HEADER_ENTER
-#if (defined _WIN32 || defined _WIN64) && defined _MSC_VER
-// Tell MS VC++ to suppress exception specification warnings
-#pragma warning(disable:4290)
-#endif
//-------------------------------
// Our most basic exception class
//-------------------------------
-class BaseExc: public std::string, public std::exception
+class BaseExc: public std::exception
{
public:
// Constructors and destructor
//----------------------------
- BaseExc (const char *s = 0) throw(); // std::string (s)
- BaseExc (const std::string &s) throw(); // std::string (s)
- BaseExc (std::stringstream &s) throw(); // std::string (s.str())
+ IEX_EXPORT BaseExc (const char *s = 0) throw(); // std::string (s)
+ IEX_EXPORT BaseExc (const std::string &s) throw(); // std::string (s)
+ IEX_EXPORT BaseExc (std::stringstream &s) throw(); // std::string (s.str())
- BaseExc (const BaseExc &be) throw();
- virtual ~BaseExc () throw ();
+ IEX_EXPORT BaseExc (const BaseExc &be) throw();
+ IEX_EXPORT virtual ~BaseExc () throw ();
- //--------------------------------------------
- // what() method -- e.what() returns e.c_str()
- //--------------------------------------------
+ //---------------------------------------------------
+ // what() method -- e.what() returns _message.c_str()
+ //---------------------------------------------------
- virtual const char * what () const throw ();
+ IEX_EXPORT virtual const char * what () const throw ();
//--------------------------------------------------
// Convenient methods to change the exception's text
//--------------------------------------------------
- BaseExc & assign (std::stringstream &s); // assign (s.str())
- BaseExc & operator = (std::stringstream &s);
+ IEX_EXPORT BaseExc & assign (std::stringstream &s); // assign (s.str())
+ IEX_EXPORT BaseExc & operator = (std::stringstream &s);
- BaseExc & append (std::stringstream &s); // append (s.str())
- BaseExc & operator += (std::stringstream &s);
+ IEX_EXPORT BaseExc & append (std::stringstream &s); // append (s.str())
+ IEX_EXPORT BaseExc & operator += (std::stringstream &s);
//--------------------------------------------------
// the definitions above.
//--------------------------------------------------
- BaseExc & assign (const char *s);
- BaseExc & operator = (const char *s);
+ IEX_EXPORT BaseExc & assign (const char *s);
+ IEX_EXPORT BaseExc & operator = (const char *s);
- BaseExc & append (const char *s);
- BaseExc & operator += (const char *s);
+ IEX_EXPORT BaseExc & append (const char *s);
+ IEX_EXPORT BaseExc & operator += (const char *s);
+ //---------------------------------------------------
+ // Access to the string representation of the message
+ //---------------------------------------------------
+
+ IEX_EXPORT const std::string & message () const;
//--------------------------------------------------
// Stack trace for the point at which the exception
// has been installed (see below, setStackTracer()).
//--------------------------------------------------
- const std::string & stackTrace () const;
+ IEX_EXPORT const std::string & stackTrace () const;
private:
- std::string _stackTrace;
+ std::string _message;
+ std::string _stackTrace;
};
// class derived directly or indirectly from BaseExc:
//-----------------------------------------------------
-#define DEFINE_EXC(name, base) \
- class name: public base \
- { \
- public: \
- name (const char* text=0) throw(): base (text) {} \
- name (const std::string &text) throw(): base (text) {} \
- name (std::stringstream &text) throw(): base (text) {} \
+#define DEFINE_EXC_EXP(exp, name, base) \
+ class name: public base \
+ { \
+ public: \
+ exp name() throw(): base (0) {} \
+ exp name (const char* text) throw(): base (text) {} \
+ exp name (const std::string &text) throw(): base (text) {} \
+ exp name (std::stringstream &text) throw(): base (text) {} \
+ exp ~name() throw() { } \
};
+// For backward compatibility.
+#define DEFINE_EXC(name, base) DEFINE_EXC_EXP(, name, base)
+
//--------------------------------------------------------
// Some exceptions which should be useful in most programs
//--------------------------------------------------------
+DEFINE_EXC_EXP (IEX_EXPORT, ArgExc, BaseExc) // Invalid arguments to a function call
-DEFINE_EXC (ArgExc, BaseExc) // Invalid arguments to a function call
+DEFINE_EXC_EXP (IEX_EXPORT, LogicExc, BaseExc) // General error in a program's logic,
+ // for example, a function was called
+ // in a context where the call does
+ // not make sense.
-DEFINE_EXC (LogicExc, BaseExc) // General error in a program's logic,
- // for example, a function was called
- // in a context where the call does
- // not make sense.
+DEFINE_EXC_EXP (IEX_EXPORT, InputExc, BaseExc) // Invalid input data, e.g. from a file
-DEFINE_EXC (InputExc, BaseExc) // Invalid input data, e.g. from a file
+DEFINE_EXC_EXP (IEX_EXPORT, IoExc, BaseExc) // Input or output operation failed
-DEFINE_EXC (IoExc, BaseExc) // Input or output operation failed
+DEFINE_EXC_EXP (IEX_EXPORT, MathExc, BaseExc) // Arithmetic exception; more specific
+ // exceptions derived from this class
+ // are defined in ExcMath.h
-DEFINE_EXC (MathExc, BaseExc) // Arithmetic exception; more specific
- // exceptions derived from this class
- // are defined in ExcMath.h
+DEFINE_EXC_EXP (IEX_EXPORT, ErrnoExc, BaseExc) // Base class for exceptions corresponding
+ // to errno values (see errno.h); more
+ // specific exceptions derived from this
+ // class are defined in ExcErrno.h
-DEFINE_EXC (ErrnoExc, BaseExc) // Base class for exceptions corresponding
- // to errno values (see errno.h); more
- // specific exceptions derived from this
- // class are defined in ExcErrno.h
+DEFINE_EXC_EXP (IEX_EXPORT, NoImplExc, BaseExc) // Missing method exception e.g. from a
+ // call to a method that is only partially
+ // or not at all implemented. A reminder
+ // to lazy software people to get back
+ // to work.
-DEFINE_EXC (NoImplExc, BaseExc) // Missing method exception e.g. from a
- // call to a method that is only partially
- // or not at all implemented. A reminder
- // to lazy software people to get back
- // to work.
+DEFINE_EXC_EXP (IEX_EXPORT, NullExc, BaseExc) // A pointer is inappropriately null.
-DEFINE_EXC (NullExc, BaseExc) // A pointer is inappropriately null.
-
-DEFINE_EXC (TypeExc, BaseExc) // An object is an inappropriate type,
- // i.e. a dynamnic_cast failed.
+DEFINE_EXC_EXP (IEX_EXPORT, TypeExc, BaseExc) // An object is an inappropriate type,
+ // i.e. a dynamnic_cast failed.
//----------------------------------------------------------------------
// Stack-tracing support:
-//
+//
// setStackTracer(st)
//
// installs a stack-tracing routine, st, which will be called from
//
// returns a pointer to the current stack-tracing routine, or 0
// if there is no current stack stack-tracing routine.
-//
+//
//----------------------------------------------------------------------
typedef std::string (* StackTracer) ();
-void setStackTracer (StackTracer stackTracer);
-StackTracer stackTracer ();
-
-
-//-----------------
-// Inline functions
-//-----------------
-
-inline BaseExc &
-BaseExc::operator = (std::stringstream &s)
-{
- return assign (s);
-}
-
-
-inline BaseExc &
-BaseExc::operator += (std::stringstream &s)
-{
- return append (s);
-}
-
-
-inline BaseExc &
-BaseExc::assign (const char *s)
-{
- std::string::assign(s);
- return *this;
-}
-
-
-inline BaseExc &
-BaseExc::operator = (const char *s)
-{
- return assign(s);
-}
-
-
-inline BaseExc &
-BaseExc::append (const char *s)
-{
- std::string::append(s);
- return *this;
-}
-
-
-inline BaseExc &
-BaseExc::operator += (const char *s)
-{
- return append(s);
-}
-
-
-inline const std::string &
-BaseExc::stackTrace () const
-{
- return _stackTrace;
-}
+IEX_EXPORT void setStackTracer (StackTracer stackTracer);
+IEX_EXPORT StackTracer stackTracer ();
-#if (defined _WIN32 || defined _WIN64) && defined _MSC_VER
-#pragma warning(default:4290)
-#endif
-} // namespace Iex
+IEX_INTERNAL_NAMESPACE_HEADER_EXIT
-#endif
+#endif // INCLUDED_IEXBASEEXC_H
///////////////////////////////////////////////////////////////////////////
//
-// Copyright (c) 2002, Industrial Light & Magic, a division of Lucas
+// Copyright (c) 2002-2012, Industrial Light & Magic, a division of Lucas
// Digital Ltd. LLC
-//
+//
// All rights reserved.
-//
+//
// Redistribution and use in source and binary forms, with or without
// modification, are permitted provided that the following conditions are
// met:
// distribution.
// * Neither the name of Industrial Light & Magic nor the names of
// its contributors may be used to endorse or promote products derived
-// from this software without specific prior written permission.
-//
+// from this software without specific prior written permission.
+//
// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
#include "IexBaseExc.h"
-namespace Iex {
-
+IEX_INTERNAL_NAMESPACE_HEADER_ENTER
DEFINE_EXC (EpermExc, ErrnoExc)
DEFINE_EXC (EnoentExc, ErrnoExc)
DEFINE_EXC (EinvaltimeExc, ErrnoExc)
DEFINE_EXC (EdestroyedExc, ErrnoExc)
-
-} // namespace Iex
+IEX_INTERNAL_NAMESPACE_HEADER_EXIT
#endif
--- /dev/null
+#ifndef IEXEXPORT_H
+#define IEXEXPORT_H
+
+///////////////////////////////////////////////////////////////////////////
+//
+// Copyright (c) 2012, Industrial Light & Magic, a division of Lucas
+// Digital Ltd. LLC
+//
+// All rights reserved.
+//
+// Redistribution and use in source and binary forms, with or without
+// modification, are permitted provided that the following conditions are
+// met:
+// * Redistributions of source code must retain the above copyright
+// notice, this list of conditions and the following disclaimer.
+// * Redistributions in binary form must reproduce the above
+// copyright notice, this list of conditions and the following disclaimer
+// in the documentation and/or other materials provided with the
+// distribution.
+// * Neither the name of Industrial Light & Magic nor the names of
+// its contributors may be used to endorse or promote products derived
+// from this software without specific prior written permission.
+//
+// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+//
+///////////////////////////////////////////////////////////////////////////
+
+#if defined(OPENEXR_DLL)
+ #if defined(IEX_EXPORTS)
+ #define IEX_EXPORT __declspec(dllexport)
+ #else
+ #define IEX_EXPORT __declspec(dllimport)
+ #endif
+ #define IEX_EXPORT_CONST
+#else
+ #define IEX_EXPORT
+ #define IEX_EXPORT_CONST const
+#endif
+
+#endif // #ifndef IEXEXPORT_H
+
--- /dev/null
+///////////////////////////////////////////////////////////////////////////
+//
+// Copyright (c) 2012, Industrial Light & Magic, a division of Lucas
+// Digital Ltd. LLC
+//
+// All rights reserved.
+//
+// Redistribution and use in source and binary forms, with or without
+// modification, are permitted provided that the following conditions are
+// met:
+// * Redistributions of source code must retain the above copyright
+// notice, this list of conditions and the following disclaimer.
+// * Redistributions in binary form must reproduce the above
+// copyright notice, this list of conditions and the following disclaimer
+// in the documentation and/or other materials provided with the
+// distribution.
+// * Neither the name of Industrial Light & Magic nor the names of
+// its contributors may be used to endorse or promote products derived
+// from this software without specific prior written permission.
+//
+// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+//
+///////////////////////////////////////////////////////////////////////////
+
+#ifndef INCLUDED_IEXFORWARD_H
+#define INCLUDED_IEXFORWARD_H
+
+#include "IexNamespace.h"
+
+IEX_INTERNAL_NAMESPACE_HEADER_ENTER
+
+//
+// Base exceptions.
+//
+
+class BaseExc;
+class ArgExc;
+class LogicExc;
+class InputExc;
+class IoExc;
+class MathExc;
+class ErrnoExc;
+class NoImplExc;
+class NullExc;
+class TypeExc;
+
+//
+// Math exceptions.
+//
+
+class OverflowExc;
+class UnderflowExc;
+class DivzeroExc;
+class InexactExc;
+class InvalidFpOpExc;
+
+//
+// Errno exceptions.
+//
+
+class EpermExc;
+class EnoentExc;
+class EsrchExc;
+class EintrExc;
+class EioExc;
+class EnxioExc;
+class E2bigExc;
+class EnoexecExc;
+class EbadfExc;
+class EchildExc;
+class EagainExc;
+class EnomemExc;
+class EaccesExc;
+class EfaultExc;
+class EnotblkExc;
+class EbusyExc;
+class EexistExc;
+class ExdevExc;
+class EnodevExc;
+class EnotdirExc;
+class EisdirExc;
+class EinvalExc;
+class EnfileExc;
+class EmfileExc;
+class EnottyExc;
+class EtxtbsyExc;
+class EfbigExc;
+class EnospcExc;
+class EspipeExc;
+class ErofsExc;
+class EmlinkExc;
+class EpipeExc;
+class EdomExc;
+class ErangeExc;
+class EnomsgExc;
+class EidrmExc;
+class EchrngExc;
+class El2nsyncExc;
+class El3hltExc;
+class El3rstExc;
+class ElnrngExc;
+class EunatchExc;
+class EnocsiExc;
+class El2hltExc;
+class EdeadlkExc;
+class EnolckExc;
+class EbadeExc;
+class EbadrExc;
+class ExfullExc;
+class EnoanoExc;
+class EbadrqcExc;
+class EbadsltExc;
+class EdeadlockExc;
+class EbfontExc;
+class EnostrExc;
+class EnodataExc;
+class EtimeExc;
+class EnosrExc;
+class EnonetExc;
+class EnopkgExc;
+class EremoteExc;
+class EnolinkExc;
+class EadvExc;
+class EsrmntExc;
+class EcommExc;
+class EprotoExc;
+class EmultihopExc;
+class EbadmsgExc;
+class EnametoolongExc;
+class EoverflowExc;
+class EnotuniqExc;
+class EbadfdExc;
+class EremchgExc;
+class ElibaccExc;
+class ElibbadExc;
+class ElibscnExc;
+class ElibmaxExc;
+class ElibexecExc;
+class EilseqExc;
+class EnosysExc;
+class EloopExc;
+class ErestartExc;
+class EstrpipeExc;
+class EnotemptyExc;
+class EusersExc;
+class EnotsockExc;
+class EdestaddrreqExc;
+class EmsgsizeExc;
+class EprototypeExc;
+class EnoprotooptExc;
+class EprotonosupportExc;
+class EsocktnosupportExc;
+class EopnotsuppExc;
+class EpfnosupportExc;
+class EafnosupportExc;
+class EaddrinuseExc;
+class EaddrnotavailExc;
+class EnetdownExc;
+class EnetunreachExc;
+class EnetresetExc;
+class EconnabortedExc;
+class EconnresetExc;
+class EnobufsExc;
+class EisconnExc;
+class EnotconnExc;
+class EshutdownExc;
+class EtoomanyrefsExc;
+class EtimedoutExc;
+class EconnrefusedExc;
+class EhostdownExc;
+class EhostunreachExc;
+class EalreadyExc;
+class EinprogressExc;
+class EstaleExc;
+class EioresidExc;
+class EucleanExc;
+class EnotnamExc;
+class EnavailExc;
+class EisnamExc;
+class EremoteioExc;
+class EinitExc;
+class EremdevExc;
+class EcanceledExc;
+class EnolimfileExc;
+class EproclimExc;
+class EdisjointExc;
+class EnologinExc;
+class EloginlimExc;
+class EgrouploopExc;
+class EnoattachExc;
+class EnotsupExc;
+class EnoattrExc;
+class EdircorruptedExc;
+class EdquotExc;
+class EnfsremoteExc;
+class EcontrollerExc;
+class EnotcontrollerExc;
+class EenqueuedExc;
+class EnotenqueuedExc;
+class EjoinedExc;
+class EnotjoinedExc;
+class EnoprocExc;
+class EmustrunExc;
+class EnotstoppedExc;
+class EclockcpuExc;
+class EinvalstateExc;
+class EnoexistExc;
+class EendofminorExc;
+class EbufsizeExc;
+class EemptyExc;
+class EnointrgroupExc;
+class EinvalmodeExc;
+class EcantextentExc;
+class EinvaltimeExc;
+class EdestroyedExc;
+
+IEX_INTERNAL_NAMESPACE_HEADER_EXIT
+
+#endif // INCLUDED_IEXFORWARD_H
///////////////////////////////////////////////////////////////////////////
//
-// Copyright (c) 2002, Industrial Light & Magic, a division of Lucas
+// Copyright (c) 2002-2018, Industrial Light & Magic, a division of Lucas
// Digital Ltd. LLC
-//
+//
// All rights reserved.
-//
+//
// Redistribution and use in source and binary forms, with or without
// modification, are permitted provided that the following conditions are
// met:
// distribution.
// * Neither the name of Industrial Light & Magic nor the names of
// its contributors may be used to endorse or promote products derived
-// from this software without specific prior written permission.
-//
+// from this software without specific prior written permission.
+//
// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
// Example:
//
// THROW (InputExc, "Syntax error in line " << line ", " << file << ".");
-//
+//
//----------------------------------------------------------------------------
-#define THROW(type, text) \
- do \
- { \
- std::stringstream s; \
- s << text; \
- throw type (s); \
- } \
+#include "IexExport.h"
+#include "IexForward.h"
+
+IEX_EXPORT void iex_debugTrap();
+
+#define THROW(type, text) \
+ do \
+ { \
+ iex_debugTrap(); \
+ std::stringstream _iex_throw_s; \
+ _iex_throw_s << text; \
+ throw type (_iex_throw_s); \
+ } \
while (0)
// }
//----------------------------------------------------------------------------
-#define APPEND_EXC(exc, text) \
- do \
- { \
- std::stringstream s; \
- s << text; \
- exc.append (s); \
- } \
+#define APPEND_EXC(exc, text) \
+ do \
+ { \
+ std::stringstream _iex_append_s; \
+ _iex_append_s << text; \
+ exc.append (_iex_append_s); \
+ } \
while (0)
-#define REPLACE_EXC(exc, text) \
- do \
- { \
- std::stringstream s; \
- s << text; \
- exc.assign (s); \
- } \
+#define REPLACE_EXC(exc, text) \
+ do \
+ { \
+ std::stringstream _iex_replace_s; \
+ _iex_replace_s << text; \
+ exc.assign (_iex_replace_s); \
+ } \
while (0)
//
//-------------------------------------------------------------
-#define THROW_ERRNO(text) \
- do \
- { \
- std::stringstream s; \
- s << text; \
- ::Iex::throwErrnoExc (s.str()); \
- } \
+#define THROW_ERRNO(text) \
+ do \
+ { \
+ std::stringstream _iex_throw_errno_s; \
+ _iex_throw_errno_s << text; \
+ ::IEX_NAMESPACE::throwErrnoExc (_iex_throw_errno_s.str()); \
+ } \
while (0)
//
// Example:
//
-// ASSERT (ptr != NULL, NullExc, "Null pointer" );
+// ASSERT (ptr != 0, NullExc, "Null pointer" );
//
//-------------------------------------------------------------
#define ASSERT(assertion, type, text) \
do \
{ \
- if ((assertion) == false) \
- THROW (type, text); \
+ if( bool(assertion) == false ) \
+ { \
+ THROW( type, text ); \
+ } \
} \
while (0)
+//-------------------------------------------------------------
+// A macro to throw an IEX_NAMESPACE::LogicExc if an assertion is false,
+// with the text composed from the source code file, line number,
+// and assertion argument text.
+//
+// Example:
+//
+// LOGIC_ASSERT (i < n);
+//
+//-------------------------------------------------------------
+#define LOGIC_ASSERT(assertion) \
+ ASSERT(assertion, \
+ IEX_NAMESPACE::LogicExc, \
+ __FILE__ << "(" << __LINE__ << "): logical assertion failed: " << #assertion )
#endif
///////////////////////////////////////////////////////////////////////////
//
-// Copyright (c) 2002, Industrial Light & Magic, a division of Lucas
+// Copyright (c) 2002-2012, Industrial Light & Magic, a division of Lucas
// Digital Ltd. LLC
-//
+//
// All rights reserved.
-//
+//
// Redistribution and use in source and binary forms, with or without
// modification, are permitted provided that the following conditions are
// met:
// distribution.
// * Neither the name of Industrial Light & Magic nor the names of
// its contributors may be used to endorse or promote products derived
-// from this software without specific prior written permission.
-//
+// from this software without specific prior written permission.
+//
// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
#include "IexBaseExc.h"
-namespace Iex {
+IEX_INTERNAL_NAMESPACE_HEADER_ENTER
//---------------------------------------------------------
// Exception classess which correspond to specific floating
DEFINE_EXC (InexactExc, MathExc) // Inexact result
DEFINE_EXC (InvalidFpOpExc, MathExc) // Invalid operation
+IEX_INTERNAL_NAMESPACE_HEADER_EXIT
-} // namespace Iex
-
-#endif
+#endif // INCLUDED_IEXMATHEXC_H
--- /dev/null
+///////////////////////////////////////////////////////////////////////////
+//
+// Copyright (c) 2012, Industrial Light & Magic, a division of Lucas
+// Digital Ltd. LLC
+//
+// All rights reserved.
+//
+// Redistribution and use in source and binary forms, with or without
+// modification, are permitted provided that the following conditions are
+// met:
+// * Redistributions of source code must retain the above copyright
+// notice, this list of conditions and the following disclaimer.
+// * Redistributions in binary form must reproduce the above
+// copyright notice, this list of conditions and the following disclaimer
+// in the documentation and/or other materials provided with the
+// distribution.
+// * Neither the name of Industrial Light & Magic nor the names of
+// its contributors may be used to endorse or promote products derived
+// from this software without specific prior written permission.
+//
+// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+//
+///////////////////////////////////////////////////////////////////////////
+
+#ifndef INCLUDED_IEXNAMESPACE_H
+#define INCLUDED_IEXNAMESPACE_H
+
+//
+// The purpose of this file is to make it possible to specify an
+// IEX_INTERNAL_NAMESPACE as a preprocessor definition and have all of the
+// Iex symbols defined within that namespace rather than the standard
+// Iex namespace. Those symbols are made available to client code through
+// the IEX_NAMESPACE in addition to the IEX_INTERNAL_NAMESPACE.
+//
+// To ensure source code compatibility, the IEX_NAMESPACE defaults to Iex
+// and then "using namespace IEX_INTERNAL_NAMESPACE;" brings all of the
+// declarations from the IEX_INTERNAL_NAMESPACE into the IEX_NAMESPACE. This
+// means that client code can continue to use syntax like Iex::BaseExc, but
+// at link time it will resolve to a mangled symbol based on the
+// IEX_INTERNAL_NAMESPACE.
+//
+// As an example, if one needed to build against a newer version of Iex and
+// have it run alongside an older version in the same application, it is now
+// possible to use an internal namespace to prevent collisions between the
+// older versions of Iex symbols and the newer ones. To do this, the
+// following could be defined at build time:
+//
+// IEX_INTERNAL_NAMESPACE = Iex_v2
+//
+// This means that declarations inside Iex headers look like this (after the
+// preprocessor has done its work):
+//
+// namespace Iex_v2 {
+// ...
+// class declarations
+// ...
+// }
+//
+// namespace Iex {
+// using namespace Iex_v2;
+// }
+//
+
+//
+// Open Source version of this file pulls in the IlmBaseConfig.h file
+// for the configure time options.
+//
+#include "IlmBaseConfig.h"
+
+#ifndef IEX_NAMESPACE
+#define IEX_NAMESPACE Iex
+#endif
+
+#ifndef IEX_INTERNAL_NAMESPACE
+#define IEX_INTERNAL_NAMESPACE IEX_NAMESPACE
+#endif
+
+//
+// We need to be sure that we import the internal namespace into the public one.
+// To do this, we use the small bit of code below which initially defines
+// IEX_INTERNAL_NAMESPACE (so it can be referenced) and then defines
+// IEX_NAMESPACE and pulls the internal symbols into the public namespace.
+//
+
+namespace IEX_INTERNAL_NAMESPACE {}
+namespace IEX_NAMESPACE {
+ using namespace IEX_INTERNAL_NAMESPACE;
+}
+
+//
+// There are identical pairs of HEADER/SOURCE ENTER/EXIT macros so that
+// future extension to the namespace mechanism is possible without changing
+// project source code.
+//
+
+#define IEX_INTERNAL_NAMESPACE_HEADER_ENTER namespace IEX_INTERNAL_NAMESPACE {
+#define IEX_INTERNAL_NAMESPACE_HEADER_EXIT }
+
+#define IEX_INTERNAL_NAMESPACE_SOURCE_ENTER namespace IEX_INTERNAL_NAMESPACE {
+#define IEX_INTERNAL_NAMESPACE_SOURCE_EXIT }
+
+#endif // INCLUDED_IEXNAMESPACE_H
///////////////////////////////////////////////////////////////////////////
//
-// Copyright (c) 2002, Industrial Light & Magic, a division of Lucas
+// Copyright (c) 2002-2012, Industrial Light & Magic, a division of Lucas
// Digital Ltd. LLC
-//
+//
// All rights reserved.
-//
+//
// Redistribution and use in source and binary forms, with or without
// modification, are permitted provided that the following conditions are
// met:
// distribution.
// * Neither the name of Industrial Light & Magic nor the names of
// its contributors may be used to endorse or promote products derived
-// from this software without specific prior written permission.
-//
+// from this software without specific prior written permission.
+//
// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
#include <string.h>
#include <errno.h>
-namespace Iex {
+#ifdef PLATFORM_WINDOWS
+#include <windows.h>
+#endif
+
+IEX_INTERNAL_NAMESPACE_SOURCE_ENTER
void throwErrnoExc (const std::string &text, int errnum)
{
+#ifdef PLATFORM_WINDOWS
+ if (0 != getenv("IEXDEBUGTHROW"))
+ DebugBreak();
+#endif
+
const char *entext = strerror (errnum);
std::string tmp (text);
std::string::size_type pos;
while (std::string::npos != (pos = tmp.find ("%T")))
- tmp.replace (pos, 2, entext, strlen (entext));
+ tmp.replace (pos, 2, entext, strlen (entext));
switch (errnum)
{
#if defined (EPERM)
- case EPERM:
- throw EpermExc (tmp);
+ case EPERM:
+ throw EpermExc (tmp);
#endif
#if defined (ENOENT)
- case ENOENT:
- throw EnoentExc (tmp);
+ case ENOENT:
+ throw EnoentExc (tmp);
#endif
#if defined (ESRCH)
- case ESRCH:
- throw EsrchExc (tmp);
+ case ESRCH:
+ throw EsrchExc (tmp);
#endif
#if defined (EINTR)
- case EINTR:
- throw EintrExc (tmp);
+ case EINTR:
+ throw EintrExc (tmp);
#endif
#if defined (EIO)
- case EIO:
- throw EioExc (tmp);
+ case EIO:
+ throw EioExc (tmp);
#endif
#if defined (ENXIO)
- case ENXIO:
- throw EnxioExc (tmp);
+ case ENXIO:
+ throw EnxioExc (tmp);
#endif
#if defined (E2BIG)
- case E2BIG:
- throw E2bigExc (tmp);
+ case E2BIG:
+ throw E2bigExc (tmp);
#endif
#if defined (ENOEXEC)
- case ENOEXEC:
- throw EnoexecExc (tmp);
+ case ENOEXEC:
+ throw EnoexecExc (tmp);
#endif
#if defined (EBADF)
- case EBADF:
- throw EbadfExc (tmp);
+ case EBADF:
+ throw EbadfExc (tmp);
#endif
#if defined (ECHILD)
- case ECHILD:
- throw EchildExc (tmp);
+ case ECHILD:
+ throw EchildExc (tmp);
#endif
#if defined (EAGAIN)
- case EAGAIN:
- throw EagainExc (tmp);
+ case EAGAIN:
+ throw EagainExc (tmp);
#endif
#if defined (ENOMEM)
- case ENOMEM:
- throw EnomemExc (tmp);
+ case ENOMEM:
+ throw EnomemExc (tmp);
#endif
#if defined (EACCES)
- case EACCES:
- throw EaccesExc (tmp);
+ case EACCES:
+ throw EaccesExc (tmp);
#endif
#if defined (EFAULT)
- case EFAULT:
- throw EfaultExc (tmp);
+ case EFAULT:
+ throw EfaultExc (tmp);
#endif
#if defined (ENOTBLK)
- case ENOTBLK:
- throw EnotblkExc (tmp);
+ case ENOTBLK:
+ throw EnotblkExc (tmp);
#endif
#if defined (EBUSY)
- case EBUSY:
- throw EbusyExc (tmp);
+ case EBUSY:
+ throw EbusyExc (tmp);
#endif
#if defined (EEXIST)
- case EEXIST:
- throw EexistExc (tmp);
+ case EEXIST:
+ throw EexistExc (tmp);
#endif
#if defined (EXDEV)
- case EXDEV:
- throw ExdevExc (tmp);
+ case EXDEV:
+ throw ExdevExc (tmp);
#endif
#if defined (ENODEV)
- case ENODEV:
- throw EnodevExc (tmp);
+ case ENODEV:
+ throw EnodevExc (tmp);
#endif
#if defined (ENOTDIR)
- case ENOTDIR:
- throw EnotdirExc (tmp);
+ case ENOTDIR:
+ throw EnotdirExc (tmp);
#endif
#if defined (EISDIR)
- case EISDIR:
- throw EisdirExc (tmp);
+ case EISDIR:
+ throw EisdirExc (tmp);
#endif
#if defined (EINVAL)
- case EINVAL:
- throw EinvalExc (tmp);
+ case EINVAL:
+ throw EinvalExc (tmp);
#endif
#if defined (ENFILE)
- case ENFILE:
- throw EnfileExc (tmp);
+ case ENFILE:
+ throw EnfileExc (tmp);
#endif
#if defined (EMFILE)
- case EMFILE:
- throw EmfileExc (tmp);
+ case EMFILE:
+ throw EmfileExc (tmp);
#endif
#if defined (ENOTTY)
- case ENOTTY:
- throw EnottyExc (tmp);
+ case ENOTTY:
+ throw EnottyExc (tmp);
#endif
#if defined (ETXTBSY)
- case ETXTBSY:
- throw EtxtbsyExc (tmp);
+ case ETXTBSY:
+ throw EtxtbsyExc (tmp);
#endif
#if defined (EFBIG)
- case EFBIG:
- throw EfbigExc (tmp);
+ case EFBIG:
+ throw EfbigExc (tmp);
#endif
#if defined (ENOSPC)
- case ENOSPC:
- throw EnospcExc (tmp);
+ case ENOSPC:
+ throw EnospcExc (tmp);
#endif
#if defined (ESPIPE)
- case ESPIPE:
- throw EspipeExc (tmp);
+ case ESPIPE:
+ throw EspipeExc (tmp);
#endif
#if defined (EROFS)
- case EROFS:
- throw ErofsExc (tmp);
+ case EROFS:
+ throw ErofsExc (tmp);
#endif
#if defined (EMLINK)
- case EMLINK:
- throw EmlinkExc (tmp);
+ case EMLINK:
+ throw EmlinkExc (tmp);
#endif
#if defined (EPIPE)
- case EPIPE:
- throw EpipeExc (tmp);
+ case EPIPE:
+ throw EpipeExc (tmp);
#endif
#if defined (EDOM)
- case EDOM:
- throw EdomExc (tmp);
+ case EDOM:
+ throw EdomExc (tmp);
#endif
#if defined (ERANGE)
- case ERANGE:
- throw ErangeExc (tmp);
+ case ERANGE:
+ throw ErangeExc (tmp);
#endif
#if defined (ENOMSG)
- case ENOMSG:
- throw EnomsgExc (tmp);
+ case ENOMSG:
+ throw EnomsgExc (tmp);
#endif
#if defined (EIDRM)
- case EIDRM:
- throw EidrmExc (tmp);
+ case EIDRM:
+ throw EidrmExc (tmp);
#endif
#if defined (ECHRNG)
- case ECHRNG:
- throw EchrngExc (tmp);
+ case ECHRNG:
+ throw EchrngExc (tmp);
#endif
#if defined (EL2NSYNC)
- case EL2NSYNC:
- throw El2nsyncExc (tmp);
+ case EL2NSYNC:
+ throw El2nsyncExc (tmp);
#endif
#if defined (EL3HLT)
- case EL3HLT:
- throw El3hltExc (tmp);
+ case EL3HLT:
+ throw El3hltExc (tmp);
#endif
#if defined (EL3RST)
- case EL3RST:
- throw El3rstExc (tmp);
+ case EL3RST:
+ throw El3rstExc (tmp);
#endif
#if defined (ELNRNG)
- case ELNRNG:
- throw ElnrngExc (tmp);
+ case ELNRNG:
+ throw ElnrngExc (tmp);
#endif
#if defined (EUNATCH)
- case EUNATCH:
- throw EunatchExc (tmp);
+ case EUNATCH:
+ throw EunatchExc (tmp);
#endif
#if defined (ENOSCI)
- case ENOCSI:
- throw EnocsiExc (tmp);
+ case ENOCSI:
+ throw EnocsiExc (tmp);
#endif
#if defined (EL2HLT)
- case EL2HLT:
- throw El2hltExc (tmp);
+ case EL2HLT:
+ throw El2hltExc (tmp);
#endif
#if defined (EDEADLK)
- case EDEADLK:
- throw EdeadlkExc (tmp);
+ case EDEADLK:
+ throw EdeadlkExc (tmp);
#endif
#if defined (ENOLCK)
- case ENOLCK:
- throw EnolckExc (tmp);
+ case ENOLCK:
+ throw EnolckExc (tmp);
#endif
#if defined (EBADE)
- case EBADE:
- throw EbadeExc (tmp);
+ case EBADE:
+ throw EbadeExc (tmp);
#endif
#if defined (EBADR)
- case EBADR:
- throw EbadrExc (tmp);
+ case EBADR:
+ throw EbadrExc (tmp);
#endif
#if defined (EXFULL)
- case EXFULL:
- throw ExfullExc (tmp);
+ case EXFULL:
+ throw ExfullExc (tmp);
#endif
#if defined (ENOANO)
- case ENOANO:
- throw EnoanoExc (tmp);
+ case ENOANO:
+ throw EnoanoExc (tmp);
#endif
#if defined (EBADRQC)
- case EBADRQC:
- throw EbadrqcExc (tmp);
+ case EBADRQC:
+ throw EbadrqcExc (tmp);
#endif
#if defined (EBADSLT)
- case EBADSLT:
- throw EbadsltExc (tmp);
+ case EBADSLT:
+ throw EbadsltExc (tmp);
#endif
#if defined (EDEADLOCK) && defined (EDEADLK)
- #if EDEADLOCK != EDEADLK
- case EDEADLOCK:
- throw EdeadlockExc (tmp);
- #endif
+ #if EDEADLOCK != EDEADLK
+ case EDEADLOCK:
+ throw EdeadlockExc (tmp);
+ #endif
#elif defined (EDEADLOCK)
- case EDEADLOCK:
- throw EdeadlockExc (tmp);
+ case EDEADLOCK:
+ throw EdeadlockExc (tmp);
#endif
#if defined (EBFONT)
- case EBFONT:
- throw EbfontExc (tmp);
+ case EBFONT:
+ throw EbfontExc (tmp);
#endif
#if defined (ENOSTR)
- case ENOSTR:
- throw EnostrExc (tmp);
+ case ENOSTR:
+ throw EnostrExc (tmp);
#endif
#if defined (ENODATA)
- case ENODATA:
- throw EnodataExc (tmp);
+ case ENODATA:
+ throw EnodataExc (tmp);
#endif
#if defined (ETIME)
- case ETIME:
- throw EtimeExc (tmp);
+ case ETIME:
+ throw EtimeExc (tmp);
#endif
#if defined (ENOSR)
- case ENOSR:
- throw EnosrExc (tmp);
+ case ENOSR:
+ throw EnosrExc (tmp);
#endif
#if defined (ENONET)
- case ENONET:
- throw EnonetExc (tmp);
+ case ENONET:
+ throw EnonetExc (tmp);
#endif
#if defined (ENOPKG)
- case ENOPKG:
- throw EnopkgExc (tmp);
+ case ENOPKG:
+ throw EnopkgExc (tmp);
#endif
#if defined (EREMOTE)
- case EREMOTE:
- throw EremoteExc (tmp);
+ case EREMOTE:
+ throw EremoteExc (tmp);
#endif
#if defined (ENOLINK)
- case ENOLINK:
- throw EnolinkExc (tmp);
+ case ENOLINK:
+ throw EnolinkExc (tmp);
#endif
#if defined (EADV)
- case EADV:
- throw EadvExc (tmp);
+ case EADV:
+ throw EadvExc (tmp);
#endif
#if defined (ESRMNT)
- case ESRMNT:
- throw EsrmntExc (tmp);
+ case ESRMNT:
+ throw EsrmntExc (tmp);
#endif
#if defined (ECOMM)
- case ECOMM:
- throw EcommExc (tmp);
+ case ECOMM:
+ throw EcommExc (tmp);
#endif
#if defined (EPROTO)
- case EPROTO:
- throw EprotoExc (tmp);
+ case EPROTO:
+ throw EprotoExc (tmp);
#endif
#if defined (EMULTIHOP)
- case EMULTIHOP:
- throw EmultihopExc (tmp);
+ case EMULTIHOP:
+ throw EmultihopExc (tmp);
#endif
#if defined (EBADMSG)
- case EBADMSG:
- throw EbadmsgExc (tmp);
+ case EBADMSG:
+ throw EbadmsgExc (tmp);
#endif
#if defined (ENAMETOOLONG)
- case ENAMETOOLONG:
- throw EnametoolongExc (tmp);
+ case ENAMETOOLONG:
+ throw EnametoolongExc (tmp);
#endif
#if defined (EOVERFLOW)
- case EOVERFLOW:
- throw EoverflowExc (tmp);
+ case EOVERFLOW:
+ throw EoverflowExc (tmp);
#endif
#if defined (ENOTUNIQ)
- case ENOTUNIQ:
- throw EnotuniqExc (tmp);
+ case ENOTUNIQ:
+ throw EnotuniqExc (tmp);
#endif
#if defined (EBADFD)
- case EBADFD:
- throw EbadfdExc (tmp);
+ case EBADFD:
+ throw EbadfdExc (tmp);
#endif
#if defined (EREMCHG)
- case EREMCHG:
- throw EremchgExc (tmp);
+ case EREMCHG:
+ throw EremchgExc (tmp);
#endif
#if defined (ELIBACC)
- case ELIBACC:
- throw ElibaccExc (tmp);
+ case ELIBACC:
+ throw ElibaccExc (tmp);
#endif
#if defined (ELIBBAD)
- case ELIBBAD:
- throw ElibbadExc (tmp);
+ case ELIBBAD:
+ throw ElibbadExc (tmp);
#endif
#if defined (ELIBSCN)
- case ELIBSCN:
- throw ElibscnExc (tmp);
+ case ELIBSCN:
+ throw ElibscnExc (tmp);
#endif
#if defined (ELIBMAX)
- case ELIBMAX:
- throw ElibmaxExc (tmp);
+ case ELIBMAX:
+ throw ElibmaxExc (tmp);
#endif
#if defined (ELIBEXEC)
- case ELIBEXEC:
- throw ElibexecExc (tmp);
+ case ELIBEXEC:
+ throw ElibexecExc (tmp);
#endif
#if defined (EILSEQ)
- case EILSEQ:
- throw EilseqExc (tmp);
+ case EILSEQ:
+ throw EilseqExc (tmp);
#endif
#if defined (ENOSYS)
- case ENOSYS:
- throw EnosysExc (tmp);
+ case ENOSYS:
+ throw EnosysExc (tmp);
#endif
#if defined (ELOOP)
- case ELOOP:
- throw EloopExc (tmp);
+ case ELOOP:
+ throw EloopExc (tmp);
#endif
#if defined (ERESTART)
- case ERESTART:
- throw ErestartExc (tmp);
+ case ERESTART:
+ throw ErestartExc (tmp);
#endif
#if defined (ESTRPIPE)
- case ESTRPIPE:
- throw EstrpipeExc (tmp);
+ case ESTRPIPE:
+ throw EstrpipeExc (tmp);
#endif
#if defined (ENOTEMPTY)
- case ENOTEMPTY:
- throw EnotemptyExc (tmp);
+ case ENOTEMPTY:
+ throw EnotemptyExc (tmp);
#endif
#if defined (EUSERS)
- case EUSERS:
- throw EusersExc (tmp);
+ case EUSERS:
+ throw EusersExc (tmp);
#endif
#if defined (ENOTSOCK)
- case ENOTSOCK:
- throw EnotsockExc (tmp);
+ case ENOTSOCK:
+ throw EnotsockExc (tmp);
#endif
#if defined (EDESTADDRREQ)
- case EDESTADDRREQ:
- throw EdestaddrreqExc (tmp);
+ case EDESTADDRREQ:
+ throw EdestaddrreqExc (tmp);
#endif
#if defined (EMSGSIZE)
- case EMSGSIZE:
- throw EmsgsizeExc (tmp);
+ case EMSGSIZE:
+ throw EmsgsizeExc (tmp);
#endif
#if defined (EPROTOTYPE)
- case EPROTOTYPE:
- throw EprototypeExc (tmp);
+ case EPROTOTYPE:
+ throw EprototypeExc (tmp);
#endif
#if defined (ENOPROTOOPT)
- case ENOPROTOOPT:
- throw EnoprotooptExc (tmp);
+ case ENOPROTOOPT:
+ throw EnoprotooptExc (tmp);
#endif
#if defined (EPROTONOSUPPORT)
- case EPROTONOSUPPORT:
- throw EprotonosupportExc (tmp);
+ case EPROTONOSUPPORT:
+ throw EprotonosupportExc (tmp);
#endif
#if defined (ESOCKTNOSUPPORT)
- case ESOCKTNOSUPPORT:
- throw EsocktnosupportExc (tmp);
+ case ESOCKTNOSUPPORT:
+ throw EsocktnosupportExc (tmp);
#endif
#if defined (EOPNOTSUPP)
- case EOPNOTSUPP:
- throw EopnotsuppExc (tmp);
+ case EOPNOTSUPP:
+ throw EopnotsuppExc (tmp);
#endif
#if defined (EPFNOSUPPORT)
- case EPFNOSUPPORT:
- throw EpfnosupportExc (tmp);
+ case EPFNOSUPPORT:
+ throw EpfnosupportExc (tmp);
#endif
#if defined (EAFNOSUPPORT)
- case EAFNOSUPPORT:
- throw EafnosupportExc (tmp);
+ case EAFNOSUPPORT:
+ throw EafnosupportExc (tmp);
#endif
#if defined (EADDRINUSE)
- case EADDRINUSE:
- throw EaddrinuseExc (tmp);
+ case EADDRINUSE:
+ throw EaddrinuseExc (tmp);
#endif
#if defined (EADDRNOTAVAIL)
- case EADDRNOTAVAIL:
- throw EaddrnotavailExc (tmp);
+ case EADDRNOTAVAIL:
+ throw EaddrnotavailExc (tmp);
#endif
#if defined (ENETDOWN)
- case ENETDOWN:
- throw EnetdownExc (tmp);
+ case ENETDOWN:
+ throw EnetdownExc (tmp);
#endif
#if defined (ENETUNREACH)
- case ENETUNREACH:
- throw EnetunreachExc (tmp);
+ case ENETUNREACH:
+ throw EnetunreachExc (tmp);
#endif
#if defined (ENETRESET)
- case ENETRESET:
- throw EnetresetExc (tmp);
+ case ENETRESET:
+ throw EnetresetExc (tmp);
#endif
#if defined (ECONNABORTED)
- case ECONNABORTED:
- throw EconnabortedExc (tmp);
+ case ECONNABORTED:
+ throw EconnabortedExc (tmp);
#endif
#if defined (ECONNRESET)
- case ECONNRESET:
- throw EconnresetExc (tmp);
+ case ECONNRESET:
+ throw EconnresetExc (tmp);
#endif
#if defined (ENOBUFS)
- case ENOBUFS:
- throw EnobufsExc (tmp);
+ case ENOBUFS:
+ throw EnobufsExc (tmp);
#endif
#if defined (EISCONN)
- case EISCONN:
- throw EisconnExc (tmp);
+ case EISCONN:
+ throw EisconnExc (tmp);
#endif
#if defined (ENOTCONN)
- case ENOTCONN:
- throw EnotconnExc (tmp);
+ case ENOTCONN:
+ throw EnotconnExc (tmp);
#endif
#if defined (ESHUTDOWN)
- case ESHUTDOWN:
- throw EshutdownExc (tmp);
+ case ESHUTDOWN:
+ throw EshutdownExc (tmp);
#endif
#if defined (ETOOMANYREFS)
- case ETOOMANYREFS:
- throw EtoomanyrefsExc (tmp);
+ case ETOOMANYREFS:
+ throw EtoomanyrefsExc (tmp);
#endif
#if defined (ETIMEDOUT)
- case ETIMEDOUT:
- throw EtimedoutExc (tmp);
+ case ETIMEDOUT:
+ throw EtimedoutExc (tmp);
#endif
#if defined (ECONNREFUSED)
- case ECONNREFUSED:
- throw EconnrefusedExc (tmp);
+ case ECONNREFUSED:
+ throw EconnrefusedExc (tmp);
#endif
#if defined (EHOSTDOWN)
- case EHOSTDOWN:
- throw EhostdownExc (tmp);
+ case EHOSTDOWN:
+ throw EhostdownExc (tmp);
#endif
#if defined (EHOSTUNREACH)
- case EHOSTUNREACH:
- throw EhostunreachExc (tmp);
+ case EHOSTUNREACH:
+ throw EhostunreachExc (tmp);
#endif
#if defined (EALREADY)
- case EALREADY:
- throw EalreadyExc (tmp);
+ case EALREADY:
+ throw EalreadyExc (tmp);
#endif
#if defined (EINPROGRESS)
- case EINPROGRESS:
- throw EinprogressExc (tmp);
+ case EINPROGRESS:
+ throw EinprogressExc (tmp);
#endif
#if defined (ESTALE)
- case ESTALE:
- throw EstaleExc (tmp);
+ case ESTALE:
+ throw EstaleExc (tmp);
#endif
#if defined (EIORESID)
- case EIORESID:
- throw EioresidExc (tmp);
+ case EIORESID:
+ throw EioresidExc (tmp);
#endif
#if defined (EUCLEAN)
- case EUCLEAN:
- throw EucleanExc (tmp);
+ case EUCLEAN:
+ throw EucleanExc (tmp);
#endif
#if defined (ENOTNAM)
- case ENOTNAM:
- throw EnotnamExc (tmp);
+ case ENOTNAM:
+ throw EnotnamExc (tmp);
#endif
#if defined (ENAVAIL)
- case ENAVAIL:
- throw EnavailExc (tmp);
+ case ENAVAIL:
+ throw EnavailExc (tmp);
#endif
#if defined (EISNAM)
- case EISNAM:
- throw EisnamExc (tmp);
+ case EISNAM:
+ throw EisnamExc (tmp);
#endif
#if defined (EREMOTEIO)
- case EREMOTEIO:
- throw EremoteioExc (tmp);
+ case EREMOTEIO:
+ throw EremoteioExc (tmp);
#endif
#if defined (EINIT)
- case EINIT:
- throw EinitExc (tmp);
+ case EINIT:
+ throw EinitExc (tmp);
#endif
#if defined (EREMDEV)
- case EREMDEV:
- throw EremdevExc (tmp);
+ case EREMDEV:
+ throw EremdevExc (tmp);
#endif
#if defined (ECANCELED)
- case ECANCELED:
- throw EcanceledExc (tmp);
+ case ECANCELED:
+ throw EcanceledExc (tmp);
#endif
#if defined (ENOLIMFILE)
- case ENOLIMFILE:
- throw EnolimfileExc (tmp);
+ case ENOLIMFILE:
+ throw EnolimfileExc (tmp);
#endif
#if defined (EPROCLIM)
- case EPROCLIM:
- throw EproclimExc (tmp);
+ case EPROCLIM:
+ throw EproclimExc (tmp);
#endif
#if defined (EDISJOINT)
- case EDISJOINT:
- throw EdisjointExc (tmp);
+ case EDISJOINT:
+ throw EdisjointExc (tmp);
#endif
#if defined (ENOLOGIN)
- case ENOLOGIN:
- throw EnologinExc (tmp);
+ case ENOLOGIN:
+ throw EnologinExc (tmp);
#endif
#if defined (ELOGINLIM)
- case ELOGINLIM:
- throw EloginlimExc (tmp);
+ case ELOGINLIM:
+ throw EloginlimExc (tmp);
#endif
#if defined (EGROUPLOOP)
- case EGROUPLOOP:
- throw EgrouploopExc (tmp);
+ case EGROUPLOOP:
+ throw EgrouploopExc (tmp);
#endif
#if defined (ENOATTACH)
- case ENOATTACH:
- throw EnoattachExc (tmp);
+ case ENOATTACH:
+ throw EnoattachExc (tmp);
#endif
#if defined (ENOTSUP) && defined (EOPNOTSUPP)
- #if ENOTSUP != EOPNOTSUPP
- case ENOTSUP:
- throw EnotsupExc (tmp);
- #endif
+ #if ENOTSUP != EOPNOTSUPP
+ case ENOTSUP:
+ throw EnotsupExc (tmp);
+ #endif
#elif defined (ENOTSUP)
- case ENOTSUP:
- throw EnotsupExc (tmp);
+ case ENOTSUP:
+ throw EnotsupExc (tmp);
#endif
#if defined (ENOATTR)
- case ENOATTR:
- throw EnoattrExc (tmp);
+ case ENOATTR:
+ throw EnoattrExc (tmp);
#endif
#if defined (EDIRCORRUPTED)
- case EDIRCORRUPTED:
- throw EdircorruptedExc (tmp);
+ case EDIRCORRUPTED:
+ throw EdircorruptedExc (tmp);
#endif
#if defined (EDQUOT)
- case EDQUOT:
- throw EdquotExc (tmp);
+ case EDQUOT:
+ throw EdquotExc (tmp);
#endif
#if defined (ENFSREMOTE)
- case ENFSREMOTE:
- throw EnfsremoteExc (tmp);
+ case ENFSREMOTE:
+ throw EnfsremoteExc (tmp);
#endif
#if defined (ECONTROLLER)
- case ECONTROLLER:
- throw EcontrollerExc (tmp);
+ case ECONTROLLER:
+ throw EcontrollerExc (tmp);
#endif
#if defined (ENOTCONTROLLER)
- case ENOTCONTROLLER:
- throw EnotcontrollerExc (tmp);
+ case ENOTCONTROLLER:
+ throw EnotcontrollerExc (tmp);
#endif
#if defined (EENQUEUED)
- case EENQUEUED:
- throw EenqueuedExc (tmp);
+ case EENQUEUED:
+ throw EenqueuedExc (tmp);
#endif
#if defined (ENOTENQUEUED)
- case ENOTENQUEUED:
- throw EnotenqueuedExc (tmp);
+ case ENOTENQUEUED:
+ throw EnotenqueuedExc (tmp);
#endif
#if defined (EJOINED)
- case EJOINED:
- throw EjoinedExc (tmp);
+ case EJOINED:
+ throw EjoinedExc (tmp);
#endif
#if defined (ENOTJOINED)
- case ENOTJOINED:
- throw EnotjoinedExc (tmp);
+ case ENOTJOINED:
+ throw EnotjoinedExc (tmp);
#endif
#if defined (ENOPROC)
- case ENOPROC:
- throw EnoprocExc (tmp);
+ case ENOPROC:
+ throw EnoprocExc (tmp);
#endif
#if defined (EMUSTRUN)
- case EMUSTRUN:
- throw EmustrunExc (tmp);
+ case EMUSTRUN:
+ throw EmustrunExc (tmp);
#endif
#if defined (ENOTSTOPPED)
- case ENOTSTOPPED:
- throw EnotstoppedExc (tmp);
+ case ENOTSTOPPED:
+ throw EnotstoppedExc (tmp);
#endif
#if defined (ECLOCKCPU)
- case ECLOCKCPU:
- throw EclockcpuExc (tmp);
+ case ECLOCKCPU:
+ throw EclockcpuExc (tmp);
#endif
#if defined (EINVALSTATE)
- case EINVALSTATE:
- throw EinvalstateExc (tmp);
+ case EINVALSTATE:
+ throw EinvalstateExc (tmp);
#endif
#if defined (ENOEXIST)
- case ENOEXIST:
- throw EnoexistExc (tmp);
+ case ENOEXIST:
+ throw EnoexistExc (tmp);
#endif
#if defined (EENDOFMINOR)
- case EENDOFMINOR:
- throw EendofminorExc (tmp);
+ case EENDOFMINOR:
+ throw EendofminorExc (tmp);
#endif
#if defined (EBUFSIZE)
- case EBUFSIZE:
- throw EbufsizeExc (tmp);
+ case EBUFSIZE:
+ throw EbufsizeExc (tmp);
#endif
#if defined (EEMPTY)
- case EEMPTY:
- throw EemptyExc (tmp);
+ case EEMPTY:
+ throw EemptyExc (tmp);
#endif
#if defined (ENOINTRGROUP)
- case ENOINTRGROUP:
- throw EnointrgroupExc (tmp);
+ case ENOINTRGROUP:
+ throw EnointrgroupExc (tmp);
#endif
#if defined (EINVALMODE)
- case EINVALMODE:
- throw EinvalmodeExc (tmp);
+ case EINVALMODE:
+ throw EinvalmodeExc (tmp);
#endif
#if defined (ECANTEXTENT)
- case ECANTEXTENT:
- throw EcantextentExc (tmp);
+ case ECANTEXTENT:
+ throw EcantextentExc (tmp);
#endif
#if defined (EINVALTIME)
- case EINVALTIME:
- throw EinvaltimeExc (tmp);
+ case EINVALTIME:
+ throw EinvaltimeExc (tmp);
#endif
#if defined (EDESTROYED)
- case EDESTROYED:
- throw EdestroyedExc (tmp);
+ case EDESTROYED:
+ throw EdestroyedExc (tmp);
#endif
}
throwErrnoExc (text, errno);
}
+void throwErrnoExc()
+{
+ std::string txt = "%T.";
+ throwErrnoExc (txt);
+}
-} // namespace Iex
+IEX_INTERNAL_NAMESPACE_SOURCE_EXIT
///////////////////////////////////////////////////////////////////////////
//
-// Copyright (c) 2002, Industrial Light & Magic, a division of Lucas
+// Copyright (c) 2002-2012, Industrial Light & Magic, a division of Lucas
// Digital Ltd. LLC
-//
+//
// All rights reserved.
-//
+//
// Redistribution and use in source and binary forms, with or without
// modification, are permitted provided that the following conditions are
// met:
// distribution.
// * Neither the name of Industrial Light & Magic nor the names of
// its contributors may be used to endorse or promote products derived
-// from this software without specific prior written permission.
-//
+// from this software without specific prior written permission.
+//
// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
//----------------------------------------------------------
#include "IexBaseExc.h"
+#include "IexExport.h"
-namespace Iex {
+IEX_INTERNAL_NAMESPACE_HEADER_ENTER
//--------------------------------------------------------------------------
// "%T" have been replaced with the output of strerror(oserror()).
//
// Example:
-//
+//
// If opening file /tmp/output failed with an ENOENT error code,
// calling
//
//
//--------------------------------------------------------------------------
-void throwErrnoExc (const std::string &txt, int errnum);
-void throwErrnoExc (const std::string &txt = "%T." /*, int errnum = oserror() */);
-
+IEX_EXPORT void throwErrnoExc(const std::string &txt, int errnum);
+IEX_EXPORT void throwErrnoExc(const std::string &txt);
+IEX_EXPORT void throwErrnoExc();
-} // namespace Iex
+IEX_INTERNAL_NAMESPACE_HEADER_EXIT
-#endif
+#endif // INCLUDED_IEXTHROWERRNOEXC_H
+#cmakedefine PLATFORM_WINDOWS
+
+//
+// Define and set to 1 if the target system has c++11/14 support
+// and you want IlmBase to NOT use it's features
+//
+
+#cmakedefine01 ILMBASE_FORCE_CXX03
+#if ILMBASE_FORCE_CXX03 == 0
+#undef ILMBASE_FORCE_CXX03
+#endif
+
//
// Define and set to 1 if the target system has POSIX thread support
// and you want IlmBase to use it for multithreaded file I/O.
#cmakedefine01 HAVE_POSIX_SEMAPHORES
-#undef HAVE_UCONTEXT_H
+
+#cmakedefine HAVE_UCONTEXT_H
+
+
+//
+// Dealing with FPEs
+//
+#cmakedefine01 ILMBASE_HAVE_CONTROL_REGISTER_SUPPORT
+
+
+//
+// Define and set to 1 if the target system has support for large
+// stack sizes.
+//
+
+#cmakedefine ILMBASE_HAVE_LARGE_STACK
+
+//
+// Current (internal) library namepace name and corresponding public
+// client namespaces.
+//
+#define ILMBASE_INTERNAL_NAMESPACE_CUSTOM @ILMBASE_INTERNAL_NAMESPACE_CUSTOM@
+#define IMATH_INTERNAL_NAMESPACE @IMATH_INTERNAL_NAMESPACE@
+#define IEX_INTERNAL_NAMESPACE @IEX_INTERNAL_NAMESPACE@
+#define ILMTHREAD_INTERNAL_NAMESPACE @ILMTHREAD_INTERNAL_NAMESPACE@
+
+#define ILMBASE_NAMESPACE_CUSTOM @ILMBASE_NAMESPACE_CUSTOM@
+#define IMATH_NAMESPACE @IMATH_NAMESPACE@
+#define IEX_NAMESPACE @IEX_NAMESPACE@
+#define ILMTHREAD_NAMESPACE @ILMTHREAD_NAMESPACE@
+
//
// Define and set to 1 if the target system has support for large
// stack sizes.
//
-#undef ILMBASE_HAVE_LARGE_STACK
+#cmakedefine ILMBASE_HAVE_LARGE_STACK
//
-// Version string for runtime access
+// Version information
//
-#define ILMBASE_VERSION_STRING "1.0.3"
-#define ILMBASE_PACKAGE_STRING "IlmBase 1.0.3"
+#define ILMBASE_VERSION_STRING @ILMBASE_VERSION_STRING@
+#define ILMBASE_PACKAGE_STRING @ILMBASE_PACKAGE_STRING@
+
+#define ILMBASE_VERSION_MAJOR @ILMBASE_VERSION_MAJOR@
+#define ILMBASE_VERSION_MINOR @ILMBASE_VERSION_MINOR@
+#define ILMBASE_VERSION_PATCH @ILMBASE_VERSION_PATCH@
+
+// Version as a single hex number, e.g. 0x01000300 == 1.0.3
+#define ILMBASE_VERSION_HEX ((ILMBASE_VERSION_MAJOR << 24) | \
+ (ILMBASE_VERSION_MINOR << 16) | \
+ (ILMBASE_VERSION_PATCH << 8))
+
+
//
// Copyright (c) 2007, Industrial Light & Magic, a division of Lucas
// Digital Ltd. LLC
-//
+//
// All rights reserved.
-//
+//
// Redistribution and use in source and binary forms, with or without
// modification, are permitted provided that the following conditions are
// met:
// distribution.
// * Neither the name of Industrial Light & Magic nor the names of
// its contributors may be used to endorse or promote products derived
-// from this software without specific prior written permission.
-//
+// from this software without specific prior written permission.
+//
// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
//-----------------------------------------------------------------------------
//
// ACES image file I/O.
-//
+//
//-----------------------------------------------------------------------------
#include <ImfAcesFile.h>
#include <ImfRgbaFile.h>
#include <ImfStandardAttributes.h>
#include <Iex.h>
-#include <algorithm> // for std::max()
+#include <algorithm>
using namespace std;
-using namespace Imath;
-using namespace Iex;
+using namespace IMATH_NAMESPACE;
+using namespace IEX_NAMESPACE;
+#include "ImfNamespace.h"
-namespace Imf {
+OPENEXR_IMF_INTERNAL_NAMESPACE_SOURCE_ENTER
const Chromaticities &
acesChromaticities ()
{
- static const Chromaticities acesChr
- (V2f (0.73470, 0.26530), // red
- V2f (0.00000, 1.00000), // green
- V2f (0.00010, -0.07700), // blue
- V2f (0.32168, 0.33767)); // white
+ static const Chromaticities acesChr
+ (V2f (0.73470, 0.26530), // red
+ V2f (0.00000, 1.00000), // green
+ V2f (0.00010, -0.07700), // blue
+ V2f (0.32168, 0.33767)); // white
return acesChr;
}
case NO_COMPRESSION:
case PIZ_COMPRESSION:
case B44A_COMPRESSION:
- break;
+ break;
default:
- throw ArgExc ("Invalid compression type for ACES file.");
+ throw ArgExc ("Invalid compression type for ACES file.");
}
}
addAdoptedNeutral (newHeader, acesChromaticities().white);
_data->rgbaFile = new RgbaOutputFile (name.c_str(),
- newHeader,
- rgbaChannels,
- numThreads);
+ newHeader,
+ rgbaChannels,
+ numThreads);
_data->rgbaFile->setYCRounding (7, 6);
}
AcesOutputFile::AcesOutputFile
- (OStream &os,
+ (OPENEXR_IMF_INTERNAL_NAMESPACE::OStream &os,
const Header &header,
RgbaChannels rgbaChannels,
int numThreads)
addAdoptedNeutral (newHeader, acesChromaticities().white);
_data->rgbaFile = new RgbaOutputFile (os,
- header,
- rgbaChannels,
- numThreads);
+ header,
+ rgbaChannels,
+ numThreads);
_data->rgbaFile->setYCRounding (7, 6);
}
AcesOutputFile::AcesOutputFile
(const std::string &name,
- const Imath::Box2i &displayWindow,
- const Imath::Box2i &dataWindow,
+ const IMATH_NAMESPACE::Box2i &displayWindow,
+ const IMATH_NAMESPACE::Box2i &dataWindow,
RgbaChannels rgbaChannels,
float pixelAspectRatio,
- const Imath::V2f screenWindowCenter,
+ const IMATH_NAMESPACE::V2f screenWindowCenter,
float screenWindowWidth,
LineOrder lineOrder,
Compression compression,
checkCompression (compression);
Header newHeader (displayWindow,
- dataWindow.isEmpty()? displayWindow: dataWindow,
- pixelAspectRatio,
- screenWindowCenter,
- screenWindowWidth,
- lineOrder,
- compression);
+ dataWindow.isEmpty()? displayWindow: dataWindow,
+ pixelAspectRatio,
+ screenWindowCenter,
+ screenWindowWidth,
+ lineOrder,
+ compression);
addChromaticities (newHeader, acesChromaticities());
addAdoptedNeutral (newHeader, acesChromaticities().white);
_data->rgbaFile = new RgbaOutputFile (name.c_str(),
- newHeader,
- rgbaChannels,
- numThreads);
+ newHeader,
+ rgbaChannels,
+ numThreads);
_data->rgbaFile->setYCRounding (7, 6);
}
int height,
RgbaChannels rgbaChannels,
float pixelAspectRatio,
- const Imath::V2f screenWindowCenter,
+ const IMATH_NAMESPACE::V2f screenWindowCenter,
float screenWindowWidth,
LineOrder lineOrder,
Compression compression,
checkCompression (compression);
Header newHeader (width,
- height,
- pixelAspectRatio,
- screenWindowCenter,
- screenWindowWidth,
- lineOrder,
- compression);
+ height,
+ pixelAspectRatio,
+ screenWindowCenter,
+ screenWindowWidth,
+ lineOrder,
+ compression);
addChromaticities (newHeader, acesChromaticities());
addAdoptedNeutral (newHeader, acesChromaticities().white);
_data->rgbaFile = new RgbaOutputFile (name.c_str(),
- newHeader,
- rgbaChannels,
- numThreads);
+ newHeader,
+ rgbaChannels,
+ numThreads);
_data->rgbaFile->setYCRounding (7, 6);
}
}
-void
+void
AcesOutputFile::setFrameBuffer
(const Rgba *base,
size_t xStride,
}
-void
+void
AcesOutputFile::writePixels (int numScanLines)
{
_data->rgbaFile->writePixels (numScanLines);
}
-int
+int
AcesOutputFile::currentScanLine () const
{
return _data->rgbaFile->currentScanLine();
}
-const Imath::Box2i &
+const IMATH_NAMESPACE::Box2i &
AcesOutputFile::displayWindow () const
{
return _data->rgbaFile->displayWindow();
}
-const Imath::Box2i &
+const IMATH_NAMESPACE::Box2i &
AcesOutputFile::dataWindow () const
{
return _data->rgbaFile->dataWindow();
}
-float
+float
AcesOutputFile::pixelAspectRatio () const
{
return _data->rgbaFile->pixelAspectRatio();
}
-const Imath::V2f
+const IMATH_NAMESPACE::V2f
AcesOutputFile::screenWindowCenter () const
{
return _data->rgbaFile->screenWindowCenter();
}
-float
+float
AcesOutputFile::screenWindowWidth () const
{
return _data->rgbaFile->screenWindowWidth();
}
-LineOrder
+LineOrder
AcesOutputFile::lineOrder () const
{
return _data->rgbaFile->lineOrder();
}
-Compression
+Compression
AcesOutputFile::compression () const
{
return _data->rgbaFile->compression();
}
-void
+void
AcesOutputFile::updatePreviewImage (const PreviewRgba pixels[])
{
_data->rgbaFile->updatePreviewImage (pixels);
Chromaticities fileChr;
if (hasChromaticities (header))
- fileChr = chromaticities (header);
+ fileChr = chromaticities (header);
V2f fileNeutral = fileChr.white;
if (hasAdoptedNeutral (header))
- fileNeutral = adoptedNeutral (header);
+ fileNeutral = adoptedNeutral (header);
const Chromaticities acesChr = acesChromaticities();
V2f acesNeutral = acesChr.white;
if (fileChr.red == acesChr.red &&
- fileChr.green == acesChr.green &&
- fileChr.blue == acesChr.blue &&
- fileChr.white == acesChr.white &&
- fileNeutral == acesNeutral)
+ fileChr.green == acesChr.green &&
+ fileChr.blue == acesChr.blue &&
+ fileChr.white == acesChr.white &&
+ fileNeutral == acesNeutral)
{
- //
- // The file already contains ACES data,
- // color conversion is not necessary.
+ //
+ // The file already contains ACES data,
+ // color conversion is not necessary.
- return;
+ return;
}
mustConvertColor = true;
//
static const M44f bradfordCPM
- (0.895100, -0.750200, 0.038900, 0.000000,
- 0.266400, 1.713500, -0.068500, 0.000000,
- -0.161400, 0.036700, 1.029600, 0.000000,
- 0.000000, 0.000000, 0.000000, 1.000000);
+ (0.895100, -0.750200, 0.038900, 0.000000,
+ 0.266400, 1.713500, -0.068500, 0.000000,
+ -0.161400, 0.036700, 1.029600, 0.000000,
+ 0.000000, 0.000000, 0.000000, 1.000000);
const static M44f inverseBradfordCPM
- (0.986993, 0.432305, -0.008529, 0.000000,
- -0.147054, 0.518360, 0.040043, 0.000000,
- 0.159963, 0.049291, 0.968487, 0.000000,
- 0.000000, 0.000000, 0.000000, 1.000000);
+ (0.986993, 0.432305, -0.008529, 0.000000,
+ -0.147054, 0.518360, 0.040043, 0.000000,
+ 0.159963, 0.049291, 0.968487, 0.000000,
+ 0.000000, 0.000000, 0.000000, 1.000000);
//
// Convert the white points of the two RGB spaces to XYZ
//
V3f ratio ((acesNeutralXYZ * bradfordCPM) /
- (fileNeutralXYZ * bradfordCPM));
+ (fileNeutralXYZ * bradfordCPM));
M44f ratioMat (ratio[0], 0, 0, 0,
- 0, ratio[1], 0, 0,
- 0, 0, ratio[2], 0,
- 0, 0, 0, 1);
+ 0, ratio[1], 0, 0,
+ 0, 0, ratio[2], 0,
+ 0, 0, 0, 1);
M44f bradfordTrans = bradfordCPM *
ratioMat *
- inverseBradfordCPM;
+ inverseBradfordCPM;
//
// Build a combined file-RGB-to-ACES-RGB conversion matrix
}
-void
+void
AcesInputFile::setFrameBuffer (Rgba *base, size_t xStride, size_t yStride)
{
_data->rgbaFile->setFrameBuffer (base, xStride, yStride);
}
-void
+void
AcesInputFile::readPixels (int scanLine1, int scanLine2)
{
//
//
if (!_data->mustConvertColor)
- return;
+ return;
int minY = min (scanLine1, scanLine2);
int maxY = max (scanLine1, scanLine2);
for (int y = minY; y <= maxY; ++y)
{
- Rgba *base = _data->fbBase +
- _data->fbXStride * _data->minX +
- _data->fbYStride * y;
+ Rgba *base = _data->fbBase +
+ _data->fbXStride * _data->minX +
+ _data->fbYStride * y;
- for (int x = _data->minX; x <= _data->maxX; ++x)
- {
- V3f aces = V3f (base->r, base->g, base->b) * _data->fileToAces;
+ for (int x = _data->minX; x <= _data->maxX; ++x)
+ {
+ V3f aces = V3f (base->r, base->g, base->b) * _data->fileToAces;
- base->r = aces[0];
- base->g = aces[1];
- base->b = aces[2];
+ base->r = aces[0];
+ base->g = aces[1];
+ base->b = aces[2];
- base += _data->fbXStride;
- }
+ base += _data->fbXStride;
+ }
}
}
-void
+void
AcesInputFile::readPixels (int scanLine)
{
readPixels (scanLine, scanLine);
}
-const Imath::Box2i &
+const IMATH_NAMESPACE::Box2i &
AcesInputFile::displayWindow () const
{
return _data->rgbaFile->displayWindow();
}
-const Imath::Box2i &
+const IMATH_NAMESPACE::Box2i &
AcesInputFile::dataWindow () const
{
return _data->rgbaFile->dataWindow();
}
-const Imath::V2f
+const IMATH_NAMESPACE::V2f
AcesInputFile::screenWindowCenter () const
{
return _data->rgbaFile->screenWindowCenter();
}
-const char *
+const char *
AcesInputFile::fileName () const
{
return _data->rgbaFile->fileName();
return _data->rgbaFile->version();
}
-} // namespace Imf
+OPENEXR_IMF_INTERNAL_NAMESPACE_SOURCE_EXIT
//
// Copyright (c) 2007, Industrial Light & Magic, a division of Lucas
// Digital Ltd. LLC
-//
+//
// All rights reserved.
-//
+//
// Redistribution and use in source and binary forms, with or without
// modification, are permitted provided that the following conditions are
// met:
// distribution.
// * Neither the name of Industrial Light & Magic nor the names of
// its contributors may be used to endorse or promote products derived
-// from this software without specific prior written permission.
-//
+// from this software without specific prior written permission.
+//
// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
//-----------------------------------------------------------------------------
//
// ACES image file I/O.
-//
+//
// This header file declares two classes that directly support
// image file input and output according to the Academy Image
// Interchange Framework.
-//
+//
// The Academy Image Interchange file format is a subset of OpenEXR:
-//
+//
// - Images are stored as scanlines. Tiles are not allowed.
-//
+//
// - Images contain three color channels, either
// R, G, B (red, green, blue) or
// Y, RY, BY (luminance, sub-sampled chroma)
-//
+//
// - Images may optionally contain an alpha channel.
-//
+//
// - Only three compression types are allowed:
// - NO_COMPRESSION (file is not compressed)
// - PIZ_COMPRESSION (lossless)
// - B44A_COMPRESSION (lossy)
-//
+//
// - The "chromaticities" header attribute must specify
// the ACES RGB primaries and white point.
-//
+//
// class AcesOutputFile writes an OpenEXR file, enforcing the
// restrictions listed above. Pixel data supplied by application
// software must already be in the ACES RGB space.
-//
+//
// class AcesInputFile reads an OpenEXR file. Pixel data delivered
// to application software is guaranteed to be in the ACES RGB space.
// If the RGB space of the file is not the same as the ACES space,
//
//-----------------------------------------------------------------------------
-#include <ImfHeader.h>
-#include <ImfRgba.h>
+#include "ImfHeader.h"
+#include "ImfRgba.h"
#include "ImathVec.h"
#include "ImathBox.h"
-#include <ImfThreading.h>
-#include <string>
+#include "ImfThreading.h"
+#include "ImfNamespace.h"
+#include "ImfExport.h"
+#include "ImfForward.h"
-namespace Imf {
+#include <string>
+OPENEXR_IMF_INTERNAL_NAMESPACE_HEADER_ENTER
-class RgbaOutputFile;
-class RgbaInputFile;
-struct PreviewRgba;
-struct Chromaticities;
//
// ACES red, green, blue and white-point chromaticities.
// Constructor -- header is constructed by the caller
//---------------------------------------------------
+ IMF_EXPORT
AcesOutputFile (const std::string &name,
- const Header &header,
- RgbaChannels rgbaChannels = WRITE_RGBA,
+ const Header &header,
+ RgbaChannels rgbaChannels = WRITE_RGBA,
int numThreads = globalThreadCount());
// automatically close the file.
//----------------------------------------------------
- AcesOutputFile (OStream &os,
- const Header &header,
- RgbaChannels rgbaChannels = WRITE_RGBA,
+ IMF_EXPORT
+ AcesOutputFile (OPENEXR_IMF_INTERNAL_NAMESPACE::OStream &os,
+ const Header &header,
+ RgbaChannels rgbaChannels = WRITE_RGBA,
int numThreads = globalThreadCount());
// call arguments (empty dataWindow means "same as displayWindow")
//----------------------------------------------------------------
+ IMF_EXPORT
AcesOutputFile (const std::string &name,
- const Imath::Box2i &displayWindow,
- const Imath::Box2i &dataWindow = Imath::Box2i(),
- RgbaChannels rgbaChannels = WRITE_RGBA,
- float pixelAspectRatio = 1,
- const Imath::V2f screenWindowCenter = Imath::V2f (0, 0),
- float screenWindowWidth = 1,
- LineOrder lineOrder = INCREASING_Y,
- Compression compression = PIZ_COMPRESSION,
+ const IMATH_NAMESPACE::Box2i &displayWindow,
+ const IMATH_NAMESPACE::Box2i &dataWindow = IMATH_NAMESPACE::Box2i(),
+ RgbaChannels rgbaChannels = WRITE_RGBA,
+ float pixelAspectRatio = 1,
+ const IMATH_NAMESPACE::V2f screenWindowCenter = IMATH_NAMESPACE::V2f (0, 0),
+ float screenWindowWidth = 1,
+ LineOrder lineOrder = INCREASING_Y,
+ Compression compression = PIZ_COMPRESSION,
int numThreads = globalThreadCount());
// Box2i (V2i (0, 0), V2i (width - 1, height -1))
//-----------------------------------------------
+ IMF_EXPORT
AcesOutputFile (const std::string &name,
- int width,
- int height,
- RgbaChannels rgbaChannels = WRITE_RGBA,
- float pixelAspectRatio = 1,
- const Imath::V2f screenWindowCenter = Imath::V2f (0, 0),
- float screenWindowWidth = 1,
- LineOrder lineOrder = INCREASING_Y,
- Compression compression = PIZ_COMPRESSION,
+ int width,
+ int height,
+ RgbaChannels rgbaChannels = WRITE_RGBA,
+ float pixelAspectRatio = 1,
+ const IMATH_NAMESPACE::V2f screenWindowCenter = IMATH_NAMESPACE::V2f (0, 0),
+ float screenWindowWidth = 1,
+ LineOrder lineOrder = INCREASING_Y,
+ Compression compression = PIZ_COMPRESSION,
int numThreads = globalThreadCount());
// Destructor
//-----------
+ IMF_EXPORT
virtual ~AcesOutputFile ();
//
//------------------------------------------------
+ IMF_EXPORT
void setFrameBuffer (const Rgba *base,
- size_t xStride,
- size_t yStride);
+ size_t xStride,
+ size_t yStride);
//-------------------------------------------------
// Access to the file header
//--------------------------
+ IMF_EXPORT
const Header & header () const;
- const Imath::Box2i & displayWindow () const;
- const Imath::Box2i & dataWindow () const;
+ IMF_EXPORT
+ const IMATH_NAMESPACE::Box2i & displayWindow () const;
+ IMF_EXPORT
+ const IMATH_NAMESPACE::Box2i & dataWindow () const;
+ IMF_EXPORT
float pixelAspectRatio () const;
- const Imath::V2f screenWindowCenter () const;
+ IMF_EXPORT
+ const IMATH_NAMESPACE::V2f screenWindowCenter () const;
+ IMF_EXPORT
float screenWindowWidth () const;
+ IMF_EXPORT
LineOrder lineOrder () const;
+ IMF_EXPORT
Compression compression () const;
+ IMF_EXPORT
RgbaChannels channels () const;
// Update the preview image (see Imf::OutputFile::updatePreviewImage())
// --------------------------------------------------------------------
+ IMF_EXPORT
void updatePreviewImage (const PreviewRgba[]);
// destructor will automatically close the file.
//-------------------------------------------------------
+ IMF_EXPORT
AcesInputFile (const std::string &name,
- int numThreads = globalThreadCount());
+ int numThreads = globalThreadCount());
//-----------------------------------------------------------
// close the file.
//-----------------------------------------------------------
- AcesInputFile (IStream &is,
- int numThreads = globalThreadCount());
+ IMF_EXPORT
+ AcesInputFile (OPENEXR_IMF_INTERNAL_NAMESPACE::IStream &is,
+ int numThreads = globalThreadCount());
//-----------
// Destructor
//-----------
+ IMF_EXPORT
virtual ~AcesInputFile ();
//
//-----------------------------------------------------
+ IMF_EXPORT
void setFrameBuffer (Rgba *base,
- size_t xStride,
- size_t yStride);
+ size_t xStride,
+ size_t yStride);
//--------------------------------------------
// Pixels returned will contain ACES RGB data.
//--------------------------------------------
+ IMF_EXPORT
void readPixels (int scanLine1, int scanLine2);
+ IMF_EXPORT
void readPixels (int scanLine);
// Access to the file header
//--------------------------
+ IMF_EXPORT
const Header & header () const;
- const Imath::Box2i & displayWindow () const;
- const Imath::Box2i & dataWindow () const;
+ IMF_EXPORT
+ const IMATH_NAMESPACE::Box2i & displayWindow () const;
+ IMF_EXPORT
+ const IMATH_NAMESPACE::Box2i & dataWindow () const;
+ IMF_EXPORT
float pixelAspectRatio () const;
- const Imath::V2f screenWindowCenter () const;
+ IMF_EXPORT
+ const IMATH_NAMESPACE::V2f screenWindowCenter () const;
+ IMF_EXPORT
float screenWindowWidth () const;
+ IMF_EXPORT
LineOrder lineOrder () const;
+ IMF_EXPORT
Compression compression () const;
+ IMF_EXPORT
RgbaChannels channels () const;
+ IMF_EXPORT
const char * fileName () const;
+ IMF_EXPORT
bool isComplete () const;
// Access to the file format version
//----------------------------------
+ IMF_EXPORT
int version () const;
private:
};
-} // namespace Imf
+OPENEXR_IMF_INTERNAL_NAMESPACE_HEADER_EXIT
+
+
+
#endif
//
// Copyright (c) 2002, Industrial Light & Magic, a division of Lucas
// Digital Ltd. LLC
-//
+//
// All rights reserved.
-//
+//
// Redistribution and use in source and binary forms, with or without
// modification, are permitted provided that the following conditions are
// met:
// distribution.
// * Neither the name of Industrial Light & Magic nor the names of
// its contributors may be used to endorse or promote products derived
-// from this software without specific prior written permission.
-//
+// from this software without specific prior written permission.
+//
// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
#ifndef INCLUDED_IMF_ARRAY_H
#define INCLUDED_IMF_ARRAY_H
+#include "ImfForward.h"
+
//-------------------------------------------------------------------------
//
// class Array
// C () {std::cout << "C::C (" << this << ")\n";};
// virtual ~C () {std::cout << "C::~C (" << this << ")\n";};
// };
-//
+//
// int
// main ()
// {
// Array <C> a(3);
-//
+//
// C &b = a[1];
// const C &c = a[1];
// C *d = a + 2;
// const C *e = a;
-//
+//
// return 0;
// }
//
//-------------------------------------------------------------------------
-namespace Imf {
-
+OPENEXR_IMF_INTERNAL_NAMESPACE_HEADER_ENTER
template <class T>
class Array
// Constructors and destructors
//-----------------------------
- Array () {_data = 0;}
- Array (long size) {_data = new T[size];}
+ Array () {_data = 0; _size = 0;}
+ Array (long size) {_data = new T[size]; _size = size;}
~Array () {delete [] _data;}
void resizeEraseUnsafe (long size);
+ //-------------------------------
+ // Return the size of this array.
+ //-------------------------------
+
+ long size() const {return _size;}
+
+
private:
Array (const Array &); // Copying and assignment
Array & operator = (const Array &); // are not implemented
+ long _size;
T * _data;
};
void resizeEraseUnsafe (long sizeX, long sizeY);
+ //-------------------------------
+ // Return the size of this array.
+ //-------------------------------
+
+ long height() const {return _sizeX;}
+ long width() const {return _sizeY;}
+
+
private:
Array2D (const Array2D &); // Copying and assignment
Array2D & operator = (const Array2D &); // are not implemented
+ long _sizeX;
long _sizeY;
T * _data;
};
{
T *tmp = new T[size];
delete [] _data;
+ _size = size;
_data = tmp;
}
{
delete [] _data;
_data = 0;
+ _size = 0;
_data = new T[size];
+ _size = size;
}
template <class T>
inline
Array2D<T>::Array2D ():
- _sizeY (0), _data (0)
+ _sizeX(0), _sizeY (0), _data (0)
{
// emtpy
}
template <class T>
inline
Array2D<T>::Array2D (long sizeX, long sizeY):
- _sizeY (sizeY), _data (new T[sizeX * sizeY])
+ _sizeX (sizeX), _sizeY (sizeY), _data (new T[sizeX * sizeY])
{
// emtpy
}
template <class T>
-inline T *
+inline T *
Array2D<T>::operator [] (long x)
{
return _data + x * _sizeY;
{
T *tmp = new T[sizeX * sizeY];
delete [] _data;
+ _sizeX = sizeX;
_sizeY = sizeY;
_data = tmp;
}
{
delete [] _data;
_data = 0;
+ _sizeX = 0;
_sizeY = 0;
_data = new T[sizeX * sizeY];
+ _sizeX = sizeX;
_sizeY = sizeY;
}
+OPENEXR_IMF_INTERNAL_NAMESPACE_HEADER_EXIT
-} // namespace Imf
#endif
//
// Copyright (c) 2002, Industrial Light & Magic, a division of Lucas
// Digital Ltd. LLC
-//
+//
// All rights reserved.
-//
+//
// Redistribution and use in source and binary forms, with or without
// modification, are permitted provided that the following conditions are
// met:
// distribution.
// * Neither the name of Industrial Light & Magic nor the names of
// its contributors may be used to endorse or promote products derived
-// from this software without specific prior written permission.
-//
+// from this software without specific prior written permission.
+//
// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
#include <string.h>
#include <map>
+#include "ImfNamespace.h"
-namespace Imf {
+OPENEXR_IMF_INTERNAL_NAMESPACE_SOURCE_ENTER
-using IlmThread::Mutex;
-using IlmThread::Lock;
+
+using ILMTHREAD_NAMESPACE::Mutex;
+using ILMTHREAD_NAMESPACE::Lock;
Attribute::Attribute () {}
bool
operator () (const char *x, const char *y) const
{
- return strcmp (x, y) < 0;
+ return strcmp (x, y) < 0;
}
};
LockedTypeMap &
typeMap ()
{
+ // c++11 requires thread-safe static variable initialization
+#if __cplusplus >= 201103L
+ static LockedTypeMap tMap;
+ return tMap;
+#else
static Mutex criticalSection;
Lock lock (criticalSection);
static LockedTypeMap* typeMap = 0;
if (typeMap == 0)
- typeMap = new LockedTypeMap ();
+ typeMap = new LockedTypeMap ();
return *typeMap;
+#endif
}
} // namespace
-bool
+bool
Attribute::knownType (const char typeName[])
{
LockedTypeMap& tMap = typeMap();
}
-void
+void
Attribute::registerAttributeType (const char typeName[],
- Attribute *(*newAttribute)())
+ Attribute *(*newAttribute)())
{
LockedTypeMap& tMap = typeMap();
Lock lock (tMap.mutex);
if (tMap.find (typeName) != tMap.end())
- THROW (Iex::ArgExc, "Cannot register image file attribute "
- "type \"" << typeName << "\". "
- "The type has already been registered.");
+ THROW (IEX_NAMESPACE::ArgExc, "Cannot register image file attribute "
+ "type \"" << typeName << "\". "
+ "The type has already been registered.");
tMap.insert (TypeMap::value_type (typeName, newAttribute));
}
TypeMap::const_iterator i = tMap.find (typeName);
if (i == tMap.end())
- THROW (Iex::ArgExc, "Cannot create image file attribute of "
- "unknown type \"" << typeName << "\".");
+ THROW (IEX_NAMESPACE::ArgExc, "Cannot create image file attribute of "
+ "unknown type \"" << typeName << "\".");
return (i->second)();
}
-} // namespace Imf
+OPENEXR_IMF_INTERNAL_NAMESPACE_SOURCE_EXIT
//
// Copyright (c) 2004, Industrial Light & Magic, a division of Lucas
// Digital Ltd. LLC
-//
+//
// All rights reserved.
-//
+//
// Redistribution and use in source and binary forms, with or without
// modification, are permitted provided that the following conditions are
// met:
// distribution.
// * Neither the name of Industrial Light & Magic nor the names of
// its contributors may be used to endorse or promote products derived
-// from this software without specific prior written permission.
-//
+// from this software without specific prior written permission.
+//
// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
//-----------------------------------------------------------------------------
#include "IexBaseExc.h"
-#include <ImfIO.h>
-#include <ImfXdr.h>
-
+#include "ImfIO.h"
+#include "ImfXdr.h"
+#include "ImfForward.h"
+#include "ImfExport.h"
+#include "ImfNamespace.h"
-namespace Imf {
+OPENEXR_IMF_INTERNAL_NAMESPACE_HEADER_ENTER
class Attribute
// Constructor and destructor
//---------------------------
+ IMF_EXPORT
Attribute ();
+ IMF_EXPORT
virtual ~Attribute ();
// Type-specific attribute I/O and copying
//----------------------------------------
- virtual void writeValueTo (OStream &os,
- int version) const = 0;
+ virtual void writeValueTo (OPENEXR_IMF_INTERNAL_NAMESPACE::OStream &os,
+ int version) const = 0;
- virtual void readValueFrom (IStream &is,
- int size,
- int version) = 0;
+ virtual void readValueFrom (OPENEXR_IMF_INTERNAL_NAMESPACE::IStream &is,
+ int size,
+ int version) = 0;
virtual void copyValueFrom (const Attribute &other) = 0;
// Attribute factory
//------------------
+ IMF_EXPORT
static Attribute * newAttribute (const char typeName[]);
// Test if a given attribute type has already been registered
//-----------------------------------------------------------
+ IMF_EXPORT
static bool knownType (const char typeName[]);
// knows how to make objects of this type.
//--------------------------------------------------
+ IMF_EXPORT
static void registerAttributeType (const char typeName[],
- Attribute *(*newAttribute)());
+ Attribute *(*newAttribute)());
//------------------------------------------------------
// Un-register an attribute type so that newAttribute()
// debugging only).
//------------------------------------------------------
+ IMF_EXPORT
static void unRegisterAttributeType (const char typeName[]);
};
//-------------------------------------------------
// Class template for attributes of a specific type
//-------------------------------------------------
-
+
template <class T>
class TypedAttribute: public Attribute
{
//--------------------------------
virtual const char * typeName () const;
-
+
//---------------------------------------------------------
// Static version of typeName()
//---------------------------------------------------------
static const char * staticTypeName ();
-
+
//---------------------
// Make a new attribute
// Depending on type T, these functions may have to be specialized.
//-----------------------------------------------------------------
- virtual void writeValueTo (OStream &os,
- int version) const;
+ virtual void writeValueTo (OPENEXR_IMF_INTERNAL_NAMESPACE::OStream &os,
+ int version) const;
- virtual void readValueFrom (IStream &is,
- int size,
- int version);
+ virtual void readValueFrom (OPENEXR_IMF_INTERNAL_NAMESPACE::IStream &is,
+ int size,
+ int version);
virtual void copyValueFrom (const Attribute &other);
T _value;
};
-
//------------------------------------
// Implementation of TypedAttribute<T>
//------------------------------------
-
template <class T>
TypedAttribute<T>::TypedAttribute ():
Attribute (),
template <class T>
-TypedAttribute<T>::TypedAttribute (const T &value):
+TypedAttribute<T>::TypedAttribute (const T & value):
Attribute (),
_value (value)
{
template <class T>
-const char *
+const char *
TypedAttribute<T>::typeName () const
{
return staticTypeName();
template <class T>
-void
-TypedAttribute<T>::writeValueTo (OStream &os, int) const
+void
+TypedAttribute<T>::writeValueTo (OPENEXR_IMF_INTERNAL_NAMESPACE::OStream &os,
+ int version) const
{
- Xdr::write <StreamIO> (os, _value);
+ OPENEXR_IMF_INTERNAL_NAMESPACE::Xdr::write <OPENEXR_IMF_INTERNAL_NAMESPACE::StreamIO> (os, _value);
}
template <class T>
-void
-TypedAttribute<T>::readValueFrom (IStream &is, int, int)
+void
+TypedAttribute<T>::readValueFrom (OPENEXR_IMF_INTERNAL_NAMESPACE::IStream &is,
+ int size,
+ int version)
{
- Xdr::read <StreamIO> (is, _value);
+ OPENEXR_IMF_INTERNAL_NAMESPACE::Xdr::read <OPENEXR_IMF_INTERNAL_NAMESPACE::StreamIO> (is, _value);
}
template <class T>
-void
+void
TypedAttribute<T>::copyValueFrom (const Attribute &other)
{
_value = cast(other)._value;
TypedAttribute<T>::cast (Attribute *attribute)
{
TypedAttribute<T> *t =
- dynamic_cast <TypedAttribute<T> *> (attribute);
+ dynamic_cast <TypedAttribute<T> *> (attribute);
if (t == 0)
- throw Iex::TypeExc ("Unexpected attribute type.");
+ throw IEX_NAMESPACE::TypeExc ("Unexpected attribute type.");
return t;
}
TypedAttribute<T>::cast (const Attribute *attribute)
{
const TypedAttribute<T> *t =
- dynamic_cast <const TypedAttribute<T> *> (attribute);
+ dynamic_cast <const TypedAttribute<T> *> (attribute);
if (t == 0)
- throw Iex::TypeExc ("Unexpected attribute type.");
+ throw IEX_NAMESPACE::TypeExc ("Unexpected attribute type.");
return t;
}
}
-} // namespace Imf
-
-#if defined(OPENEXR_DLL) && defined(_MSC_VER)
- // Tell MS VC++ to disable "non dll-interface class used as base
- // for dll-interface class" and "no suitable definition provided
- // for explicit template"
- #pragma warning (disable : 4275 4661)
-
- #if defined (ILMIMF_EXPORTS)
- #define IMF_EXPIMP_TEMPLATE
- #else
- #define IMF_EXPIMP_TEMPLATE extern
- #endif
-
- IMF_EXPIMP_TEMPLATE template class Imf::TypedAttribute<float>;
- IMF_EXPIMP_TEMPLATE template class Imf::TypedAttribute<double>;
+OPENEXR_IMF_INTERNAL_NAMESPACE_HEADER_EXIT
- #pragma warning(default : 4251)
- #undef EXTERN_TEMPLATE
-#endif
-
-// Metrowerks compiler wants the .cpp file inlined, too
-#ifdef __MWERKS__
-#include <ImfAttribute.cpp>
-#endif
#endif
//
// Copyright (c) 2002, Industrial Light & Magic, a division of Lucas
// Digital Ltd. LLC
-//
+//
// All rights reserved.
-//
+//
// Redistribution and use in source and binary forms, with or without
// modification, are permitted provided that the following conditions are
// met:
// distribution.
// * Neither the name of Industrial Light & Magic nor the names of
// its contributors may be used to endorse or promote products derived
-// from this software without specific prior written permission.
-//
+// from this software without specific prior written permission.
+//
// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
//
//-----------------------------------------------------------------------------
-#include "OpenEXRConfig.h"
-
-#if !defined (HAVE_LARGE_STACK)
+#include "ImfNamespace.h"
#include <string.h>
-#endif
-namespace Imf {
+OPENEXR_IMF_INTERNAL_NAMESPACE_HEADER_ENTER
#if !defined (HAVE_LARGE_STACK)
{
public:
- AutoArray (): _data (new T [size]) { memset(_data, 0, size*sizeof(T)); }
- ~AutoArray () {delete [] _data;}
-
- operator T * () {return _data;}
- operator const T * () const {return _data;}
+ AutoArray (): _data (new T [size]) { memset(_data, 0, size*sizeof(T)); }
+ ~AutoArray () {delete [] _data;}
+ operator T * () {return _data;}
+ operator const T * () const {return _data;}
+
private:
- T *_data;
+ T *_data;
};
{
public:
- operator T * () {return _data;}
- operator const T * () const {return _data;}
-
+ operator T * () {return _data;}
+ operator const T * () const {return _data;}
+
private:
- T _data[size];
+ T _data[size];
};
#endif
-} // namespace Imf
+OPENEXR_IMF_INTERNAL_NAMESPACE_HEADER_EXIT
+
#endif
//
// Copyright (c) 2006, Industrial Light & Magic, a division of Lucas
// Digital Ltd. LLC
-//
+//
// All rights reserved.
-//
+//
// Redistribution and use in source and binary forms, with or without
// modification, are permitted provided that the following conditions are
// met:
// distribution.
// * Neither the name of Industrial Light & Magic nor the names of
// its contributors may be used to endorse or promote products derived
-// from this software without specific prior written permission.
-//
+// from this software without specific prior written permission.
+//
// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
// |
// | 0
// |
-// v
+// v
// 4 --------> 5 --------> 6 --------> 7
// | 4 8 12
// |
//
//-----------------------------------------------------------------------------
-#include <ImfB44Compressor.h>
-#include <ImfHeader.h>
-#include <ImfChannelList.h>
-#include <ImfMisc.h>
-#include <ImfCheckedArithmetic.h>
+#include "ImfB44Compressor.h"
+#include "ImfHeader.h"
+#include "ImfChannelList.h"
+#include "ImfMisc.h"
+#include "ImfCheckedArithmetic.h"
#include <ImathFun.h>
#include <ImathBox.h>
#include <Iex.h>
#include <string.h>
#include <assert.h>
#include <algorithm>
+#include "ImfNamespace.h"
+
-namespace Imf {
+OPENEXR_IMF_INTERNAL_NAMESPACE_SOURCE_ENTER
-using Imath::divp;
-using Imath::modp;
-using Imath::Box2i;
-using Imath::V2i;
+
+using IMATH_NAMESPACE::divp;
+using IMATH_NAMESPACE::modp;
+using IMATH_NAMESPACE::Box2i;
+using IMATH_NAMESPACE::V2i;
using std::min;
namespace {
//
// Lookup tables for
// y = exp (x / 8)
-// and
+// and
// x = 8 * log (y)
//
convertFromLinear (unsigned short s[16])
{
for (int i = 0; i < 16; ++i)
- s[i] = expTable[s[i]];
+ s[i] = expTable[s[i]];
}
convertToLinear (unsigned short s[16])
{
for (int i = 0; i < 16; ++i)
- s[i] = logTable[s[i]];
+ s[i] = logTable[s[i]];
}
for (int i = 0; i < 16; ++i)
{
- if ((s[i] & 0x7c00) == 0x7c00)
- t[i] = 0x8000;
- else if (s[i] & 0x8000)
- t[i] = ~s[i];
- else
- t[i] = s[i] | 0x8000;
+ if ((s[i] & 0x7c00) == 0x7c00)
+ t[i] = 0x8000;
+ else if (s[i] & 0x8000)
+ t[i] = ~s[i];
+ else
+ t[i] = s[i] | 0x8000;
}
-
+
//
// Find the maximum, tMax, of t[0] ... t[15].
//
unsigned short tMax = 0;
for (int i = 0; i < 16; ++i)
- if (tMax < t[i])
- tMax = t[i];
+ if (tMax < t[i])
+ tMax = t[i];
//
// Compute a set of running differences, r[0] ... r[14]:
do
{
- shift += 1;
+ shift += 1;
- //
- // Compute absolute differences, d[0] ... d[15],
- // between tMax and t[0] ... t[15].
- //
- // Shift and round the absolute differences.
- //
+ //
+ // Compute absolute differences, d[0] ... d[15],
+ // between tMax and t[0] ... t[15].
+ //
+ // Shift and round the absolute differences.
+ //
- for (int i = 0; i < 16; ++i)
- d[i] = shiftAndRound (tMax - t[i], shift);
+ for (int i = 0; i < 16; ++i)
+ d[i] = shiftAndRound (tMax - t[i], shift);
- //
- // Convert d[0] .. d[15] into running differences
- //
+ //
+ // Convert d[0] .. d[15] into running differences
+ //
- r[ 0] = d[ 0] - d[ 4] + bias;
- r[ 1] = d[ 4] - d[ 8] + bias;
- r[ 2] = d[ 8] - d[12] + bias;
+ r[ 0] = d[ 0] - d[ 4] + bias;
+ r[ 1] = d[ 4] - d[ 8] + bias;
+ r[ 2] = d[ 8] - d[12] + bias;
- r[ 3] = d[ 0] - d[ 1] + bias;
- r[ 4] = d[ 4] - d[ 5] + bias;
- r[ 5] = d[ 8] - d[ 9] + bias;
- r[ 6] = d[12] - d[13] + bias;
+ r[ 3] = d[ 0] - d[ 1] + bias;
+ r[ 4] = d[ 4] - d[ 5] + bias;
+ r[ 5] = d[ 8] - d[ 9] + bias;
+ r[ 6] = d[12] - d[13] + bias;
- r[ 7] = d[ 1] - d[ 2] + bias;
- r[ 8] = d[ 5] - d[ 6] + bias;
- r[ 9] = d[ 9] - d[10] + bias;
- r[10] = d[13] - d[14] + bias;
+ r[ 7] = d[ 1] - d[ 2] + bias;
+ r[ 8] = d[ 5] - d[ 6] + bias;
+ r[ 9] = d[ 9] - d[10] + bias;
+ r[10] = d[13] - d[14] + bias;
- r[11] = d[ 2] - d[ 3] + bias;
- r[12] = d[ 6] - d[ 7] + bias;
- r[13] = d[10] - d[11] + bias;
- r[14] = d[14] - d[15] + bias;
+ r[11] = d[ 2] - d[ 3] + bias;
+ r[12] = d[ 6] - d[ 7] + bias;
+ r[13] = d[10] - d[11] + bias;
+ r[14] = d[14] - d[15] + bias;
- rMin = r[0];
- rMax = r[0];
+ rMin = r[0];
+ rMax = r[0];
- for (int i = 1; i < 15; ++i)
- {
- if (rMin > r[i])
- rMin = r[i];
+ for (int i = 1; i < 15; ++i)
+ {
+ if (rMin > r[i])
+ rMin = r[i];
- if (rMax < r[i])
- rMax = r[i];
- }
+ if (rMax < r[i])
+ rMax = r[i];
+ }
}
while (rMin < 0 || rMax > 0x3f);
if (rMin == bias && rMax == bias && optFlatFields)
{
- //
- // Special case - all pixels have the same value.
- // We encode this in 3 instead of 14 bytes by
- // storing the value 0xfc in the third output byte,
- // which cannot occur in the 14-byte encoding.
- //
+ //
+ // Special case - all pixels have the same value.
+ // We encode this in 3 instead of 14 bytes by
+ // storing the value 0xfc in the third output byte,
+ // which cannot occur in the 14-byte encoding.
+ //
- b[0] = (t[0] >> 8);
- b[1] = t[0];
- b[2] = 0xfc;
+ b[0] = (t[0] >> 8);
+ b[1] = (unsigned char) t[0];
+ b[2] = 0xfc;
- return 3;
+ return 3;
}
if (exactMax)
{
- //
- // Adjust t[0] so that the pixel whose value is equal
- // to tMax gets represented as accurately as possible.
- //
+ //
+ // Adjust t[0] so that the pixel whose value is equal
+ // to tMax gets represented as accurately as possible.
+ //
- t[0] = tMax - (d[0] << shift);
+ t[0] = tMax - (d[0] << shift);
}
//
//
b[ 0] = (t[0] >> 8);
- b[ 1] = t[0];
+ b[ 1] = (unsigned char) t[0];
b[ 2] = (unsigned char) ((shift << 2) | (r[ 0] >> 4));
b[ 3] = (unsigned char) ((r[ 0] << 4) | (r[ 1] >> 2));
//
#if defined (DEBUG)
- assert (b[2] != 0xfc);
+ assert (b[2] != 0xfc);
#endif
s[ 0] = (b[0] << 8) | b[1];
s[ 4] = s[ 0] + ((((b[ 2] << 4) | (b[ 3] >> 4)) & 0x3f) << shift) - bias;
s[ 8] = s[ 4] + ((((b[ 3] << 2) | (b[ 4] >> 6)) & 0x3f) << shift) - bias;
s[12] = s[ 8] + ((b[ 4] & 0x3f) << shift) - bias;
-
+
s[ 1] = s[ 0] + ((b[ 5] >> 2) << shift) - bias;
s[ 5] = s[ 4] + ((((b[ 5] << 4) | (b[ 6] >> 4)) & 0x3f) << shift) - bias;
s[ 9] = s[ 8] + ((((b[ 6] << 2) | (b[ 7] >> 6)) & 0x3f) << shift) - bias;
s[13] = s[12] + ((b[ 7] & 0x3f) << shift) - bias;
-
+
s[ 2] = s[ 1] + ((b[ 8] >> 2) << shift) - bias;
s[ 6] = s[ 5] + ((((b[ 8] << 4) | (b[ 9] >> 4)) & 0x3f) << shift) - bias;
s[10] = s[ 9] + ((((b[ 9] << 2) | (b[10] >> 6)) & 0x3f) << shift) - bias;
s[14] = s[13] + ((b[10] & 0x3f) << shift) - bias;
-
+
s[ 3] = s[ 2] + ((b[11] >> 2) << shift) - bias;
s[ 7] = s[ 6] + ((((b[11] << 4) | (b[12] >> 4)) & 0x3f) << shift) - bias;
s[11] = s[10] + ((((b[12] << 2) | (b[13] >> 6)) & 0x3f) << shift) - bias;
for (int i = 0; i < 16; ++i)
{
- if (s[i] & 0x8000)
- s[i] &= 0x7fff;
- else
- s[i] = ~s[i];
+ if (s[i] & 0x8000)
+ s[i] &= 0x7fff;
+ else
+ s[i] = ~s[i];
}
}
//
#if defined (DEBUG)
- assert (b[2] == 0xfc);
+ assert (b[2] == 0xfc);
#endif
s[0] = (b[0] << 8) | b[1];
if (s[0] & 0x8000)
- s[0] &= 0x7fff;
+ s[0] &= 0x7fff;
else
- s[0] = ~s[0];
+ s[0] = ~s[0];
for (int i = 1; i < 16; ++i)
- s[i] = s[0];
+ s[i] = s[0];
}
void
notEnoughData ()
{
- throw Iex::InputExc ("Error decompressing data "
- "(input data are shorter than expected).");
+ throw IEX_NAMESPACE::InputExc ("Error decompressing data "
+ "(input data are shorter than expected).");
}
void
tooMuchData ()
{
- throw Iex::InputExc ("Error decompressing data "
- "(input data are longer than expected).");
+ throw IEX_NAMESPACE::InputExc ("Error decompressing data "
+ "(input data are longer than expected).");
}
} // namespace
int numHalfChans = 0;
for (ChannelList::ConstIterator c = channels.begin();
- c != channels.end();
- ++c)
+ c != channels.end();
+ ++c)
{
- assert (pixelTypeSize (c.channel().type) % pixelTypeSize (HALF) == 0);
- ++_numChans;
+ assert (pixelTypeSize (c.channel().type) % pixelTypeSize (HALF) == 0);
+ ++_numChans;
- if (c.channel().type == HALF)
- ++numHalfChans;
+ if (c.channel().type == HALF)
+ ++numHalfChans;
}
//
int i = 0;
for (ChannelList::ConstIterator c = channels.begin();
- c != channels.end();
- ++c, ++i)
+ c != channels.end();
+ ++c, ++i)
{
- _channelData[i].ys = c.channel().ySampling;
- _channelData[i].type = c.channel().type;
- _channelData[i].pLinear = c.channel().pLinear;
- _channelData[i].size =
- pixelTypeSize (c.channel().type) / pixelTypeSize (HALF);
+ _channelData[i].ys = c.channel().ySampling;
+ _channelData[i].type = c.channel().type;
+ _channelData[i].pLinear = c.channel().pLinear;
+ _channelData[i].size =
+ pixelTypeSize (c.channel().type) / pixelTypeSize (HALF);
}
const Box2i &dataWindow = hdr.dataWindow();
assert (sizeof (unsigned short) == pixelTypeSize (HALF));
if (_numChans == numHalfChans)
- _format = NATIVE;
+ _format = NATIVE;
}
int
B44Compressor::compress (const char *inPtr,
- int inSize,
- int minY,
- const char *&outPtr)
+ int inSize,
+ int minY,
+ const char *&outPtr)
{
return compress (inPtr,
- inSize,
- Box2i (V2i (_minX, minY),
- V2i (_maxX, minY + numScanLines() - 1)),
- outPtr);
+ inSize,
+ Box2i (V2i (_minX, minY),
+ V2i (_maxX, minY + numScanLines() - 1)),
+ outPtr);
}
int
B44Compressor::compressTile (const char *inPtr,
- int inSize,
- Imath::Box2i range,
- const char *&outPtr)
+ int inSize,
+ IMATH_NAMESPACE::Box2i range,
+ const char *&outPtr)
{
return compress (inPtr, inSize, range, outPtr);
}
int
B44Compressor::uncompress (const char *inPtr,
- int inSize,
- int minY,
- const char *&outPtr)
+ int inSize,
+ int minY,
+ const char *&outPtr)
{
return uncompress (inPtr,
- inSize,
- Box2i (V2i (_minX, minY),
- V2i (_maxX, minY + numScanLines() - 1)),
- outPtr);
+ inSize,
+ Box2i (V2i (_minX, minY),
+ V2i (_maxX, minY + numScanLines() - 1)),
+ outPtr);
}
int
B44Compressor::uncompressTile (const char *inPtr,
- int inSize,
- Imath::Box2i range,
- const char *&outPtr)
+ int inSize,
+ IMATH_NAMESPACE::Box2i range,
+ const char *&outPtr)
{
return uncompress (inPtr, inSize, range, outPtr);
}
int
B44Compressor::compress (const char *inPtr,
- int inSize,
- Imath::Box2i range,
- const char *&outPtr)
+ int inSize,
+ IMATH_NAMESPACE::Box2i range,
+ const char *&outPtr)
{
//
// Compress a block of pixel data: First copy the input pixels
if (inSize == 0)
{
- //
- // Special case - empty input buffer.
- //
+ //
+ // Special case - empty input buffer.
+ //
- return 0;
+ return 0;
}
//
int maxX = min (range.max.x, _maxX);
int minY = range.min.y;
int maxY = min (range.max.y, _maxY);
-
+
unsigned short *tmpBufferEnd = _tmpBuffer;
int i = 0;
for (ChannelList::ConstIterator c = _channels.begin();
- c != _channels.end();
- ++c, ++i)
+ c != _channels.end();
+ ++c, ++i)
{
- ChannelData &cd = _channelData[i];
+ ChannelData &cd = _channelData[i];
- cd.start = tmpBufferEnd;
- cd.end = cd.start;
+ cd.start = tmpBufferEnd;
+ cd.end = cd.start;
- cd.nx = numSamples (c.channel().xSampling, minX, maxX);
- cd.ny = numSamples (c.channel().ySampling, minY, maxY);
+ cd.nx = numSamples (c.channel().xSampling, minX, maxX);
+ cd.ny = numSamples (c.channel().ySampling, minY, maxY);
- tmpBufferEnd += cd.nx * cd.ny * cd.size;
+ tmpBufferEnd += cd.nx * cd.ny * cd.size;
}
if (_format == XDR)
{
- //
- // The data in the input buffer are in the machine-independent
- // Xdr format. Copy the HALF channels into _tmpBuffer and
- // convert them back into native format for compression.
- // Copy UINT and FLOAT channels verbatim into _tmpBuffer.
- //
-
- for (int y = minY; y <= maxY; ++y)
- {
- for (int i = 0; i < _numChans; ++i)
- {
- ChannelData &cd = _channelData[i];
-
- if (modp (y, cd.ys) != 0)
- continue;
-
- if (cd.type == HALF)
- {
- for (int x = cd.nx; x > 0; --x)
- {
- Xdr::read <CharPtrIO> (inPtr, *cd.end);
- ++cd.end;
- }
- }
- else
- {
- int n = cd.nx * cd.size;
- memcpy (cd.end, inPtr, n * sizeof (unsigned short));
- inPtr += n * sizeof (unsigned short);
- cd.end += n;
- }
- }
- }
+ //
+ // The data in the input buffer are in the machine-independent
+ // Xdr format. Copy the HALF channels into _tmpBuffer and
+ // convert them back into native format for compression.
+ // Copy UINT and FLOAT channels verbatim into _tmpBuffer.
+ //
+
+ for (int y = minY; y <= maxY; ++y)
+ {
+ for (int i = 0; i < _numChans; ++i)
+ {
+ ChannelData &cd = _channelData[i];
+
+ if (modp (y, cd.ys) != 0)
+ continue;
+
+ if (cd.type == HALF)
+ {
+ for (int x = cd.nx; x > 0; --x)
+ {
+ Xdr::read <CharPtrIO> (inPtr, *cd.end);
+ ++cd.end;
+ }
+ }
+ else
+ {
+ int n = cd.nx * cd.size;
+ memcpy (cd.end, inPtr, n * sizeof (unsigned short));
+ inPtr += n * sizeof (unsigned short);
+ cd.end += n;
+ }
+ }
+ }
}
else
{
- //
- // The input buffer contains only HALF channels, and they
- // are in native, machine-dependent format. Copy the pixels
- // into _tmpBuffer.
- //
-
- for (int y = minY; y <= maxY; ++y)
- {
- for (int i = 0; i < _numChans; ++i)
- {
- ChannelData &cd = _channelData[i];
-
- #if defined (DEBUG)
- assert (cd.type == HALF);
- #endif
-
- if (modp (y, cd.ys) != 0)
- continue;
-
- int n = cd.nx * cd.size;
- memcpy (cd.end, inPtr, n * sizeof (unsigned short));
- inPtr += n * sizeof (unsigned short);
- cd.end += n;
- }
- }
+ //
+ // The input buffer contains only HALF channels, and they
+ // are in native, machine-dependent format. Copy the pixels
+ // into _tmpBuffer.
+ //
+
+ for (int y = minY; y <= maxY; ++y)
+ {
+ for (int i = 0; i < _numChans; ++i)
+ {
+ ChannelData &cd = _channelData[i];
+
+ #if defined (DEBUG)
+ assert (cd.type == HALF);
+ #endif
+
+ if (modp (y, cd.ys) != 0)
+ continue;
+
+ int n = cd.nx * cd.size;
+ memcpy (cd.end, inPtr, n * sizeof (unsigned short));
+ inPtr += n * sizeof (unsigned short);
+ cd.end += n;
+ }
+ }
}
//
#if defined (DEBUG)
- for (int i = 1; i < _numChans; ++i)
- assert (_channelData[i-1].end == _channelData[i].start);
+ for (int i = 1; i < _numChans; ++i)
+ assert (_channelData[i-1].end == _channelData[i].start);
- assert (_channelData[_numChans-1].end == tmpBufferEnd);
+ assert (_channelData[_numChans-1].end == tmpBufferEnd);
#endif
for (int i = 0; i < _numChans; ++i)
{
- ChannelData &cd = _channelData[i];
-
- if (cd.type != HALF)
- {
- //
- // UINT or FLOAT channel.
- //
-
- int n = cd.nx * cd.ny * cd.size * sizeof (unsigned short);
- memcpy (outEnd, cd.start, n);
- outEnd += n;
-
- continue;
- }
-
- //
- // HALF channel
- //
-
- for (int y = 0; y < cd.ny; y += 4)
- {
- //
- // Copy the next 4x4 pixel block into array s.
- // If the width, cd.nx, or the height, cd.ny, of
- // the pixel data in _tmpBuffer is not divisible
- // by 4, then pad the data by repeating the
- // rightmost column and the bottom row.
- //
-
- unsigned short *row0 = cd.start + y * cd.nx;
- unsigned short *row1 = row0 + cd.nx;
- unsigned short *row2 = row1 + cd.nx;
- unsigned short *row3 = row2 + cd.nx;
-
- if (y + 3 >= cd.ny)
- {
- if (y + 1 >= cd.ny)
- row1 = row0;
-
- if (y + 2 >= cd.ny)
- row2 = row1;
-
- row3 = row2;
- }
-
- for (int x = 0; x < cd.nx; x += 4)
- {
- unsigned short s[16];
-
- if (x + 3 >= cd.nx)
- {
- int n = cd.nx - x;
-
- for (int i = 0; i < 4; ++i)
- {
- int j = min (i, n - 1);
-
- s[i + 0] = row0[j];
- s[i + 4] = row1[j];
- s[i + 8] = row2[j];
- s[i + 12] = row3[j];
- }
- }
- else
- {
- memcpy (&s[ 0], row0, 4 * sizeof (unsigned short));
- memcpy (&s[ 4], row1, 4 * sizeof (unsigned short));
- memcpy (&s[ 8], row2, 4 * sizeof (unsigned short));
- memcpy (&s[12], row3, 4 * sizeof (unsigned short));
- }
-
- row0 += 4;
- row1 += 4;
- row2 += 4;
- row3 += 4;
-
- //
- // Compress the contents of array s and append the
- // results to the output buffer.
- //
-
- if (cd.pLinear)
- convertFromLinear (s);
-
- outEnd += pack (s, (unsigned char *) outEnd,
- _optFlatFields, !cd.pLinear);
- }
- }
+ ChannelData &cd = _channelData[i];
+
+ if (cd.type != HALF)
+ {
+ //
+ // UINT or FLOAT channel.
+ //
+
+ int n = cd.nx * cd.ny * cd.size * sizeof (unsigned short);
+ memcpy (outEnd, cd.start, n);
+ outEnd += n;
+
+ continue;
+ }
+
+ //
+ // HALF channel
+ //
+
+ for (int y = 0; y < cd.ny; y += 4)
+ {
+ //
+ // Copy the next 4x4 pixel block into array s.
+ // If the width, cd.nx, or the height, cd.ny, of
+ // the pixel data in _tmpBuffer is not divisible
+ // by 4, then pad the data by repeating the
+ // rightmost column and the bottom row.
+ //
+
+ unsigned short *row0 = cd.start + y * cd.nx;
+ unsigned short *row1 = row0 + cd.nx;
+ unsigned short *row2 = row1 + cd.nx;
+ unsigned short *row3 = row2 + cd.nx;
+
+ if (y + 3 >= cd.ny)
+ {
+ if (y + 1 >= cd.ny)
+ row1 = row0;
+
+ if (y + 2 >= cd.ny)
+ row2 = row1;
+
+ row3 = row2;
+ }
+
+ for (int x = 0; x < cd.nx; x += 4)
+ {
+ unsigned short s[16];
+
+ if (x + 3 >= cd.nx)
+ {
+ int n = cd.nx - x;
+
+ for (int i = 0; i < 4; ++i)
+ {
+ int j = min (i, n - 1);
+
+ s[i + 0] = row0[j];
+ s[i + 4] = row1[j];
+ s[i + 8] = row2[j];
+ s[i + 12] = row3[j];
+ }
+ }
+ else
+ {
+ memcpy (&s[ 0], row0, 4 * sizeof (unsigned short));
+ memcpy (&s[ 4], row1, 4 * sizeof (unsigned short));
+ memcpy (&s[ 8], row2, 4 * sizeof (unsigned short));
+ memcpy (&s[12], row3, 4 * sizeof (unsigned short));
+ }
+
+ row0 += 4;
+ row1 += 4;
+ row2 += 4;
+ row3 += 4;
+
+ //
+ // Compress the contents of array s and append the
+ // results to the output buffer.
+ //
+
+ if (cd.pLinear)
+ convertFromLinear (s);
+
+ outEnd += pack (s, (unsigned char *) outEnd,
+ _optFlatFields, !cd.pLinear);
+ }
+ }
}
return outEnd - _outBuffer;
int
B44Compressor::uncompress (const char *inPtr,
- int inSize,
- Imath::Box2i range,
- const char *&outPtr)
+ int inSize,
+ IMATH_NAMESPACE::Box2i range,
+ const char *&outPtr)
{
//
// This function is the reverse of the compress() function,
if (inSize == 0)
{
- return 0;
+ return 0;
}
int minX = range.min.x;
int maxX = min (range.max.x, _maxX);
int minY = range.min.y;
int maxY = min (range.max.y, _maxY);
-
+
unsigned short *tmpBufferEnd = _tmpBuffer;
int i = 0;
for (ChannelList::ConstIterator c = _channels.begin();
- c != _channels.end();
- ++c, ++i)
+ c != _channels.end();
+ ++c, ++i)
{
- ChannelData &cd = _channelData[i];
+ ChannelData &cd = _channelData[i];
- cd.start = tmpBufferEnd;
- cd.end = cd.start;
+ cd.start = tmpBufferEnd;
+ cd.end = cd.start;
- cd.nx = numSamples (c.channel().xSampling, minX, maxX);
- cd.ny = numSamples (c.channel().ySampling, minY, maxY);
+ cd.nx = numSamples (c.channel().xSampling, minX, maxX);
+ cd.ny = numSamples (c.channel().ySampling, minY, maxY);
- tmpBufferEnd += cd.nx * cd.ny * cd.size;
+ tmpBufferEnd += cd.nx * cd.ny * cd.size;
}
for (int i = 0; i < _numChans; ++i)
{
- ChannelData &cd = _channelData[i];
-
- if (cd.type != HALF)
- {
- //
- // UINT or FLOAT channel.
- //
-
- int n = cd.nx * cd.ny * cd.size * sizeof (unsigned short);
-
- if (inSize < n)
- notEnoughData();
-
- memcpy (cd.start, inPtr, n);
- inPtr += n;
- inSize -= n;
-
- continue;
- }
-
- //
- // HALF channel
- //
-
- for (int y = 0; y < cd.ny; y += 4)
- {
- unsigned short *row0 = cd.start + y * cd.nx;
- unsigned short *row1 = row0 + cd.nx;
- unsigned short *row2 = row1 + cd.nx;
- unsigned short *row3 = row2 + cd.nx;
-
- for (int x = 0; x < cd.nx; x += 4)
- {
- unsigned short s[16];
-
- if (inSize < 3)
- notEnoughData();
-
- if (((const unsigned char *)inPtr)[2] == 0xfc)
- {
- unpack3 ((const unsigned char *)inPtr, s);
- inPtr += 3;
- inSize -= 3;
- }
- else
- {
- if (inSize < 14)
- notEnoughData();
-
- unpack14 ((const unsigned char *)inPtr, s);
- inPtr += 14;
- inSize -= 14;
- }
-
- if (cd.pLinear)
- convertToLinear (s);
-
- int n = (x + 3 < cd.nx)?
- 4 * sizeof (unsigned short) :
- (cd.nx - x) * sizeof (unsigned short);
-
- if (y + 3 < cd.ny)
- {
- memcpy (row0, &s[ 0], n);
- memcpy (row1, &s[ 4], n);
- memcpy (row2, &s[ 8], n);
- memcpy (row3, &s[12], n);
- }
- else
- {
- memcpy (row0, &s[ 0], n);
-
- if (y + 1 < cd.ny)
- memcpy (row1, &s[ 4], n);
-
- if (y + 2 < cd.ny)
- memcpy (row2, &s[ 8], n);
- }
-
- row0 += 4;
- row1 += 4;
- row2 += 4;
- row3 += 4;
- }
- }
+ ChannelData &cd = _channelData[i];
+
+ if (cd.type != HALF)
+ {
+ //
+ // UINT or FLOAT channel.
+ //
+
+ int n = cd.nx * cd.ny * cd.size * sizeof (unsigned short);
+
+ if (inSize < n)
+ notEnoughData();
+
+ memcpy (cd.start, inPtr, n);
+ inPtr += n;
+ inSize -= n;
+
+ continue;
+ }
+
+ //
+ // HALF channel
+ //
+
+ for (int y = 0; y < cd.ny; y += 4)
+ {
+ unsigned short *row0 = cd.start + y * cd.nx;
+ unsigned short *row1 = row0 + cd.nx;
+ unsigned short *row2 = row1 + cd.nx;
+ unsigned short *row3 = row2 + cd.nx;
+
+ for (int x = 0; x < cd.nx; x += 4)
+ {
+ unsigned short s[16];
+
+ if (inSize < 3)
+ notEnoughData();
+
+ if (((const unsigned char *)inPtr)[2] == 0xfc)
+ {
+ unpack3 ((const unsigned char *)inPtr, s);
+ inPtr += 3;
+ inSize -= 3;
+ }
+ else
+ {
+ if (inSize < 14)
+ notEnoughData();
+
+ unpack14 ((const unsigned char *)inPtr, s);
+ inPtr += 14;
+ inSize -= 14;
+ }
+
+ if (cd.pLinear)
+ convertToLinear (s);
+
+ int n = (x + 3 < cd.nx)?
+ 4 * sizeof (unsigned short) :
+ (cd.nx - x) * sizeof (unsigned short);
+
+ if (y + 3 < cd.ny)
+ {
+ memcpy (row0, &s[ 0], n);
+ memcpy (row1, &s[ 4], n);
+ memcpy (row2, &s[ 8], n);
+ memcpy (row3, &s[12], n);
+ }
+ else
+ {
+ memcpy (row0, &s[ 0], n);
+
+ if (y + 1 < cd.ny)
+ memcpy (row1, &s[ 4], n);
+
+ if (y + 2 < cd.ny)
+ memcpy (row2, &s[ 8], n);
+ }
+
+ row0 += 4;
+ row1 += 4;
+ row2 += 4;
+ row3 += 4;
+ }
+ }
}
char *outEnd = _outBuffer;
if (_format == XDR)
{
- for (int y = minY; y <= maxY; ++y)
- {
- for (int i = 0; i < _numChans; ++i)
- {
- ChannelData &cd = _channelData[i];
-
- if (modp (y, cd.ys) != 0)
- continue;
-
- if (cd.type == HALF)
- {
- for (int x = cd.nx; x > 0; --x)
- {
- Xdr::write <CharPtrIO> (outEnd, *cd.end);
- ++cd.end;
- }
- }
- else
- {
- int n = cd.nx * cd.size;
- memcpy (outEnd, cd.end, n * sizeof (unsigned short));
- outEnd += n * sizeof (unsigned short);
- cd.end += n;
- }
- }
- }
+ for (int y = minY; y <= maxY; ++y)
+ {
+ for (int i = 0; i < _numChans; ++i)
+ {
+ ChannelData &cd = _channelData[i];
+
+ if (modp (y, cd.ys) != 0)
+ continue;
+
+ if (cd.type == HALF)
+ {
+ for (int x = cd.nx; x > 0; --x)
+ {
+ Xdr::write <CharPtrIO> (outEnd, *cd.end);
+ ++cd.end;
+ }
+ }
+ else
+ {
+ int n = cd.nx * cd.size;
+ memcpy (outEnd, cd.end, n * sizeof (unsigned short));
+ outEnd += n * sizeof (unsigned short);
+ cd.end += n;
+ }
+ }
+ }
}
else
{
- for (int y = minY; y <= maxY; ++y)
- {
- for (int i = 0; i < _numChans; ++i)
- {
- ChannelData &cd = _channelData[i];
-
- #if defined (DEBUG)
- assert (cd.type == HALF);
- #endif
-
- if (modp (y, cd.ys) != 0)
- continue;
-
- int n = cd.nx * cd.size;
- memcpy (outEnd, cd.end, n * sizeof (unsigned short));
- outEnd += n * sizeof (unsigned short);
- cd.end += n;
- }
- }
+ for (int y = minY; y <= maxY; ++y)
+ {
+ for (int i = 0; i < _numChans; ++i)
+ {
+ ChannelData &cd = _channelData[i];
+
+ #if defined (DEBUG)
+ assert (cd.type == HALF);
+ #endif
+
+ if (modp (y, cd.ys) != 0)
+ continue;
+
+ int n = cd.nx * cd.size;
+ memcpy (outEnd, cd.end, n * sizeof (unsigned short));
+ outEnd += n * sizeof (unsigned short);
+ cd.end += n;
+ }
+ }
}
#if defined (DEBUG)
- for (int i = 1; i < _numChans; ++i)
- assert (_channelData[i-1].end == _channelData[i].start);
+ for (int i = 1; i < _numChans; ++i)
+ assert (_channelData[i-1].end == _channelData[i].start);
- assert (_channelData[_numChans-1].end == tmpBufferEnd);
+ assert (_channelData[_numChans-1].end == tmpBufferEnd);
#endif
if (inSize > 0)
- tooMuchData();
+ tooMuchData();
outPtr = _outBuffer;
return outEnd - _outBuffer;
}
-} // namespace Imf
+OPENEXR_IMF_INTERNAL_NAMESPACE_SOURCE_EXIT
//
// Copyright (c) 2006, Industrial Light & Magic, a division of Lucas
// Digital Ltd. LLC
-//
+//
// All rights reserved.
-//
+//
// Redistribution and use in source and binary forms, with or without
// modification, are permitted provided that the following conditions are
// met:
// distribution.
// * Neither the name of Industrial Light & Magic nor the names of
// its contributors may be used to endorse or promote products derived
-// from this software without specific prior written permission.
-//
+// from this software without specific prior written permission.
+//
// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
//
//-----------------------------------------------------------------------------
-#include <ImfCompressor.h>
-
-namespace Imf {
+#include "ImfCompressor.h"
+#include "ImfNamespace.h"
+#include "ImfExport.h"
+#include "ImfForward.h"
-class ChannelList;
+OPENEXR_IMF_INTERNAL_NAMESPACE_HEADER_ENTER
class B44Compressor: public Compressor
{
public:
+ IMF_EXPORT
B44Compressor (const Header &hdr,
size_t maxScanLineSize,
- size_t numScanLines,
- bool optFlatFields);
+ size_t numScanLines,
+ bool optFlatFields);
+ IMF_EXPORT
virtual ~B44Compressor ();
+ IMF_EXPORT
virtual int numScanLines () const;
+ IMF_EXPORT
virtual Format format () const;
+ IMF_EXPORT
virtual int compress (const char *inPtr,
- int inSize,
- int minY,
- const char *&outPtr);
-
+ int inSize,
+ int minY,
+ const char *&outPtr);
+
+ IMF_EXPORT
virtual int compressTile (const char *inPtr,
- int inSize,
- Imath::Box2i range,
- const char *&outPtr);
+ int inSize,
+ IMATH_NAMESPACE::Box2i range,
+ const char *&outPtr);
+ IMF_EXPORT
virtual int uncompress (const char *inPtr,
- int inSize,
- int minY,
- const char *&outPtr);
-
+ int inSize,
+ int minY,
+ const char *&outPtr);
+
+ IMF_EXPORT
virtual int uncompressTile (const char *inPtr,
- int inSize,
- Imath::Box2i range,
- const char *&outPtr);
+ int inSize,
+ IMATH_NAMESPACE::Box2i range,
+ const char *&outPtr);
private:
struct ChannelData;
-
+
int compress (const char *inPtr,
- int inSize,
- Imath::Box2i range,
- const char *&outPtr);
-
+ int inSize,
+ IMATH_NAMESPACE::Box2i range,
+ const char *&outPtr);
+
int uncompress (const char *inPtr,
- int inSize,
- Imath::Box2i range,
- const char *&outPtr);
+ int inSize,
+ IMATH_NAMESPACE::Box2i range,
+ const char *&outPtr);
int _maxScanLineSize;
bool _optFlatFields;
};
-} // namespace Imf
+OPENEXR_IMF_INTERNAL_NAMESPACE_HEADER_EXIT
#endif
//
// Copyright (c) 2004, Industrial Light & Magic, a division of Lucas
// Digital Ltd. LLC
-//
+//
// All rights reserved.
-//
+//
// Redistribution and use in source and binary forms, with or without
// modification, are permitted provided that the following conditions are
// met:
// distribution.
// * Neither the name of Industrial Light & Magic nor the names of
// its contributors may be used to endorse or promote products derived
-// from this software without specific prior written permission.
-//
+// from this software without specific prior written permission.
+//
// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
#include <ImfBoxAttribute.h>
-namespace Imf {
+OPENEXR_IMF_INTERNAL_NAMESPACE_SOURCE_ENTER
+using namespace OPENEXR_IMF_INTERNAL_NAMESPACE;
template <>
const char *
template <>
void
-Box2iAttribute::writeValueTo (OStream &os, int) const
+Box2iAttribute::writeValueTo (OPENEXR_IMF_INTERNAL_NAMESPACE::OStream &os, int version) const
{
Xdr::write <StreamIO> (os, _value.min.x);
Xdr::write <StreamIO> (os, _value.min.y);
template <>
void
-Box2iAttribute::readValueFrom (IStream &is, int, int)
+Box2iAttribute::readValueFrom (OPENEXR_IMF_INTERNAL_NAMESPACE::IStream &is, int size, int version)
{
Xdr::read <StreamIO> (is, _value.min.x);
Xdr::read <StreamIO> (is, _value.min.y);
template <>
void
-Box2fAttribute::writeValueTo (OStream &os, int) const
+Box2fAttribute::writeValueTo (OPENEXR_IMF_INTERNAL_NAMESPACE::OStream &os, int version) const
{
Xdr::write <StreamIO> (os, _value.min.x);
Xdr::write <StreamIO> (os, _value.min.y);
template <>
void
-Box2fAttribute::readValueFrom (IStream &is, int, int)
+Box2fAttribute::readValueFrom (OPENEXR_IMF_INTERNAL_NAMESPACE::IStream &is, int size, int version)
{
Xdr::read <StreamIO> (is, _value.min.x);
Xdr::read <StreamIO> (is, _value.min.y);
}
-} // namespace Imf
+OPENEXR_IMF_INTERNAL_NAMESPACE_SOURCE_EXIT
//
// Copyright (c) 2004, Industrial Light & Magic, a division of Lucas
// Digital Ltd. LLC
-//
+//
// All rights reserved.
-//
+//
// Redistribution and use in source and binary forms, with or without
// modification, are permitted provided that the following conditions are
// met:
// distribution.
// * Neither the name of Industrial Light & Magic nor the names of
// its contributors may be used to endorse or promote products derived
-// from this software without specific prior written permission.
-//
+// from this software without specific prior written permission.
+//
// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
//
//-----------------------------------------------------------------------------
-#include <ImfAttribute.h>
+#include "ImfForward.h"
+#include "ImfExport.h"
+#include "ImfAttribute.h"
#include "ImathBox.h"
+#include "ImfNamespace.h"
+OPENEXR_IMF_INTERNAL_NAMESPACE_HEADER_ENTER
-namespace Imf {
+typedef TypedAttribute<IMATH_NAMESPACE::Box2i> Box2iAttribute;
-typedef TypedAttribute<Imath::Box2i> Box2iAttribute;
-template <> const char *Box2iAttribute::staticTypeName ();
-template <> void Box2iAttribute::writeValueTo (OStream &, int) const;
-template <> void Box2iAttribute::readValueFrom (IStream &, int, int);
+template <>
+IMF_EXPORT
+const char *Box2iAttribute::staticTypeName ();
+template <>
+IMF_EXPORT
+void Box2iAttribute::writeValueTo (OPENEXR_IMF_INTERNAL_NAMESPACE::OStream &,
+ int) const;
+template <>
+IMF_EXPORT
+void Box2iAttribute::readValueFrom (OPENEXR_IMF_INTERNAL_NAMESPACE::IStream &,
+ int, int);
-typedef TypedAttribute<Imath::Box2f> Box2fAttribute;
-template <> const char *Box2fAttribute::staticTypeName ();
-template <> void Box2fAttribute::writeValueTo (OStream &, int) const;
-template <> void Box2fAttribute::readValueFrom (IStream &, int, int);
+typedef TypedAttribute<IMATH_NAMESPACE::Box2f> Box2fAttribute;
+template <>
+IMF_EXPORT
+const char *Box2fAttribute::staticTypeName ();
+template <>
+IMF_EXPORT
+void Box2fAttribute::writeValueTo (OPENEXR_IMF_INTERNAL_NAMESPACE::OStream &,
+ int) const;
+template <>
+IMF_EXPORT
+void Box2fAttribute::readValueFrom (OPENEXR_IMF_INTERNAL_NAMESPACE::IStream &,
+ int, int);
-} // namespace Imf
-
-// Metrowerks compiler wants the .cpp file inlined, too
-#ifdef __MWERKS__
-#include <ImfBoxAttribute.cpp>
-#endif
+OPENEXR_IMF_INTERNAL_NAMESPACE_HEADER_EXIT
#endif
//
// Copyright (c) 2004, Industrial Light & Magic, a division of Lucas
// Digital Ltd. LLC
-//
+//
// All rights reserved.
-//
+//
// Redistribution and use in source and binary forms, with or without
// modification, are permitted provided that the following conditions are
// met:
// distribution.
// * Neither the name of Industrial Light & Magic nor the names of
// its contributors may be used to endorse or promote products derived
-// from this software without specific prior written permission.
-//
+// from this software without specific prior written permission.
+//
// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
#include <ImfChannelList.h>
#include <ImfLut.h>
#include "half.h"
+#include "ImfNamespace.h"
+#include "ImathForward.h"
+
#include <string.h>
-using Imath::Box2i;
-using Imath::Box2f;
-using Imath::V2i;
-using Imath::V2f;
-using Imath::V3i;
-using Imath::V3f;
-using Imath::M33f;
-using Imath::M44f;
+
+using IMATH_NAMESPACE::Box2i;
+using IMATH_NAMESPACE::Box2f;
+using IMATH_NAMESPACE::V2i;
+using IMATH_NAMESPACE::V2f;
+using IMATH_NAMESPACE::V3i;
+using IMATH_NAMESPACE::V3f;
+using IMATH_NAMESPACE::M33f;
+using IMATH_NAMESPACE::M44f;
namespace {
}
-inline Imf::Header *
+inline OPENEXR_IMF_INTERNAL_NAMESPACE::Header *
header (ImfHeader *hdr)
{
- return (Imf::Header *)(hdr);
+ return (OPENEXR_IMF_INTERNAL_NAMESPACE::Header *)(hdr);
}
-inline const Imf::Header *
+inline const OPENEXR_IMF_INTERNAL_NAMESPACE::Header *
header (const ImfHeader *hdr)
{
- return (const Imf::Header *)(hdr);
+ return (const OPENEXR_IMF_INTERNAL_NAMESPACE::Header *)(hdr);
}
-inline Imf::RgbaOutputFile *
+inline OPENEXR_IMF_INTERNAL_NAMESPACE::RgbaOutputFile *
outfile (ImfOutputFile *out)
{
- return (Imf::RgbaOutputFile *) out;
+ return (OPENEXR_IMF_INTERNAL_NAMESPACE::RgbaOutputFile *) out;
}
-inline const Imf::RgbaOutputFile *
+inline const OPENEXR_IMF_INTERNAL_NAMESPACE::RgbaOutputFile *
outfile (const ImfOutputFile *out)
{
- return (const Imf::RgbaOutputFile *) out;
+ return (const OPENEXR_IMF_INTERNAL_NAMESPACE::RgbaOutputFile *) out;
}
-inline Imf::TiledRgbaOutputFile *
+inline OPENEXR_IMF_INTERNAL_NAMESPACE::TiledRgbaOutputFile *
outfile (ImfTiledOutputFile *out)
{
- return (Imf::TiledRgbaOutputFile *) out;
+ return (OPENEXR_IMF_INTERNAL_NAMESPACE::TiledRgbaOutputFile *) out;
}
-inline const Imf::TiledRgbaOutputFile *
+inline const OPENEXR_IMF_INTERNAL_NAMESPACE::TiledRgbaOutputFile *
outfile (const ImfTiledOutputFile *out)
{
- return (const Imf::TiledRgbaOutputFile *) out;
+ return (const OPENEXR_IMF_INTERNAL_NAMESPACE::TiledRgbaOutputFile *) out;
}
-inline Imf::RgbaInputFile *
+inline OPENEXR_IMF_INTERNAL_NAMESPACE::RgbaInputFile *
infile (ImfInputFile *in)
{
- return (Imf::RgbaInputFile *) in;
+ return (OPENEXR_IMF_INTERNAL_NAMESPACE::RgbaInputFile *) in;
}
-inline const Imf::RgbaInputFile *
+inline const OPENEXR_IMF_INTERNAL_NAMESPACE::RgbaInputFile *
infile (const ImfInputFile *in)
{
- return (const Imf::RgbaInputFile *) in;
+ return (const OPENEXR_IMF_INTERNAL_NAMESPACE::RgbaInputFile *) in;
}
-inline Imf::TiledRgbaInputFile *
+inline OPENEXR_IMF_INTERNAL_NAMESPACE::TiledRgbaInputFile *
infile (ImfTiledInputFile *in)
{
- return (Imf::TiledRgbaInputFile *) in;
+ return (OPENEXR_IMF_INTERNAL_NAMESPACE::TiledRgbaInputFile *) in;
}
-inline const Imf::TiledRgbaInputFile *
+inline const OPENEXR_IMF_INTERNAL_NAMESPACE::TiledRgbaInputFile *
infile (const ImfTiledInputFile *in)
{
- return (const Imf::TiledRgbaInputFile *) in;
+ return (const OPENEXR_IMF_INTERNAL_NAMESPACE::TiledRgbaInputFile *) in;
}
} // namespace
-void
+void
ImfFloatToHalf (float f, ImfHalf *h)
{
*h = half(f).bits();
}
-void
+void
ImfFloatToHalfArray (int n, const float f[/*n*/], ImfHalf h[/*n*/])
{
for (int i = 0; i < n; ++i)
- h[i] = half(f[i]).bits();
+ h[i] = half(f[i]).bits();
}
-float
+float
ImfHalfToFloat (ImfHalf h)
{
return float (*((half *)&h));
ImfHalfToFloatArray (int n, const ImfHalf h[/*n*/], float f[/*n*/])
{
for (int i = 0; i < n; ++i)
- f[i] = float (*((half *)(h + i)));
+ f[i] = float (*((half *)(h + i)));
}
{
try
{
- return (ImfHeader *) new Imf::Header;
+ return (ImfHeader *) new OPENEXR_IMF_INTERNAL_NAMESPACE::Header;
}
catch (const std::exception &e)
{
- setErrorMessage (e);
- return 0;
+ setErrorMessage (e);
+ return 0;
}
}
-void
+void
ImfDeleteHeader (ImfHeader *hdr)
{
delete header (hdr);
{
try
{
- return (ImfHeader *) new Imf::Header (*header (hdr));
+ return (ImfHeader *) new OPENEXR_IMF_INTERNAL_NAMESPACE::Header (*header (hdr));
}
catch (const std::exception &e)
{
- setErrorMessage (e);
- return 0;
+ setErrorMessage (e);
+ return 0;
}
}
-void
+void
ImfHeaderSetDisplayWindow (ImfHeader *hdr,
- int xMin, int yMin,
- int xMax, int yMax)
+ int xMin, int yMin,
+ int xMax, int yMax)
{
header(hdr)->displayWindow() = Box2i (V2i (xMin, yMin), V2i (xMax, yMax));
}
-void
+void
ImfHeaderDisplayWindow (const ImfHeader *hdr,
- int *xMin, int *yMin,
- int *xMax, int *yMax)
+ int *xMin, int *yMin,
+ int *xMax, int *yMax)
{
const Box2i dw = header(hdr)->displayWindow();
*xMin = dw.min.x;
void
ImfHeaderSetDataWindow (ImfHeader *hdr,
- int xMin, int yMin,
- int xMax, int yMax)
+ int xMin, int yMin,
+ int xMax, int yMax)
{
header(hdr)->dataWindow() = Box2i (V2i (xMin, yMin), V2i (xMax, yMax));
}
-void
+void
ImfHeaderDataWindow (const ImfHeader *hdr,
- int *xMin, int *yMin,
- int *xMax, int *yMax)
+ int *xMin, int *yMin,
+ int *xMax, int *yMax)
{
const Box2i dw = header(hdr)->dataWindow();
*xMin = dw.min.x;
}
-void
+void
ImfHeaderSetPixelAspectRatio (ImfHeader *hdr, float pixelAspectRatio)
{
header(hdr)->pixelAspectRatio() = pixelAspectRatio;
}
-float
+float
ImfHeaderPixelAspectRatio (const ImfHeader *hdr)
{
return header(hdr)->pixelAspectRatio();
}
-void
+void
ImfHeaderSetScreenWindowCenter (ImfHeader *hdr, float x, float y)
{
header(hdr)->screenWindowCenter() = V2f (x, y);
}
-void
+void
ImfHeaderScreenWindowCenter (const ImfHeader *hdr, float *x, float *y)
{
const V2i &swc = header(hdr)->screenWindowCenter();
- *x = swc.x;
- *y = swc.y;
+ *x = (float) swc.x;
+ *y = (float) swc.y;
}
-void
+void
ImfHeaderSetScreenWindowWidth (ImfHeader *hdr, float width)
{
header(hdr)->screenWindowWidth() = width;
}
-float
+float
ImfHeaderScreenWindowWidth (const ImfHeader *hdr)
{
return header(hdr)->screenWindowWidth();
}
-void
+void
ImfHeaderSetLineOrder (ImfHeader *hdr, int lineOrder)
{
- header(hdr)->lineOrder() = Imf::LineOrder (lineOrder);
+ header(hdr)->lineOrder() = OPENEXR_IMF_INTERNAL_NAMESPACE::LineOrder (lineOrder);
}
-int
+int
ImfHeaderLineOrder (const ImfHeader *hdr)
{
return header(hdr)->lineOrder();
}
-
-void
+
+void
ImfHeaderSetCompression (ImfHeader *hdr, int compression)
{
- header(hdr)->compression() = Imf::Compression (compression);
+ header(hdr)->compression() = OPENEXR_IMF_INTERNAL_NAMESPACE::Compression (compression);
}
-int
+int
ImfHeaderCompression (const ImfHeader *hdr)
{
return header(hdr)->compression();
}
-int
+int
ImfHeaderSetIntAttribute (ImfHeader *hdr, const char name[], int value)
{
try
{
- if (header(hdr)->find(name) == header(hdr)->end())
- {
- header(hdr)->insert (name, Imf::IntAttribute (value));
- }
- else
- {
- header(hdr)->typedAttribute<Imf::IntAttribute>(name).value() =
- value;
- }
+ if (header(hdr)->find(name) == header(hdr)->end())
+ {
+ header(hdr)->insert (name, OPENEXR_IMF_INTERNAL_NAMESPACE::IntAttribute (value));
+ }
+ else
+ {
+ header(hdr)->typedAttribute<OPENEXR_IMF_INTERNAL_NAMESPACE::IntAttribute>(name).value() =
+ value;
+ }
- return 1;
+ return 1;
}
catch (const std::exception &e)
{
- setErrorMessage (e);
- return 0;
+ setErrorMessage (e);
+ return 0;
}
}
-int
+int
ImfHeaderIntAttribute (const ImfHeader *hdr, const char name[], int *value)
{
try
{
- *value = header(hdr)->typedAttribute<Imf::IntAttribute>(name).value();
- return 1;
+ *value = header(hdr)->typedAttribute<OPENEXR_IMF_INTERNAL_NAMESPACE::IntAttribute>(name).value();
+ return 1;
}
catch (const std::exception &e)
{
- setErrorMessage (e);
- return 0;
+ setErrorMessage (e);
+ return 0;
}
}
-int
+int
ImfHeaderSetFloatAttribute (ImfHeader *hdr, const char name[], float value)
{
try
{
- if (header(hdr)->find(name) == header(hdr)->end())
- {
- header(hdr)->insert (name, Imf::FloatAttribute (value));
- }
- else
- {
- header(hdr)->typedAttribute<Imf::FloatAttribute>(name).value() =
- value;
- }
+ if (header(hdr)->find(name) == header(hdr)->end())
+ {
+ header(hdr)->insert (name, OPENEXR_IMF_INTERNAL_NAMESPACE::FloatAttribute (value));
+ }
+ else
+ {
+ header(hdr)->typedAttribute<OPENEXR_IMF_INTERNAL_NAMESPACE::FloatAttribute>(name).value() =
+ value;
+ }
- return 1;
+ return 1;
}
catch (const std::exception &e)
{
- setErrorMessage (e);
- return 0;
+ setErrorMessage (e);
+ return 0;
}
}
-int
+int
ImfHeaderSetDoubleAttribute (ImfHeader *hdr, const char name[], double value)
{
try
{
- if (header(hdr)->find(name) == header(hdr)->end())
- {
- header(hdr)->insert (name, Imf::DoubleAttribute (value));
- }
- else
- {
- header(hdr)->typedAttribute<Imf::DoubleAttribute>(name).value() =
- value;
- }
+ if (header(hdr)->find(name) == header(hdr)->end())
+ {
+ header(hdr)->insert (name, OPENEXR_IMF_INTERNAL_NAMESPACE::DoubleAttribute (value));
+ }
+ else
+ {
+ header(hdr)->typedAttribute<OPENEXR_IMF_INTERNAL_NAMESPACE::DoubleAttribute>(name).value() =
+ value;
+ }
- return 1;
+ return 1;
}
catch (const std::exception &e)
{
- setErrorMessage (e);
- return 0;
+ setErrorMessage (e);
+ return 0;
}
}
{
try
{
- *value = header(hdr)->typedAttribute<Imf::FloatAttribute>(name).value();
- return 1;
+ *value = header(hdr)->typedAttribute<OPENEXR_IMF_INTERNAL_NAMESPACE::FloatAttribute>(name).value();
+ return 1;
}
catch (const std::exception &e)
{
- setErrorMessage (e);
- return 0;
+ setErrorMessage (e);
+ return 0;
}
}
int
ImfHeaderDoubleAttribute (const ImfHeader *hdr,
- const char name[],
- double *value)
+ const char name[],
+ double *value)
{
try
{
- *value = header(hdr)->
- typedAttribute<Imf::DoubleAttribute>(name).value();
+ *value = header(hdr)->
+ typedAttribute<OPENEXR_IMF_INTERNAL_NAMESPACE::DoubleAttribute>(name).value();
- return 1;
+ return 1;
}
catch (const std::exception &e)
{
- setErrorMessage (e);
- return 0;
+ setErrorMessage (e);
+ return 0;
}
}
int
ImfHeaderSetStringAttribute (ImfHeader *hdr,
- const char name[],
- const char value[])
+ const char name[],
+ const char value[])
{
try
{
- if (header(hdr)->find(name) == header(hdr)->end())
- {
- header(hdr)->insert (name, Imf::StringAttribute (value));
- }
- else
- {
- header(hdr)->typedAttribute<Imf::StringAttribute>(name).value() =
- value;
- }
+ if (header(hdr)->find(name) == header(hdr)->end())
+ {
+ header(hdr)->insert (name, OPENEXR_IMF_INTERNAL_NAMESPACE::StringAttribute (value));
+ }
+ else
+ {
+ header(hdr)->typedAttribute<OPENEXR_IMF_INTERNAL_NAMESPACE::StringAttribute>(name).value() =
+ value;
+ }
- return 1;
+ return 1;
}
catch (const std::exception &e)
{
- setErrorMessage (e);
- return 0;
+ setErrorMessage (e);
+ return 0;
}
}
int
ImfHeaderStringAttribute (const ImfHeader *hdr,
- const char name[],
- const char **value)
+ const char name[],
+ const char **value)
{
try
{
- *value = header(hdr)->
- typedAttribute<Imf::StringAttribute>(name).value().c_str();
+ *value = header(hdr)->
+ typedAttribute<OPENEXR_IMF_INTERNAL_NAMESPACE::StringAttribute>(name).value().c_str();
- return 1;
+ return 1;
}
catch (const std::exception &e)
{
- setErrorMessage (e);
- return 0;
+ setErrorMessage (e);
+ return 0;
}
}
int
ImfHeaderSetBox2iAttribute (ImfHeader *hdr,
- const char name[],
- int xMin, int yMin,
- int xMax, int yMax)
+ const char name[],
+ int xMin, int yMin,
+ int xMax, int yMax)
{
try
{
- Box2i box (V2i (xMin, yMin), V2i (xMax, yMax));
+ Box2i box (V2i (xMin, yMin), V2i (xMax, yMax));
- if (header(hdr)->find(name) == header(hdr)->end())
- {
- header(hdr)->insert (name, Imf::Box2iAttribute (box));
- }
- else
- {
- header(hdr)->typedAttribute<Imf::Box2iAttribute>(name).value() =
- box;
- }
+ if (header(hdr)->find(name) == header(hdr)->end())
+ {
+ header(hdr)->insert (name, OPENEXR_IMF_INTERNAL_NAMESPACE::Box2iAttribute (box));
+ }
+ else
+ {
+ header(hdr)->typedAttribute<OPENEXR_IMF_INTERNAL_NAMESPACE::Box2iAttribute>(name).value() =
+ box;
+ }
- return 1;
+ return 1;
}
catch (const std::exception &e)
{
- setErrorMessage (e);
- return 0;
+ setErrorMessage (e);
+ return 0;
}
}
int
ImfHeaderBox2iAttribute (const ImfHeader *hdr,
- const char name[],
- int *xMin, int *yMin,
- int *xMax, int *yMax)
+ const char name[],
+ int *xMin, int *yMin,
+ int *xMax, int *yMax)
{
try
{
- const Box2i &box =
- header(hdr)->typedAttribute<Imf::Box2iAttribute>(name).value();
+ const Box2i &box =
+ header(hdr)->typedAttribute<OPENEXR_IMF_INTERNAL_NAMESPACE::Box2iAttribute>(name).value();
- *xMin = box.min.x;
- *yMin = box.min.y;
- *xMax = box.max.x;
- *yMax = box.max.y;
+ *xMin = box.min.x;
+ *yMin = box.min.y;
+ *xMax = box.max.x;
+ *yMax = box.max.y;
- return 1;
+ return 1;
}
catch (const std::exception &e)
{
- setErrorMessage (e);
- return 0;
+ setErrorMessage (e);
+ return 0;
}
}
int
ImfHeaderSetBox2fAttribute (ImfHeader *hdr,
- const char name[],
- float xMin, float yMin,
- float xMax, float yMax)
+ const char name[],
+ float xMin, float yMin,
+ float xMax, float yMax)
{
try
{
- Box2f box (V2f (xMin, yMin), V2f (xMax, yMax));
+ Box2f box (V2f (xMin, yMin), V2f (xMax, yMax));
- if (header(hdr)->find(name) == header(hdr)->end())
- {
- header(hdr)->insert (name, Imf::Box2fAttribute (box));
- }
- else
- {
- header(hdr)->typedAttribute<Imf::Box2fAttribute>(name).value() =
- box;
- }
+ if (header(hdr)->find(name) == header(hdr)->end())
+ {
+ header(hdr)->insert (name, OPENEXR_IMF_INTERNAL_NAMESPACE::Box2fAttribute (box));
+ }
+ else
+ {
+ header(hdr)->typedAttribute<OPENEXR_IMF_INTERNAL_NAMESPACE::Box2fAttribute>(name).value() =
+ box;
+ }
- return 1;
+ return 1;
}
catch (const std::exception &e)
{
- setErrorMessage (e);
- return 0;
+ setErrorMessage (e);
+ return 0;
}
}
int
ImfHeaderBox2fAttribute (const ImfHeader *hdr,
- const char name[],
- float *xMin, float *yMin,
- float *xMax, float *yMax)
+ const char name[],
+ float *xMin, float *yMin,
+ float *xMax, float *yMax)
{
try
{
- const Box2f &box =
- header(hdr)->typedAttribute<Imf::Box2fAttribute>(name).value();
+ const Box2f &box =
+ header(hdr)->typedAttribute<OPENEXR_IMF_INTERNAL_NAMESPACE::Box2fAttribute>(name).value();
- *xMin = box.min.x;
- *yMin = box.min.y;
- *xMax = box.max.x;
- *yMax = box.max.y;
+ *xMin = box.min.x;
+ *yMin = box.min.y;
+ *xMax = box.max.x;
+ *yMax = box.max.y;
- return 1;
+ return 1;
}
catch (const std::exception &e)
{
- setErrorMessage (e);
- return 0;
+ setErrorMessage (e);
+ return 0;
}
}
int
ImfHeaderSetV2iAttribute (ImfHeader *hdr,
- const char name[],
- int x, int y)
+ const char name[],
+ int x, int y)
{
try
{
- V2i v (x, y);
+ V2i v (x, y);
- if (header(hdr)->find(name) == header(hdr)->end())
- header(hdr)->insert (name, Imf::V2iAttribute (v));
- else
- header(hdr)->typedAttribute<Imf::V2iAttribute>(name).value() = v;
+ if (header(hdr)->find(name) == header(hdr)->end())
+ header(hdr)->insert (name, OPENEXR_IMF_INTERNAL_NAMESPACE::V2iAttribute (v));
+ else
+ header(hdr)->typedAttribute<OPENEXR_IMF_INTERNAL_NAMESPACE::V2iAttribute>(name).value() = v;
- return 1;
+ return 1;
}
catch (const std::exception &e)
{
- setErrorMessage (e);
- return 0;
+ setErrorMessage (e);
+ return 0;
}
}
int
ImfHeaderV2iAttribute (const ImfHeader *hdr,
- const char name[],
- int *x, int *y)
+ const char name[],
+ int *x, int *y)
{
try
{
- const V2i &v =
- header(hdr)->typedAttribute<Imf::V2iAttribute>(name).value();
+ const V2i &v =
+ header(hdr)->typedAttribute<OPENEXR_IMF_INTERNAL_NAMESPACE::V2iAttribute>(name).value();
- *x = v.x;
- *y = v.y;
+ *x = v.x;
+ *y = v.y;
- return 1;
+ return 1;
}
catch (const std::exception &e)
{
- setErrorMessage (e);
- return 0;
+ setErrorMessage (e);
+ return 0;
}
}
-int
+int
ImfHeaderSetV2fAttribute (ImfHeader *hdr,
- const char name[],
- float x, float y)
+ const char name[],
+ float x, float y)
{
try
{
- V2f v (x, y);
+ V2f v (x, y);
- if (header(hdr)->find(name) == header(hdr)->end())
- header(hdr)->insert (name, Imf::V2fAttribute (v));
- else
- header(hdr)->typedAttribute<Imf::V2fAttribute>(name).value() = v;
+ if (header(hdr)->find(name) == header(hdr)->end())
+ header(hdr)->insert (name, OPENEXR_IMF_INTERNAL_NAMESPACE::V2fAttribute (v));
+ else
+ header(hdr)->typedAttribute<OPENEXR_IMF_INTERNAL_NAMESPACE::V2fAttribute>(name).value() = v;
- return 1;
+ return 1;
}
catch (const std::exception &e)
{
- setErrorMessage (e);
- return 0;
+ setErrorMessage (e);
+ return 0;
}
}
int
ImfHeaderV2fAttribute (const ImfHeader *hdr,
- const char name[],
- float *x, float *y)
+ const char name[],
+ float *x, float *y)
{
try
{
- const V2f &v =
- header(hdr)->typedAttribute<Imf::V2fAttribute>(name).value();
+ const V2f &v =
+ header(hdr)->typedAttribute<OPENEXR_IMF_INTERNAL_NAMESPACE::V2fAttribute>(name).value();
- *x = v.x;
- *y = v.y;
+ *x = v.x;
+ *y = v.y;
- return 1;
+ return 1;
}
catch (const std::exception &e)
{
- setErrorMessage (e);
- return 0;
+ setErrorMessage (e);
+ return 0;
}
}
int
ImfHeaderSetV3iAttribute (ImfHeader *hdr,
- const char name[],
- int x, int y, int z)
+ const char name[],
+ int x, int y, int z)
{
try
{
- V3i v (x, y, z);
+ V3i v (x, y, z);
- if (header(hdr)->find(name) == header(hdr)->end())
- header(hdr)->insert (name, Imf::V3iAttribute (v));
- else
- header(hdr)->typedAttribute<Imf::V3iAttribute>(name).value() = v;
+ if (header(hdr)->find(name) == header(hdr)->end())
+ header(hdr)->insert (name, OPENEXR_IMF_INTERNAL_NAMESPACE::V3iAttribute (v));
+ else
+ header(hdr)->typedAttribute<OPENEXR_IMF_INTERNAL_NAMESPACE::V3iAttribute>(name).value() = v;
- return 1;
+ return 1;
}
catch (const std::exception &e)
{
- setErrorMessage (e);
- return 0;
+ setErrorMessage (e);
+ return 0;
}
}
int
ImfHeaderV3iAttribute (const ImfHeader *hdr,
- const char name[],
- int *x, int *y, int *z)
+ const char name[],
+ int *x, int *y, int *z)
{
try
{
- const V3i &v =
- header(hdr)->typedAttribute<Imf::V3iAttribute>(name).value();
+ const V3i &v =
+ header(hdr)->typedAttribute<OPENEXR_IMF_INTERNAL_NAMESPACE::V3iAttribute>(name).value();
- *x = v.x;
- *y = v.y;
- *z = v.z;
+ *x = v.x;
+ *y = v.y;
+ *z = v.z;
- return 1;
+ return 1;
}
catch (const std::exception &e)
{
- setErrorMessage (e);
- return 0;
+ setErrorMessage (e);
+ return 0;
}
}
int
ImfHeaderSetV3fAttribute (ImfHeader *hdr,
- const char name[],
- float x, float y, float z)
+ const char name[],
+ float x, float y, float z)
{
try
{
- V3f v (x, y, z);
+ V3f v (x, y, z);
- if (header(hdr)->find(name) == header(hdr)->end())
- header(hdr)->insert (name, Imf::V3fAttribute (v));
- else
- header(hdr)->typedAttribute<Imf::V3fAttribute>(name).value() = v;
+ if (header(hdr)->find(name) == header(hdr)->end())
+ header(hdr)->insert (name, OPENEXR_IMF_INTERNAL_NAMESPACE::V3fAttribute (v));
+ else
+ header(hdr)->typedAttribute<OPENEXR_IMF_INTERNAL_NAMESPACE::V3fAttribute>(name).value() = v;
- return 1;
+ return 1;
}
catch (const std::exception &e)
{
- setErrorMessage (e);
- return 0;
+ setErrorMessage (e);
+ return 0;
}
}
int
ImfHeaderV3fAttribute (const ImfHeader *hdr,
- const char name[],
- float *x, float *y, float *z)
+ const char name[],
+ float *x, float *y, float *z)
{
try
{
- const V3f &v =
- header(hdr)->typedAttribute<Imf::V3fAttribute>(name).value();
+ const V3f &v =
+ header(hdr)->typedAttribute<OPENEXR_IMF_INTERNAL_NAMESPACE::V3fAttribute>(name).value();
- *x = v.x;
- *y = v.y;
- *z = v.z;
+ *x = v.x;
+ *y = v.y;
+ *z = v.z;
- return 1;
+ return 1;
}
catch (const std::exception &e)
{
- setErrorMessage (e);
- return 0;
+ setErrorMessage (e);
+ return 0;
}
}
int
ImfHeaderSetM33fAttribute (ImfHeader *hdr,
- const char name[],
- const float m[3][3])
+ const char name[],
+ const float m[3][3])
{
try
{
- M33f m3 (m);
+ M33f m3 (m);
- if (header(hdr)->find(name) == header(hdr)->end())
- header(hdr)->insert (name, Imf::M33fAttribute (m3));
- else
- header(hdr)->typedAttribute<Imf::M33fAttribute>(name).value() = m3;
+ if (header(hdr)->find(name) == header(hdr)->end())
+ header(hdr)->insert (name, OPENEXR_IMF_INTERNAL_NAMESPACE::M33fAttribute (m3));
+ else
+ header(hdr)->typedAttribute<OPENEXR_IMF_INTERNAL_NAMESPACE::M33fAttribute>(name).value() = m3;
- return 1;
+ return 1;
}
catch (const std::exception &e)
{
- setErrorMessage (e);
- return 0;
+ setErrorMessage (e);
+ return 0;
}
}
int
ImfHeaderM33fAttribute (const ImfHeader *hdr,
- const char name[],
- float m[3][3])
+ const char name[],
+ float m[3][3])
{
try
{
- const M33f &m3 =
- header(hdr)->typedAttribute<Imf::M33fAttribute>(name).value();
+ const M33f &m3 =
+ header(hdr)->typedAttribute<OPENEXR_IMF_INTERNAL_NAMESPACE::M33fAttribute>(name).value();
- m[0][0] = m3[0][0];
- m[0][1] = m3[0][1];
- m[0][2] = m3[0][2];
+ m[0][0] = m3[0][0];
+ m[0][1] = m3[0][1];
+ m[0][2] = m3[0][2];
- m[1][0] = m3[1][0];
- m[1][1] = m3[1][1];
- m[1][2] = m3[1][2];
+ m[1][0] = m3[1][0];
+ m[1][1] = m3[1][1];
+ m[1][2] = m3[1][2];
- m[2][0] = m3[2][0];
- m[2][1] = m3[2][1];
- m[2][2] = m3[2][2];
+ m[2][0] = m3[2][0];
+ m[2][1] = m3[2][1];
+ m[2][2] = m3[2][2];
- return 1;
+ return 1;
}
catch (const std::exception &e)
{
- setErrorMessage (e);
- return 0;
+ setErrorMessage (e);
+ return 0;
}
}
int
ImfHeaderSetM44fAttribute (ImfHeader *hdr,
- const char name[],
- const float m[4][4])
+ const char name[],
+ const float m[4][4])
{
try
{
- M44f m4 (m);
+ M44f m4 (m);
- if (header(hdr)->find(name) == header(hdr)->end())
- header(hdr)->insert (name, Imf::M44fAttribute (m4));
- else
- header(hdr)->typedAttribute<Imf::M44fAttribute>(name).value() = m4;
+ if (header(hdr)->find(name) == header(hdr)->end())
+ header(hdr)->insert (name, OPENEXR_IMF_INTERNAL_NAMESPACE::M44fAttribute (m4));
+ else
+ header(hdr)->typedAttribute<OPENEXR_IMF_INTERNAL_NAMESPACE::M44fAttribute>(name).value() = m4;
- return 1;
+ return 1;
}
catch (const std::exception &e)
{
- setErrorMessage (e);
- return 0;
+ setErrorMessage (e);
+ return 0;
}
}
int
ImfHeaderM44fAttribute (const ImfHeader *hdr,
- const char name[],
- float m[4][4])
+ const char name[],
+ float m[4][4])
{
try
{
- const M44f &m4 =
- header(hdr)->typedAttribute<Imf::M44fAttribute>(name).value();
+ const M44f &m4 =
+ header(hdr)->typedAttribute<OPENEXR_IMF_INTERNAL_NAMESPACE::M44fAttribute>(name).value();
- m[0][0] = m4[0][0];
- m[0][1] = m4[0][1];
- m[0][2] = m4[0][2];
- m[0][3] = m4[0][3];
+ m[0][0] = m4[0][0];
+ m[0][1] = m4[0][1];
+ m[0][2] = m4[0][2];
+ m[0][3] = m4[0][3];
- m[1][0] = m4[1][0];
- m[1][1] = m4[1][1];
- m[1][2] = m4[1][2];
- m[1][3] = m4[1][3];
+ m[1][0] = m4[1][0];
+ m[1][1] = m4[1][1];
+ m[1][2] = m4[1][2];
+ m[1][3] = m4[1][3];
- m[2][0] = m4[2][0];
- m[2][1] = m4[2][1];
- m[2][2] = m4[2][2];
- m[2][3] = m4[2][3];
+ m[2][0] = m4[2][0];
+ m[2][1] = m4[2][1];
+ m[2][2] = m4[2][2];
+ m[2][3] = m4[2][3];
- m[3][0] = m4[3][0];
- m[3][1] = m4[3][1];
- m[3][2] = m4[3][2];
- m[3][3] = m4[3][3];
+ m[3][0] = m4[3][0];
+ m[3][1] = m4[3][1];
+ m[3][2] = m4[3][2];
+ m[3][3] = m4[3][3];
- return 1;
+ return 1;
}
catch (const std::exception &e)
{
- setErrorMessage (e);
- return 0;
+ setErrorMessage (e);
+ return 0;
}
}
-ImfOutputFile *
+ImfOutputFile *
ImfOpenOutputFile (const char name[], const ImfHeader *hdr, int channels)
{
try
{
- return (ImfOutputFile *) new Imf::RgbaOutputFile
- (name, *header(hdr), Imf::RgbaChannels (channels));
+ return (ImfOutputFile *) new OPENEXR_IMF_INTERNAL_NAMESPACE::RgbaOutputFile
+ (name, *header(hdr), OPENEXR_IMF_INTERNAL_NAMESPACE::RgbaChannels (channels));
}
catch (const std::exception &e)
{
- setErrorMessage (e);
- return 0;
+ setErrorMessage (e);
+ return 0;
}
}
-int
+int
ImfCloseOutputFile (ImfOutputFile *out)
{
try
{
- delete outfile (out);
- return 1;
+ delete outfile (out);
+ return 1;
}
catch (const std::exception &e)
{
- setErrorMessage (e);
- return 0;
+ setErrorMessage (e);
+ return 0;
}
}
-int
+int
ImfOutputSetFrameBuffer (ImfOutputFile *out,
- const ImfRgba *base,
- size_t xStride,
- size_t yStride)
+ const ImfRgba *base,
+ size_t xStride,
+ size_t yStride)
{
try
{
- outfile(out)->setFrameBuffer ((Imf::Rgba *)base, xStride, yStride);
- return 1;
+ outfile(out)->setFrameBuffer ((OPENEXR_IMF_INTERNAL_NAMESPACE::Rgba *)base, xStride, yStride);
+ return 1;
}
catch (const std::exception &e)
{
- setErrorMessage (e);
- return 0;
+ setErrorMessage (e);
+ return 0;
}
}
-int
+int
ImfOutputWritePixels (ImfOutputFile *out, int numScanLines)
{
try
{
- outfile(out)->writePixels (numScanLines);
- return 1;
+ outfile(out)->writePixels (numScanLines);
+ return 1;
}
catch (const std::exception &e)
{
- setErrorMessage (e);
- return 0;
+ setErrorMessage (e);
+ return 0;
}
}
}
-ImfTiledOutputFile *
+ImfTiledOutputFile *
ImfOpenTiledOutputFile (const char name[],
- const ImfHeader *hdr,
- int channels,
- int xSize, int ySize,
- int mode, int rmode)
+ const ImfHeader *hdr,
+ int channels,
+ int xSize, int ySize,
+ int mode, int rmode)
{
try
{
- return (ImfTiledOutputFile *) new Imf::TiledRgbaOutputFile
- (name, *header(hdr),
- Imf::RgbaChannels (channels),
- xSize, ySize,
- Imf::LevelMode (mode),
- Imf::LevelRoundingMode (rmode));
+ return (ImfTiledOutputFile *) new OPENEXR_IMF_INTERNAL_NAMESPACE::TiledRgbaOutputFile
+ (name, *header(hdr),
+ OPENEXR_IMF_INTERNAL_NAMESPACE::RgbaChannels (channels),
+ xSize, ySize,
+ OPENEXR_IMF_INTERNAL_NAMESPACE::LevelMode (mode),
+ OPENEXR_IMF_INTERNAL_NAMESPACE::LevelRoundingMode (rmode));
}
catch (const std::exception &e)
{
- setErrorMessage (e);
- return 0;
+ setErrorMessage (e);
+ return 0;
}
}
-int
+int
ImfCloseTiledOutputFile (ImfTiledOutputFile *out)
{
try
{
- delete outfile (out);
- return 1;
+ delete outfile (out);
+ return 1;
}
catch (const std::exception &e)
{
- setErrorMessage (e);
- return 0;
+ setErrorMessage (e);
+ return 0;
}
}
-int
+int
ImfTiledOutputSetFrameBuffer (ImfTiledOutputFile *out,
- const ImfRgba *base,
- size_t xStride,
- size_t yStride)
+ const ImfRgba *base,
+ size_t xStride,
+ size_t yStride)
{
try
{
- outfile(out)->setFrameBuffer ((Imf::Rgba *)base, xStride, yStride);
- return 1;
+ outfile(out)->setFrameBuffer ((OPENEXR_IMF_INTERNAL_NAMESPACE::Rgba *)base, xStride, yStride);
+ return 1;
}
catch (const std::exception &e)
{
- setErrorMessage (e);
- return 0;
+ setErrorMessage (e);
+ return 0;
}
}
-int
+int
ImfTiledOutputWriteTile (ImfTiledOutputFile *out,
- int dx, int dy,
- int lx, int ly)
+ int dx, int dy,
+ int lx, int ly)
{
try
{
- outfile(out)->writeTile (dx, dy, lx, ly);
- return 1;
+ outfile(out)->writeTile (dx, dy, lx, ly);
+ return 1;
}
catch (const std::exception &e)
{
- setErrorMessage (e);
- return 0;
+ setErrorMessage (e);
+ return 0;
}
}
-int
+int
ImfTiledOutputWriteTiles (ImfTiledOutputFile *out,
- int dxMin, int dxMax,
+ int dxMin, int dxMax,
int dyMin, int dyMax,
- int lx, int ly)
+ int lx, int ly)
{
try
{
- outfile(out)->writeTiles (dxMin, dxMax, dyMin, dyMax, lx, ly);
- return 1;
+ outfile(out)->writeTiles (dxMin, dxMax, dyMin, dyMax, lx, ly);
+ return 1;
}
catch (const std::exception &e)
{
- setErrorMessage (e);
- return 0;
+ setErrorMessage (e);
+ return 0;
}
}
}
-ImfInputFile *
+ImfInputFile *
ImfOpenInputFile (const char name[])
{
try
{
- return (ImfInputFile *) new Imf::RgbaInputFile (name);
+ return (ImfInputFile *) new OPENEXR_IMF_INTERNAL_NAMESPACE::RgbaInputFile (name);
}
catch (const std::exception &e)
{
- setErrorMessage (e);
- return 0;
+ setErrorMessage (e);
+ return 0;
}
}
{
try
{
- delete infile (in);
- return 1;
+ delete infile (in);
+ return 1;
}
catch (const std::exception &e)
{
- setErrorMessage (e);
- return 0;
+ setErrorMessage (e);
+ return 0;
}
}
-int
+int
ImfInputSetFrameBuffer (ImfInputFile *in,
- ImfRgba *base,
- size_t xStride,
- size_t yStride)
+ ImfRgba *base,
+ size_t xStride,
+ size_t yStride)
{
try
{
- infile(in)->setFrameBuffer ((Imf::Rgba *) base, xStride, yStride);
- return 1;
+ infile(in)->setFrameBuffer ((OPENEXR_IMF_INTERNAL_NAMESPACE::Rgba *) base, xStride, yStride);
+ return 1;
}
catch (const std::exception &e)
{
- setErrorMessage (e);
- return 0;
+ setErrorMessage (e);
+ return 0;
}
}
{
try
{
- infile(in)->readPixels (scanLine1, scanLine2);
- return 1;
+ infile(in)->readPixels (scanLine1, scanLine2);
+ return 1;
}
catch (const std::exception &e)
{
- setErrorMessage (e);
- return 0;
+ setErrorMessage (e);
+ return 0;
}
}
}
-ImfTiledInputFile *
+ImfTiledInputFile *
ImfOpenTiledInputFile (const char name[])
{
try
{
- return (ImfTiledInputFile *) new Imf::TiledRgbaInputFile (name);
+ return (ImfTiledInputFile *) new OPENEXR_IMF_INTERNAL_NAMESPACE::TiledRgbaInputFile (name);
}
catch (const std::exception &e)
{
- setErrorMessage (e);
- return 0;
+ setErrorMessage (e);
+ return 0;
}
}
{
try
{
- delete infile (in);
- return 1;
+ delete infile (in);
+ return 1;
}
catch (const std::exception &e)
{
- setErrorMessage (e);
- return 0;
+ setErrorMessage (e);
+ return 0;
}
}
-int
+int
ImfTiledInputSetFrameBuffer (ImfTiledInputFile *in,
- ImfRgba *base,
- size_t xStride,
- size_t yStride)
+ ImfRgba *base,
+ size_t xStride,
+ size_t yStride)
{
try
{
- infile(in)->setFrameBuffer ((Imf::Rgba *) base, xStride, yStride);
- return 1;
+ infile(in)->setFrameBuffer ((OPENEXR_IMF_INTERNAL_NAMESPACE::Rgba *) base, xStride, yStride);
+ return 1;
}
catch (const std::exception &e)
{
- setErrorMessage (e);
- return 0;
+ setErrorMessage (e);
+ return 0;
}
}
int
ImfTiledInputReadTile (ImfTiledInputFile *in,
- int dx, int dy,
- int lx, int ly)
+ int dx, int dy,
+ int lx, int ly)
{
try
{
- infile(in)->readTile (dx, dy, lx, ly);
- return 1;
+ infile(in)->readTile (dx, dy, lx, ly);
+ return 1;
}
catch (const std::exception &e)
{
- setErrorMessage (e);
- return 0;
+ setErrorMessage (e);
+ return 0;
}
}
int
ImfTiledInputReadTiles (ImfTiledInputFile *in,
- int dxMin, int dxMax,
+ int dxMin, int dxMax,
int dyMin, int dyMax,
- int lx, int ly)
+ int lx, int ly)
{
try
{
- infile(in)->readTiles (dxMin, dxMax, dyMin, dyMax, lx, ly);
- return 1;
+ infile(in)->readTiles (dxMin, dxMax, dyMin, dyMax, lx, ly);
+ return 1;
}
catch (const std::exception &e)
{
- setErrorMessage (e);
- return 0;
+ setErrorMessage (e);
+ return 0;
}
}
{
try
{
- return (ImfLut *) new Imf::RgbaLut
- (Imf::round12log, Imf::RgbaChannels (channels));
+ return (ImfLut *) new OPENEXR_IMF_INTERNAL_NAMESPACE::RgbaLut
+ (OPENEXR_IMF_INTERNAL_NAMESPACE::round12log, OPENEXR_IMF_INTERNAL_NAMESPACE::RgbaChannels (channels));
}
catch (const std::exception &e)
{
- setErrorMessage (e);
- return 0;
+ setErrorMessage (e);
+ return 0;
}
}
{
try
{
- return (ImfLut *) new Imf::RgbaLut
- (Imf::roundNBit (n), Imf::RgbaChannels (channels));
+ return (ImfLut *) new OPENEXR_IMF_INTERNAL_NAMESPACE::RgbaLut
+ (OPENEXR_IMF_INTERNAL_NAMESPACE::roundNBit (n), OPENEXR_IMF_INTERNAL_NAMESPACE::RgbaChannels (channels));
}
catch (const std::exception &e)
{
- setErrorMessage (e);
- return 0;
+ setErrorMessage (e);
+ return 0;
}
}
void
ImfDeleteLut (ImfLut *lut)
{
- delete (Imf::RgbaLut *) lut;
+ delete (OPENEXR_IMF_INTERNAL_NAMESPACE::RgbaLut *) lut;
}
void
ImfApplyLut (ImfLut *lut, ImfRgba *data, int nData, int stride)
{
- ((Imf::RgbaLut *)lut)->apply ((Imf::Rgba *)data, nData, stride);
+ ((OPENEXR_IMF_INTERNAL_NAMESPACE::RgbaLut *)lut)->apply ((OPENEXR_IMF_INTERNAL_NAMESPACE::Rgba *)data, nData, stride);
}
-const char *
+const char *
ImfErrorMessage ()
{
return errorMessage;
distribution.
* Neither the name of Industrial Light & Magic nor the names of
its contributors may be used to endorse or promote products derived
-from this software without specific prior written permission.
+from this software without specific prior written permission.
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
"AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
#ifndef INCLUDED_IMF_C_RGBA_FILE_H
#define INCLUDED_IMF_C_RGBA_FILE_H
+#include "ImfExport.h"
#include <stdlib.h>
typedef unsigned short ImfHalf;
+IMF_EXPORT
void ImfFloatToHalf (float f,
- ImfHalf *h);
+ ImfHalf *h);
+IMF_EXPORT
void ImfFloatToHalfArray (int n,
- const float f[/*n*/],
- ImfHalf h[/*n*/]);
+ const float f[/*n*/],
+ ImfHalf h[/*n*/]);
+IMF_EXPORT
float ImfHalfToFloat (ImfHalf h);
+IMF_EXPORT
void ImfHalfToFloatArray (int n,
- const ImfHalf h[/*n*/],
- float f[/*n*/]);
+ const ImfHalf h[/*n*/],
+ float f[/*n*/]);
/*
** RGBA pixel; memory layout must be the same as struct Imf::Rgba.
#define IMF_INCREASING_Y 0
#define IMF_DECREASING_Y 1
-#define IMF_RAMDOM_Y 2
+#define IMF_RANDOM_Y 2
/*
struct ImfHeader;
typedef struct ImfHeader ImfHeader;
+IMF_EXPORT
ImfHeader * ImfNewHeader (void);
+IMF_EXPORT
void ImfDeleteHeader (ImfHeader *hdr);
+IMF_EXPORT
ImfHeader * ImfCopyHeader (const ImfHeader *hdr);
+IMF_EXPORT
void ImfHeaderSetDisplayWindow (ImfHeader *hdr,
- int xMin, int yMin,
- int xMax, int yMax);
+ int xMin, int yMin,
+ int xMax, int yMax);
+IMF_EXPORT
void ImfHeaderDisplayWindow (const ImfHeader *hdr,
- int *xMin, int *yMin,
- int *xMax, int *yMax);
+ int *xMin, int *yMin,
+ int *xMax, int *yMax);
+IMF_EXPORT
void ImfHeaderSetDataWindow (ImfHeader *hdr,
- int xMin, int yMin,
- int xMax, int yMax);
+ int xMin, int yMin,
+ int xMax, int yMax);
+IMF_EXPORT
void ImfHeaderDataWindow (const ImfHeader *hdr,
- int *xMin, int *yMin,
- int *xMax, int *yMax);
+ int *xMin, int *yMin,
+ int *xMax, int *yMax);
+IMF_EXPORT
void ImfHeaderSetPixelAspectRatio (ImfHeader *hdr,
- float pixelAspectRatio);
+ float pixelAspectRatio);
+IMF_EXPORT
float ImfHeaderPixelAspectRatio (const ImfHeader *hdr);
+IMF_EXPORT
void ImfHeaderSetScreenWindowCenter (ImfHeader *hdr,
- float x, float y);
+ float x, float y);
+IMF_EXPORT
void ImfHeaderScreenWindowCenter (const ImfHeader *hdr,
- float *x, float *y);
+ float *x, float *y);
+IMF_EXPORT
void ImfHeaderSetScreenWindowWidth (ImfHeader *hdr,
- float width);
+ float width);
+IMF_EXPORT
float ImfHeaderScreenWindowWidth (const ImfHeader *hdr);
+IMF_EXPORT
void ImfHeaderSetLineOrder (ImfHeader *hdr,
- int lineOrder);
+ int lineOrder);
+IMF_EXPORT
int ImfHeaderLineOrder (const ImfHeader *hdr);
-
+
+IMF_EXPORT
void ImfHeaderSetCompression (ImfHeader *hdr,
- int compression);
+ int compression);
+IMF_EXPORT
int ImfHeaderCompression (const ImfHeader *hdr);
+IMF_EXPORT
int ImfHeaderSetIntAttribute (ImfHeader *hdr,
- const char name[],
- int value);
+ const char name[],
+ int value);
+IMF_EXPORT
int ImfHeaderIntAttribute (const ImfHeader *hdr,
- const char name[],
- int *value);
+ const char name[],
+ int *value);
+IMF_EXPORT
int ImfHeaderSetFloatAttribute (ImfHeader *hdr,
- const char name[],
- float value);
+ const char name[],
+ float value);
+IMF_EXPORT
int ImfHeaderSetDoubleAttribute (ImfHeader *hdr,
- const char name[],
- double value);
+ const char name[],
+ double value);
+IMF_EXPORT
int ImfHeaderFloatAttribute (const ImfHeader *hdr,
- const char name[],
- float *value);
+ const char name[],
+ float *value);
+IMF_EXPORT
int ImfHeaderDoubleAttribute (const ImfHeader *hdr,
- const char name[],
- double *value);
+ const char name[],
+ double *value);
+IMF_EXPORT
int ImfHeaderSetStringAttribute (ImfHeader *hdr,
- const char name[],
- const char value[]);
+ const char name[],
+ const char value[]);
+IMF_EXPORT
int ImfHeaderStringAttribute (const ImfHeader *hdr,
- const char name[],
- const char **value);
+ const char name[],
+ const char **value);
+IMF_EXPORT
int ImfHeaderSetBox2iAttribute (ImfHeader *hdr,
- const char name[],
- int xMin, int yMin,
- int xMax, int yMax);
+ const char name[],
+ int xMin, int yMin,
+ int xMax, int yMax);
+IMF_EXPORT
int ImfHeaderBox2iAttribute (const ImfHeader *hdr,
- const char name[],
- int *xMin, int *yMin,
- int *xMax, int *yMax);
+ const char name[],
+ int *xMin, int *yMin,
+ int *xMax, int *yMax);
+IMF_EXPORT
int ImfHeaderSetBox2fAttribute (ImfHeader *hdr,
- const char name[],
- float xMin, float yMin,
- float xMax, float yMax);
+ const char name[],
+ float xMin, float yMin,
+ float xMax, float yMax);
+IMF_EXPORT
int ImfHeaderBox2fAttribute (const ImfHeader *hdr,
- const char name[],
- float *xMin, float *yMin,
- float *xMax, float *yMax);
+ const char name[],
+ float *xMin, float *yMin,
+ float *xMax, float *yMax);
+IMF_EXPORT
int ImfHeaderSetV2iAttribute (ImfHeader *hdr,
- const char name[],
- int x, int y);
+ const char name[],
+ int x, int y);
+IMF_EXPORT
int ImfHeaderV2iAttribute (const ImfHeader *hdr,
- const char name[],
- int *x, int *y);
+ const char name[],
+ int *x, int *y);
+IMF_EXPORT
int ImfHeaderSetV2fAttribute (ImfHeader *hdr,
- const char name[],
- float x, float y);
+ const char name[],
+ float x, float y);
+IMF_EXPORT
int ImfHeaderV2fAttribute (const ImfHeader *hdr,
- const char name[],
- float *x, float *y);
+ const char name[],
+ float *x, float *y);
+IMF_EXPORT
int ImfHeaderSetV3iAttribute (ImfHeader *hdr,
- const char name[],
- int x, int y, int z);
+ const char name[],
+ int x, int y, int z);
+IMF_EXPORT
int ImfHeaderV3iAttribute (const ImfHeader *hdr,
- const char name[],
- int *x, int *y, int *z);
+ const char name[],
+ int *x, int *y, int *z);
+IMF_EXPORT
int ImfHeaderSetV3fAttribute (ImfHeader *hdr,
- const char name[],
- float x, float y, float z);
+ const char name[],
+ float x, float y, float z);
+IMF_EXPORT
int ImfHeaderV3fAttribute (const ImfHeader *hdr,
- const char name[],
- float *x, float *y, float *z);
+ const char name[],
+ float *x, float *y, float *z);
+IMF_EXPORT
int ImfHeaderSetM33fAttribute (ImfHeader *hdr,
- const char name[],
- const float m[3][3]);
+ const char name[],
+ const float m[3][3]);
+IMF_EXPORT
int ImfHeaderM33fAttribute (const ImfHeader *hdr,
- const char name[],
- float m[3][3]);
+ const char name[],
+ float m[3][3]);
+IMF_EXPORT
int ImfHeaderSetM44fAttribute (ImfHeader *hdr,
- const char name[],
- const float m[4][4]);
+ const char name[],
+ const float m[4][4]);
+IMF_EXPORT
int ImfHeaderM44fAttribute (const ImfHeader *hdr,
- const char name[],
- float m[4][4]);
+ const char name[],
+ float m[4][4]);
/*
** RGBA output file
struct ImfOutputFile;
typedef struct ImfOutputFile ImfOutputFile;
+IMF_EXPORT
ImfOutputFile * ImfOpenOutputFile (const char name[],
- const ImfHeader *hdr,
- int channels);
+ const ImfHeader *hdr,
+ int channels);
+IMF_EXPORT
int ImfCloseOutputFile (ImfOutputFile *out);
+IMF_EXPORT
int ImfOutputSetFrameBuffer (ImfOutputFile *out,
- const ImfRgba *base,
- size_t xStride,
- size_t yStride);
+ const ImfRgba *base,
+ size_t xStride,
+ size_t yStride);
+IMF_EXPORT
int ImfOutputWritePixels (ImfOutputFile *out,
- int numScanLines);
+ int numScanLines);
+IMF_EXPORT
int ImfOutputCurrentScanLine (const ImfOutputFile *out);
+IMF_EXPORT
const ImfHeader * ImfOutputHeader (const ImfOutputFile *out);
+IMF_EXPORT
int ImfOutputChannels (const ImfOutputFile *out);
struct ImfTiledOutputFile;
typedef struct ImfTiledOutputFile ImfTiledOutputFile;
+IMF_EXPORT
ImfTiledOutputFile * ImfOpenTiledOutputFile (const char name[],
- const ImfHeader *hdr,
- int channels,
- int xSize, int ySize,
- int mode, int rmode);
+ const ImfHeader *hdr,
+ int channels,
+ int xSize, int ySize,
+ int mode, int rmode);
+IMF_EXPORT
int ImfCloseTiledOutputFile (ImfTiledOutputFile *out);
+IMF_EXPORT
int ImfTiledOutputSetFrameBuffer (ImfTiledOutputFile *out,
- const ImfRgba *base,
- size_t xStride,
- size_t yStride);
+ const ImfRgba *base,
+ size_t xStride,
+ size_t yStride);
+IMF_EXPORT
int ImfTiledOutputWriteTile (ImfTiledOutputFile *out,
- int dx, int dy,
- int lx, int ly);
+ int dx, int dy,
+ int lx, int ly);
+IMF_EXPORT
int ImfTiledOutputWriteTiles (ImfTiledOutputFile *out,
int dxMin, int dxMax,
int dyMin, int dyMax,
int lx, int ly);
+IMF_EXPORT
const ImfHeader * ImfTiledOutputHeader (const ImfTiledOutputFile *out);
+IMF_EXPORT
int ImfTiledOutputChannels (const ImfTiledOutputFile *out);
+IMF_EXPORT
int ImfTiledOutputTileXSize (const ImfTiledOutputFile *out);
+IMF_EXPORT
int ImfTiledOutputTileYSize (const ImfTiledOutputFile *out);
+IMF_EXPORT
int ImfTiledOutputLevelMode (const ImfTiledOutputFile *out);
+
+IMF_EXPORT
int ImfTiledOutputLevelRoundingMode
- (const ImfTiledOutputFile *out);
+ (const ImfTiledOutputFile *out);
/*
ImfInputFile * ImfOpenInputFile (const char name[]);
+IMF_EXPORT
int ImfCloseInputFile (ImfInputFile *in);
+IMF_EXPORT
int ImfInputSetFrameBuffer (ImfInputFile *in,
- ImfRgba *base,
- size_t xStride,
- size_t yStride);
+ ImfRgba *base,
+ size_t xStride,
+ size_t yStride);
+IMF_EXPORT
int ImfInputReadPixels (ImfInputFile *in,
- int scanLine1,
- int scanLine2);
+ int scanLine1,
+ int scanLine2);
+IMF_EXPORT
const ImfHeader * ImfInputHeader (const ImfInputFile *in);
+IMF_EXPORT
int ImfInputChannels (const ImfInputFile *in);
+IMF_EXPORT
const char * ImfInputFileName (const ImfInputFile *in);
struct ImfTiledInputFile;
typedef struct ImfTiledInputFile ImfTiledInputFile;
+IMF_EXPORT
ImfTiledInputFile * ImfOpenTiledInputFile (const char name[]);
+IMF_EXPORT
int ImfCloseTiledInputFile (ImfTiledInputFile *in);
+IMF_EXPORT
int ImfTiledInputSetFrameBuffer (ImfTiledInputFile *in,
- ImfRgba *base,
- size_t xStride,
- size_t yStride);
+ ImfRgba *base,
+ size_t xStride,
+ size_t yStride);
+IMF_EXPORT
int ImfTiledInputReadTile (ImfTiledInputFile *in,
- int dx, int dy,
- int lx, int ly);
+ int dx, int dy,
+ int lx, int ly);
+IMF_EXPORT
int ImfTiledInputReadTiles (ImfTiledInputFile *in,
int dxMin, int dxMax,
int dyMin, int dyMax,
int lx, int ly);
+IMF_EXPORT
const ImfHeader * ImfTiledInputHeader (const ImfTiledInputFile *in);
+IMF_EXPORT
int ImfTiledInputChannels (const ImfTiledInputFile *in);
+IMF_EXPORT
const char * ImfTiledInputFileName (const ImfTiledInputFile *in);
+IMF_EXPORT
int ImfTiledInputTileXSize (const ImfTiledInputFile *in);
+IMF_EXPORT
int ImfTiledInputTileYSize (const ImfTiledInputFile *in);
+IMF_EXPORT
int ImfTiledInputLevelMode (const ImfTiledInputFile *in);
+IMF_EXPORT
int ImfTiledInputLevelRoundingMode
- (const ImfTiledInputFile *in);
+ (const ImfTiledInputFile *in);
/*
** Lookup tables
struct ImfLut;
typedef struct ImfLut ImfLut;
+IMF_EXPORT
ImfLut * ImfNewRound12logLut (int channels);
+IMF_EXPORT
ImfLut * ImfNewRoundNBitLut (unsigned int n, int channels);
+IMF_EXPORT
void ImfDeleteLut (ImfLut *lut);
+IMF_EXPORT
void ImfApplyLut (ImfLut *lut,
- ImfRgba *data,
- int nData,
- int stride);
+ ImfRgba *data,
+ int nData,
+ int stride);
/*
** Most recent error message
*/
+IMF_EXPORT
const char * ImfErrorMessage (void);
//
// Copyright (c) 2002, Industrial Light & Magic, a division of Lucas
// Digital Ltd. LLC
-//
+//
// All rights reserved.
-//
+//
// Redistribution and use in source and binary forms, with or without
// modification, are permitted provided that the following conditions are
// met:
// distribution.
// * Neither the name of Industrial Light & Magic nor the names of
// its contributors may be used to endorse or promote products derived
-// from this software without specific prior written permission.
-//
+// from this software without specific prior written permission.
+//
// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
using std::string;
using std::set;
+#include "ImfNamespace.h"
-namespace Imf {
+OPENEXR_IMF_INTERNAL_NAMESPACE_SOURCE_ENTER
Channel::Channel (PixelType t, int xs, int ys, bool pl):
}
-bool
+bool
Channel::operator == (const Channel &other) const
{
return type == other.type &&
- xSampling == other.xSampling &&
- ySampling == other.ySampling &&
- pLinear == other.pLinear;
+ xSampling == other.xSampling &&
+ ySampling == other.ySampling &&
+ pLinear == other.pLinear;
}
-void
+void
ChannelList::insert (const char name[], const Channel &channel)
{
if (name[0] == 0)
- THROW (Iex::ArgExc, "Image channel name cannot be an empty string.");
+ THROW (IEX_NAMESPACE::ArgExc, "Image channel name cannot be an empty string.");
_map[name] = channel;
}
-void
+void
ChannelList::insert (const string &name, const Channel &channel)
{
insert (name.c_str(), channel);
ChannelMap::iterator i = _map.find (name);
if (i == _map.end())
- THROW (Iex::ArgExc, "Cannot find image channel \"" << name << "\".");
+ THROW (IEX_NAMESPACE::ArgExc, "Cannot find image channel \"" << name << "\".");
return i->second;
}
ChannelMap::const_iterator i = _map.find (name);
if (i == _map.end())
- THROW (Iex::ArgExc, "Cannot find image channel \"" << name << "\".");
+ THROW (IEX_NAMESPACE::ArgExc, "Cannot find image channel \"" << name << "\".");
return i->second;
}
}
-ChannelList::Iterator
+ChannelList::Iterator
ChannelList::begin ()
{
return _map.begin();
}
-ChannelList::ConstIterator
+ChannelList::ConstIterator
ChannelList::begin () const
{
return _map.begin();
}
-ChannelList::ConstIterator
+ChannelList::ConstIterator
ChannelList::end () const
{
return _map.end();
for (ConstIterator i = begin(); i != end(); ++i)
{
- string layerName = i.name();
- size_t pos = layerName.rfind ('.');
-
- if (pos != string::npos && pos != 0 && pos + 1 < layerName.size())
- {
- layerName.erase (pos);
- layerNames.insert (layerName);
- }
+ string layerName = i.name();
+ size_t pos = layerName.rfind ('.');
+
+ if (pos != string::npos && pos != 0 && pos + 1 < layerName.size())
+ {
+ layerName.erase (pos);
+ layerNames.insert (layerName);
+ }
}
}
void
ChannelList::channelsInLayer (const string &layerName,
- Iterator &first,
- Iterator &last)
+ Iterator &first,
+ Iterator &last)
{
channelsWithPrefix (layerName + '.', first, last);
}
void
ChannelList::channelsInLayer (const string &layerName,
- ConstIterator &first,
- ConstIterator &last) const
+ ConstIterator &first,
+ ConstIterator &last) const
{
channelsWithPrefix (layerName + '.', first, last);
}
-void
+void
ChannelList::channelsWithPrefix (const char prefix[],
- Iterator &first,
- Iterator &last)
+ Iterator &first,
+ Iterator &last)
{
first = last = _map.lower_bound (prefix);
- int n = strlen (prefix);
+ size_t n = int(strlen (prefix));
while (last != Iterator (_map.end()) &&
- strncmp (last.name(), prefix, n) <= 0)
+ strncmp (last.name(), prefix, n) <= 0)
{
- ++last;
+ ++last;
}
}
void
ChannelList::channelsWithPrefix (const char prefix[],
- ConstIterator &first,
- ConstIterator &last) const
+ ConstIterator &first,
+ ConstIterator &last) const
{
first = last = _map.lower_bound (prefix);
- int n = strlen (prefix);
+ size_t n = strlen (prefix);
while (last != ConstIterator (_map.end()) &&
- strncmp (last.name(), prefix, n) <= 0)
+ strncmp (last.name(), prefix, n) <= 0)
{
- ++last;
+ ++last;
}
}
-void
+void
ChannelList::channelsWithPrefix (const string &prefix,
- Iterator &first,
- Iterator &last)
+ Iterator &first,
+ Iterator &last)
{
return channelsWithPrefix (prefix.c_str(), first, last);
}
void
ChannelList::channelsWithPrefix (const string &prefix,
- ConstIterator &first,
- ConstIterator &last) const
+ ConstIterator &first,
+ ConstIterator &last) const
{
return channelsWithPrefix (prefix.c_str(), first, last);
}
-bool
+bool
ChannelList::operator == (const ChannelList &other) const
{
ConstIterator i = begin();
while (i != end() && j != other.end())
{
- if (!(i.channel() == j.channel()))
- return false;
+ if (!(i.channel() == j.channel()))
+ return false;
- ++i;
- ++j;
+ ++i;
+ ++j;
}
return i == end() && j == other.end();
}
-} // namespace Imf
+OPENEXR_IMF_INTERNAL_NAMESPACE_SOURCE_EXIT
//
// Copyright (c) 2002, Industrial Light & Magic, a division of Lucas
// Digital Ltd. LLC
-//
+//
// All rights reserved.
-//
+//
// Redistribution and use in source and binary forms, with or without
// modification, are permitted provided that the following conditions are
// met:
// distribution.
// * Neither the name of Industrial Light & Magic nor the names of
// its contributors may be used to endorse or promote products derived
-// from this software without specific prior written permission.
-//
+// from this software without specific prior written permission.
+//
// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
//
//-----------------------------------------------------------------------------
-#include <ImfName.h>
-#include <ImfPixelType.h>
+#include "ImfName.h"
+#include "ImfPixelType.h"
+
+#include "ImfNamespace.h"
+#include "ImfExport.h"
+
#include <map>
#include <set>
#include <string>
-
-namespace Imf {
+OPENEXR_IMF_INTERNAL_NAMESPACE_HEADER_ENTER
struct Channel
//--------------------------------------------
// Subsampling: pixel (x, y) is present in the
- // channel only if
+ // channel only if
//
// x % xSampling == 0 && y % ySampling == 0
//
//------------
// Constructor
//------------
-
+
+ IMF_EXPORT
Channel (PixelType type = HALF,
- int xSampling = 1,
- int ySampling = 1,
- bool pLinear = false);
+ int xSampling = 1,
+ int ySampling = 1,
+ bool pLinear = false);
//------------
// Operator ==
//------------
+ IMF_EXPORT
bool operator == (const Channel &other) const;
};
// Add a channel
//--------------
+ IMF_EXPORT
void insert (const char name[],
- const Channel &channel);
+ const Channel &channel);
+ IMF_EXPORT
void insert (const std::string &name,
- const Channel &channel);
+ const Channel &channel);
//------------------------------------------------------------------
// Access to existing channels:
//
// [n] Returns a reference to the channel with name n.
- // If no channel with name n exists, an Iex::ArgExc
+ // If no channel with name n exists, an IEX_NAMESPACE::ArgExc
// is thrown.
//
// findChannel(n) Returns a pointer to the channel with name n,
//
//------------------------------------------------------------------
+ IMF_EXPORT
Channel & operator [] (const char name[]);
+ IMF_EXPORT
const Channel & operator [] (const char name[]) const;
+ IMF_EXPORT
Channel & operator [] (const std::string &name);
+ IMF_EXPORT
const Channel & operator [] (const std::string &name) const;
+ IMF_EXPORT
Channel * findChannel (const char name[]);
+ IMF_EXPORT
const Channel * findChannel (const char name[]) const;
+ IMF_EXPORT
Channel * findChannel (const std::string &name);
+ IMF_EXPORT
const Channel * findChannel (const std::string &name) const;
class Iterator;
class ConstIterator;
+ IMF_EXPORT
Iterator begin ();
+ IMF_EXPORT
ConstIterator begin () const;
+ IMF_EXPORT
Iterator end ();
+ IMF_EXPORT
ConstIterator end () const;
+ IMF_EXPORT
Iterator find (const char name[]);
+ IMF_EXPORT
ConstIterator find (const char name[]) const;
+ IMF_EXPORT
Iterator find (const std::string &name);
+ IMF_EXPORT
ConstIterator find (const std::string &name) const;
-
+
//-----------------------------------------------------------------
// Support for image layers:
//
// several different virtual light sources. The channels in
// this image might be called "light1.R", "light1.G", "light1.B",
// "light2.R", "light2.G", "light2.B", etc.
- //
+ //
// Note that this naming convention allows layers to be nested;
// for example, "light1.specular.R" identifies the "R" channel
// in the "specular" sub-layer of layer "light1".
//
//-----------------------------------------------------------------
+ IMF_EXPORT
void layers (std::set <std::string> &layerNames) const;
+ IMF_EXPORT
void channelsInLayer (const std::string &layerName,
- Iterator &first,
- Iterator &last);
+ Iterator &first,
+ Iterator &last);
+ IMF_EXPORT
void channelsInLayer (const std::string &layerName,
- ConstIterator &first,
- ConstIterator &last) const;
+ ConstIterator &first,
+ ConstIterator &last) const;
//-------------------------------------------------------------------
//
//-------------------------------------------------------------------
+ IMF_EXPORT
void channelsWithPrefix (const char prefix[],
- Iterator &first,
- Iterator &last);
+ Iterator &first,
+ Iterator &last);
+ IMF_EXPORT
void channelsWithPrefix (const char prefix[],
- ConstIterator &first,
- ConstIterator &last) const;
+ ConstIterator &first,
+ ConstIterator &last) const;
+ IMF_EXPORT
void channelsWithPrefix (const std::string &prefix,
- Iterator &first,
- Iterator &last);
+ Iterator &first,
+ Iterator &last);
+ IMF_EXPORT
void channelsWithPrefix (const std::string &prefix,
- ConstIterator &first,
- ConstIterator &last) const;
+ ConstIterator &first,
+ ConstIterator &last) const;
//------------
// Operator ==
//------------
+ IMF_EXPORT
bool operator == (const ChannelList &other) const;
private:
{
public:
+ IMF_EXPORT
Iterator ();
+ IMF_EXPORT
Iterator (const ChannelList::ChannelMap::iterator &i);
+ IMF_EXPORT
Iterator & operator ++ ();
+ IMF_EXPORT
Iterator operator ++ (int);
+ IMF_EXPORT
const char * name () const;
+ IMF_EXPORT
Channel & channel () const;
private:
{
public:
+ IMF_EXPORT
ConstIterator ();
+ IMF_EXPORT
ConstIterator (const ChannelList::ChannelMap::const_iterator &i);
+ IMF_EXPORT
ConstIterator (const ChannelList::Iterator &other);
+ IMF_EXPORT
ConstIterator & operator ++ ();
+ IMF_EXPORT
ConstIterator operator ++ (int);
+ IMF_EXPORT
const char * name () const;
+ IMF_EXPORT
const Channel & channel () const;
private:
}
-inline ChannelList::Iterator &
+inline ChannelList::Iterator &
ChannelList::Iterator::operator ++ ()
{
++_i;
}
-inline ChannelList::Iterator
+inline ChannelList::Iterator
ChannelList::Iterator::operator ++ (int)
{
Iterator tmp = *this;
}
-inline Channel &
+inline Channel &
ChannelList::Iterator::channel () const
{
return _i->second;
}
-inline ChannelList::ConstIterator
+inline ChannelList::ConstIterator
ChannelList::ConstIterator::operator ++ (int)
{
ConstIterator tmp = *this;
return *_i->first;
}
-inline const Channel &
+inline const Channel &
ChannelList::ConstIterator::channel () const
{
return _i->second;
inline bool
operator == (const ChannelList::ConstIterator &x,
- const ChannelList::ConstIterator &y)
+ const ChannelList::ConstIterator &y)
{
return x._i == y._i;
}
inline bool
operator != (const ChannelList::ConstIterator &x,
- const ChannelList::ConstIterator &y)
+ const ChannelList::ConstIterator &y)
{
return !(x == y);
}
-} // namespace Imf
+OPENEXR_IMF_INTERNAL_NAMESPACE_HEADER_EXIT
#endif
//
// Copyright (c) 2002, Industrial Light & Magic, a division of Lucas
// Digital Ltd. LLC
-//
+//
// All rights reserved.
-//
+//
// Redistribution and use in source and binary forms, with or without
// modification, are permitted provided that the following conditions are
// met:
// distribution.
// * Neither the name of Industrial Light & Magic nor the names of
// its contributors may be used to endorse or promote products derived
-// from this software without specific prior written permission.
-//
+// from this software without specific prior written permission.
+//
// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
#include <ImfChannelListAttribute.h>
-
-namespace Imf {
+OPENEXR_IMF_INTERNAL_NAMESPACE_SOURCE_ENTER
namespace {
template <size_t N>
void checkIsNullTerminated (const char (&str)[N], const char *what)
{
- for (int i = 0; i < N; ++i) {
+ for (size_t i = 0; i < N; ++i) {
if (str[i] == '\0')
return;
}
std::stringstream s;
- s << "Invalid " << what << ": it is more than " << (N - 1)
+ s << "Invalid " << what << ": it is more than " << (N - 1)
<< " characters long.";
- throw Iex::InputExc(s);
+ throw IEX_NAMESPACE::InputExc(s);
}
} // namespace
+
template <>
const char *
ChannelListAttribute::staticTypeName ()
return "chlist";
}
+using namespace OPENEXR_IMF_INTERNAL_NAMESPACE;
template <>
void
-ChannelListAttribute::writeValueTo (OStream &os, int) const
+ChannelListAttribute::writeValueTo (OStream &os, int version) const
{
for (ChannelList::ConstIterator i = _value.begin();
- i != _value.end();
- ++i)
+ i != _value.end();
+ ++i)
{
- //
- // Write name
- //
+ //
+ // Write name
+ //
- Xdr::write <StreamIO> (os, i.name());
+ Xdr::write <StreamIO> (os, i.name());
- //
- // Write Channel struct
- //
+ //
+ // Write Channel struct
+ //
- Xdr::write <StreamIO> (os, int (i.channel().type));
- Xdr::write <StreamIO> (os, i.channel().pLinear);
- Xdr::pad <StreamIO> (os, 3);
- Xdr::write <StreamIO> (os, i.channel().xSampling);
- Xdr::write <StreamIO> (os, i.channel().ySampling);
+ Xdr::write <StreamIO> (os, int (i.channel().type));
+ Xdr::write <StreamIO> (os, i.channel().pLinear);
+ Xdr::pad <StreamIO> (os, 3);
+ Xdr::write <StreamIO> (os, i.channel().xSampling);
+ Xdr::write <StreamIO> (os, i.channel().ySampling);
}
//
template <>
void
-ChannelListAttribute::readValueFrom (IStream &is, int, int)
+ChannelListAttribute::readValueFrom (IStream &is,
+ int size,
+ int version)
{
while (true)
{
- //
- // Read name; zero length name means end of channel list
- //
+ //
+ // Read name; zero length name means end of channel list
+ //
- char name[Name::SIZE];
- Xdr::read <StreamIO> (is, Name::MAX_LENGTH, name);
+ char name[Name::SIZE];
+ Xdr::read <StreamIO> (is,Name::MAX_LENGTH,name);
- if (name[0] == 0)
- break;
+ if (name[0] == 0)
+ break;
- checkIsNullTerminated (name, "channel name");
+ checkIsNullTerminated (name, "channel name");
- //
- // Read Channel struct
- //
+ //
+ // Read Channel struct
+ //
- int type;
- bool pLinear;
- int xSampling;
- int ySampling;
+ int type;
+ bool pLinear;
+ int xSampling;
+ int ySampling;
- Xdr::read <StreamIO> (is, type);
- Xdr::read <StreamIO> (is, pLinear);
- Xdr::skip <StreamIO> (is, 3);
- Xdr::read <StreamIO> (is, xSampling);
- Xdr::read <StreamIO> (is, ySampling);
+ Xdr::read <StreamIO> (is, type);
+ Xdr::read <StreamIO> (is, pLinear);
+ Xdr::skip <StreamIO> (is, 3);
+ Xdr::read <StreamIO> (is, xSampling);
+ Xdr::read <StreamIO> (is, ySampling);
- _value.insert
- (name, Channel (PixelType (type), xSampling, ySampling, pLinear));
+ _value.insert (name, Channel (PixelType (type),
+ xSampling,
+ ySampling,
+ pLinear));
}
}
-} // namespace Imf
+OPENEXR_IMF_INTERNAL_NAMESPACE_SOURCE_EXIT
//
// Copyright (c) 2002, Industrial Light & Magic, a division of Lucas
// Digital Ltd. LLC
-//
+//
// All rights reserved.
-//
+//
// Redistribution and use in source and binary forms, with or without
// modification, are permitted provided that the following conditions are
// met:
// distribution.
// * Neither the name of Industrial Light & Magic nor the names of
// its contributors may be used to endorse or promote products derived
-// from this software without specific prior written permission.
-//
+// from this software without specific prior written permission.
+//
// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
//
//-----------------------------------------------------------------------------
-#include <ImfAttribute.h>
-#include <ImfChannelList.h>
+#include "ImfAttribute.h"
+#include "ImfChannelList.h"
+#include "ImfExport.h"
+OPENEXR_IMF_INTERNAL_NAMESPACE_HEADER_ENTER
-namespace Imf {
+typedef TypedAttribute<OPENEXR_IMF_INTERNAL_NAMESPACE::ChannelList> ChannelListAttribute;
-typedef TypedAttribute<ChannelList> ChannelListAttribute;
-template <> const char *ChannelListAttribute::staticTypeName ();
-template <> void ChannelListAttribute::writeValueTo (OStream &, int) const;
-template <> void ChannelListAttribute::readValueFrom (IStream &, int, int);
+template <>
+IMF_EXPORT
+const char *ChannelListAttribute::staticTypeName ();
+template <>
+IMF_EXPORT
+void ChannelListAttribute::writeValueTo (OPENEXR_IMF_INTERNAL_NAMESPACE::OStream &,
+ int) const;
-} // namespace Imf
+template <>
+IMF_EXPORT
+void ChannelListAttribute::readValueFrom (OPENEXR_IMF_INTERNAL_NAMESPACE::IStream &,
+ int, int);
+
+
+OPENEXR_IMF_INTERNAL_NAMESPACE_HEADER_EXIT
-// Metrowerks compiler wants the .cpp file inlined, too
-#ifdef __MWERKS__
-#include <ImfChannelListAttribute.cpp>
-#endif
#endif
//
// Copyright (c) 2009, Industrial Light & Magic, a division of Lucas
// Digital Ltd. LLC
-//
+//
// All rights reserved.
-//
+//
// Redistribution and use in source and binary forms, with or without
// modification, are permitted provided that the following conditions are
// met:
// distribution.
// * Neither the name of Industrial Light & Magic nor the names of
// its contributors may be used to endorse or promote products derived
-// from this software without specific prior written permission.
-//
+// from this software without specific prior written permission.
+//
// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
//-----------------------------------------------------------------------------
#include <limits>
-#include <IexMathExc.h>
+#include "IexMathExc.h"
+#include "ImfNamespace.h"
-namespace Imf {
+OPENEXR_IMF_INTERNAL_NAMESPACE_HEADER_ENTER
template <bool b> struct StaticAssertionFailed;
template <> struct StaticAssertionFailed <true> {};
#define IMF_STATIC_ASSERT(x) \
- do {StaticAssertionFailed <x> staticAssertionFailed;} while (false)
+ do {StaticAssertionFailed <x> staticAssertionFailed; ((void) staticAssertionFailed);} while (false)
template <class T>
std::numeric_limits<T>::is_integer);
if (a > 0 && b > std::numeric_limits<T>::max() / a)
- throw Iex::OverflowExc ("Integer multiplication overflow.");
+ throw IEX_NAMESPACE::OverflowExc ("Integer multiplication overflow.");
return a * b;
}
std::numeric_limits<T>::is_integer);
if (b == 0)
- throw Iex::DivzeroExc ("Integer division by zero.");
+ throw IEX_NAMESPACE::DivzeroExc ("Integer division by zero.");
return a / b;
}
std::numeric_limits<T>::is_integer);
if (a > std::numeric_limits<T>::max() - b)
- throw Iex::OverflowExc ("Integer addition overflow.");
+ throw IEX_NAMESPACE::OverflowExc ("Integer addition overflow.");
return a + b;
}
std::numeric_limits<T>::is_integer);
if (a < b)
- throw Iex::UnderflowExc ("Integer subtraction underflow.");
+ throw IEX_NAMESPACE::UnderflowExc ("Integer subtraction underflow.");
return a - b;
}
//
// size_t (n) * s
//
- // would overflow, then throw an Iex::OverflowExc exception.
+ // would overflow, then throw an IEX_NAMESPACE::OverflowExc exception.
// Otherwise return
//
// size_t (n).
IMF_STATIC_ASSERT (sizeof (T) <= sizeof (size_t));
if (size_t (n) > std::numeric_limits<size_t>::max() / s)
- throw Iex::OverflowExc ("Integer multiplication overflow.");
+ throw IEX_NAMESPACE::OverflowExc ("Integer multiplication overflow.");
return size_t (n);
}
-} // namespace Imf
+OPENEXR_IMF_INTERNAL_NAMESPACE_HEADER_EXIT
+
#endif
//
// Copyright (c) 2003, Industrial Light & Magic, a division of Lucas
// Digital Ltd. LLC
-//
+//
// All rights reserved.
-//
+//
// Redistribution and use in source and binary forms, with or without
// modification, are permitted provided that the following conditions are
// met:
// distribution.
// * Neither the name of Industrial Light & Magic nor the names of
// its contributors may be used to endorse or promote products derived
-// from this software without specific prior written permission.
-//
+// from this software without specific prior written permission.
+//
// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
//-----------------------------------------------------------------------------
#include <ImfChromaticities.h>
+#include "ImfNamespace.h"
+#include <string.h>
-namespace Imf {
-
+OPENEXR_IMF_INTERNAL_NAMESPACE_SOURCE_ENTER
-Chromaticities::Chromaticities (const Imath::V2f &red,
- const Imath::V2f &green,
- const Imath::V2f &blue,
- const Imath::V2f &white)
+
+Chromaticities::Chromaticities (const IMATH_NAMESPACE::V2f &red,
+ const IMATH_NAMESPACE::V2f &green,
+ const IMATH_NAMESPACE::V2f &blue,
+ const IMATH_NAMESPACE::V2f &white)
:
red (red),
green (green),
// empty
}
+
+bool
+Chromaticities::operator == (const Chromaticities & c) const
+{
+ return red == c.red && green == c.green && blue == c.blue;
+}
-Imath::M44f
+
+bool
+Chromaticities::operator != (const Chromaticities & c) const
+{
+ return red != c.red || green != c.green || blue != c.blue;
+}
+
+
+IMATH_NAMESPACE::M44f
RGBtoXYZ (const Chromaticities chroma, float Y)
{
//
// For an explanation of how the color conversion matrix is derived,
// see Roy Hall, "Illumination and Color in Computer Generated Imagery",
- // Springer-Verlag, 1989, chapter 3, "Perceptual Response"; and
+ // Springer-Verlag, 1989, chapter 3, "Perceptual Response"; and
// Charles A. Poynton, "A Technical Introduction to Digital Video",
// John Wiley & Sons, 1996, chapter 7, "Color science for video".
//
//
float d = chroma.red.x * (chroma.blue.y - chroma.green.y) +
- chroma.blue.x * (chroma.green.y - chroma.red.y) +
- chroma.green.x * (chroma.red.y - chroma.blue.y);
+ chroma.blue.x * (chroma.green.y - chroma.red.y) +
+ chroma.green.x * (chroma.red.y - chroma.blue.y);
float Sr = (X * (chroma.blue.y - chroma.green.y) -
- chroma.green.x * (Y * (chroma.blue.y - 1) +
- chroma.blue.y * (X + Z)) +
- chroma.blue.x * (Y * (chroma.green.y - 1) +
- chroma.green.y * (X + Z))) / d;
+ chroma.green.x * (Y * (chroma.blue.y - 1) +
+ chroma.blue.y * (X + Z)) +
+ chroma.blue.x * (Y * (chroma.green.y - 1) +
+ chroma.green.y * (X + Z))) / d;
float Sg = (X * (chroma.red.y - chroma.blue.y) +
- chroma.red.x * (Y * (chroma.blue.y - 1) +
- chroma.blue.y * (X + Z)) -
- chroma.blue.x * (Y * (chroma.red.y - 1) +
- chroma.red.y * (X + Z))) / d;
+ chroma.red.x * (Y * (chroma.blue.y - 1) +
+ chroma.blue.y * (X + Z)) -
+ chroma.blue.x * (Y * (chroma.red.y - 1) +
+ chroma.red.y * (X + Z))) / d;
float Sb = (X * (chroma.green.y - chroma.red.y) -
- chroma.red.x * (Y * (chroma.green.y - 1) +
- chroma.green.y * (X + Z)) +
- chroma.green.x * (Y * (chroma.red.y - 1) +
- chroma.red.y * (X + Z))) / d;
+ chroma.red.x * (Y * (chroma.green.y - 1) +
+ chroma.green.y * (X + Z)) +
+ chroma.green.x * (Y * (chroma.red.y - 1) +
+ chroma.red.y * (X + Z))) / d;
//
// Assemble the matrix
//
- Imath::M44f M;
+ IMATH_NAMESPACE::M44f M;
M[0][0] = Sr * chroma.red.x;
M[0][1] = Sr * chroma.red.y;
}
-Imath::M44f
+IMATH_NAMESPACE::M44f
XYZtoRGB (const Chromaticities chroma, float Y)
{
return RGBtoXYZ (chroma, Y).inverse();
}
-} // namespace Imf
+OPENEXR_IMF_INTERNAL_NAMESPACE_SOURCE_EXIT
//
// Copyright (c) 2003, Industrial Light & Magic, a division of Lucas
// Digital Ltd. LLC
-//
+//
// All rights reserved.
-//
+//
// Redistribution and use in source and binary forms, with or without
// modification, are permitted provided that the following conditions are
// met:
// distribution.
// * Neither the name of Industrial Light & Magic nor the names of
// its contributors may be used to endorse or promote products derived
-// from this software without specific prior written permission.
-//
+// from this software without specific prior written permission.
+//
// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
#include "ImathVec.h"
#include "ImathMatrix.h"
+#include "ImfNamespace.h"
+#include "ImfExport.h"
-namespace Imf {
+OPENEXR_IMF_INTERNAL_NAMESPACE_HEADER_ENTER
+
struct Chromaticities
{
//-----------------------------------------------
// (1,0,0), (0,1,0), (0,0,1) and (1,1,1).
//-----------------------------------------------
- Imath::V2f red;
- Imath::V2f green;
- Imath::V2f blue;
- Imath::V2f white;
+ IMATH_NAMESPACE::V2f red;
+ IMATH_NAMESPACE::V2f green;
+ IMATH_NAMESPACE::V2f blue;
+ IMATH_NAMESPACE::V2f white;
//--------------------------------------------
// Default constructor produces chromaticities
// according to Rec. ITU-R BT.709-3
//--------------------------------------------
- Chromaticities (const Imath::V2f &red = Imath::V2f (0.6400f, 0.3300f),
- const Imath::V2f &green = Imath::V2f (0.3000f, 0.6000f),
- const Imath::V2f &blue = Imath::V2f (0.1500f, 0.0600f),
- const Imath::V2f &white = Imath::V2f (0.3127f, 0.3290f));
+ IMF_EXPORT
+ Chromaticities (const IMATH_NAMESPACE::V2f &red = IMATH_NAMESPACE::V2f (0.6400f, 0.3300f),
+ const IMATH_NAMESPACE::V2f &green = IMATH_NAMESPACE::V2f (0.3000f, 0.6000f),
+ const IMATH_NAMESPACE::V2f &blue = IMATH_NAMESPACE::V2f (0.1500f, 0.0600f),
+ const IMATH_NAMESPACE::V2f &white = IMATH_NAMESPACE::V2f (0.3127f, 0.3290f));
+
+
+ //---------
+ // Equality
+ //---------
+
+ IMF_EXPORT
+ bool operator == (const Chromaticities &v) const;
+ IMF_EXPORT
+ bool operator != (const Chromaticities &v) const;
};
// triple (1,1,1), or "white", RGBtoXYZ(c,Y) computes a matrix, M, so
// that multiplying an RGB value, v, with M produces an equivalent
// XYZ value, w. (w == v * M)
-//
+//
// If we define that
-//
+//
// (Xr, Yr, Zr) == (1, 0, 0) * M
// (Xg, Yg, Zg) == (0, 1, 0) * M
// (Xb, Yb, Zb) == (0, 0, 1) * M
// (Xw, Yw, Zw) == (1, 1, 1) * M,
-//
+//
// then the following statements are true:
-//
+//
// Xr / (Xr + Yr + Zr) == c.red.x
// Yr / (Xr + Yr + Zr) == c.red.y
-//
+//
// Xg / (Xg + Yg + Zg) == c.red.x
// Yg / (Xg + Yg + Zg) == c.red.y
-//
+//
// Xb / (Xb + Yb + Zb) == c.red.x
// Yb / (Xb + Yb + Zb) == c.red.y
-//
+//
// Xw / (Xw + Yw + Zw) == c.red.x
// Yw / (Xw + Yw + Zw) == c.red.y
-//
+//
// Yw == Y.
-//
+//
// XYZ to RGB:
-//
+//
// YYZtoRGB(c,Y) returns RGBtoXYZ(c,Y).inverse().
-//
+//
-Imath::M44f RGBtoXYZ (const Chromaticities chroma, float Y);
-Imath::M44f XYZtoRGB (const Chromaticities chroma, float Y);
+IMF_EXPORT IMATH_NAMESPACE::M44f RGBtoXYZ (const Chromaticities chroma, float Y);
+IMF_EXPORT IMATH_NAMESPACE::M44f XYZtoRGB (const Chromaticities chroma, float Y);
-} // namespace Imf
+OPENEXR_IMF_INTERNAL_NAMESPACE_HEADER_EXIT
#endif
//
// Copyright (c) 2003, Industrial Light & Magic, a division of Lucas
// Digital Ltd. LLC
-//
+//
// All rights reserved.
-//
+//
// Redistribution and use in source and binary forms, with or without
// modification, are permitted provided that the following conditions are
// met:
// distribution.
// * Neither the name of Industrial Light & Magic nor the names of
// its contributors may be used to endorse or promote products derived
-// from this software without specific prior written permission.
-//
+// from this software without specific prior written permission.
+//
// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
#include <ImfChromaticitiesAttribute.h>
-namespace Imf {
+OPENEXR_IMF_INTERNAL_NAMESPACE_SOURCE_ENTER
+using namespace OPENEXR_IMF_INTERNAL_NAMESPACE;
template <>
const char *
template <>
void
-ChromaticitiesAttribute::writeValueTo (OStream &os, int) const
+ChromaticitiesAttribute::writeValueTo (OPENEXR_IMF_INTERNAL_NAMESPACE::OStream &os, int version) const
{
Xdr::write <StreamIO> (os, _value.red.x);
Xdr::write <StreamIO> (os, _value.red.y);
template <>
void
-ChromaticitiesAttribute::readValueFrom (IStream &is, int, int)
+ChromaticitiesAttribute::readValueFrom (OPENEXR_IMF_INTERNAL_NAMESPACE::IStream &is, int size, int version)
{
Xdr::read <StreamIO> (is, _value.red.x);
Xdr::read <StreamIO> (is, _value.red.y);
}
-} // namespace Imf
+OPENEXR_IMF_INTERNAL_NAMESPACE_SOURCE_EXIT
//
// Copyright (c) 2003, Industrial Light & Magic, a division of Lucas
// Digital Ltd. LLC
-//
+//
// All rights reserved.
-//
+//
// Redistribution and use in source and binary forms, with or without
// modification, are permitted provided that the following conditions are
// met:
// distribution.
// * Neither the name of Industrial Light & Magic nor the names of
// its contributors may be used to endorse or promote products derived
-// from this software without specific prior written permission.
-//
+// from this software without specific prior written permission.
+//
// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
//
//-----------------------------------------------------------------------------
-#include <ImfAttribute.h>
-#include <ImfChromaticities.h>
+#include "ImfAttribute.h"
+#include "ImfChromaticities.h"
+OPENEXR_IMF_INTERNAL_NAMESPACE_HEADER_ENTER
-namespace Imf {
-
-typedef TypedAttribute<Chromaticities> ChromaticitiesAttribute;
+typedef TypedAttribute<OPENEXR_IMF_INTERNAL_NAMESPACE::Chromaticities> ChromaticitiesAttribute;
template <>
+IMF_EXPORT
const char *ChromaticitiesAttribute::staticTypeName ();
template <>
-void ChromaticitiesAttribute::writeValueTo (OStream &, int) const;
+IMF_EXPORT
+void ChromaticitiesAttribute::writeValueTo (OPENEXR_IMF_INTERNAL_NAMESPACE::OStream &,
+ int) const;
template <>
-void ChromaticitiesAttribute::readValueFrom (IStream &, int, int);
+IMF_EXPORT
+void ChromaticitiesAttribute::readValueFrom (OPENEXR_IMF_INTERNAL_NAMESPACE::IStream &,
+ int,
+ int);
-} // namespace Imf
+OPENEXR_IMF_INTERNAL_NAMESPACE_HEADER_EXIT
-// Metrowerks compiler wants the .cpp file inlined, too
-#ifdef __MWERKS__
-#include <ImfChromaticitiesAttribute.cpp>
-#endif
#endif
--- /dev/null
+///////////////////////////////////////////////////////////////////////////
+//
+// Copyright (c) 2012, Weta Digital Ltd
+//
+// All rights reserved.
+//
+// Redistribution and use in source and binary forms, with or without
+// modification, are permitted provided that the following conditions are
+// met:
+// * Redistributions of source code must retain the above copyright
+// notice, this list of conditions and the following disclaimer.
+// * Redistributions in binary form must reproduce the above
+// copyright notice, this list of conditions and the following disclaimer
+// in the documentation and/or other materials provided with the
+// distribution.
+// * Neither the name of Weta Digital nor the names of
+// its contributors may be used to endorse or promote products derived
+// from this software without specific prior written permission.
+//
+// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+//
+///////////////////////////////////////////////////////////////////////////
+
+
+#include "ImfCompositeDeepScanLine.h"
+#include "ImfDeepScanLineInputPart.h"
+#include "ImfDeepScanLineInputFile.h"
+#include "ImfChannelList.h"
+#include "ImfFrameBuffer.h"
+#include "ImfDeepFrameBuffer.h"
+#include "ImfDeepCompositing.h"
+#include "ImfPixelType.h"
+#include "IlmThreadPool.h"
+
+#include <Iex.h>
+#include <vector>
+OPENEXR_IMF_INTERNAL_NAMESPACE_SOURCE_ENTER
+
+using std::vector;
+using std::string;
+using IMATH_NAMESPACE::Box2i;
+using ILMTHREAD_NAMESPACE::Task;
+using ILMTHREAD_NAMESPACE::TaskGroup;
+using ILMTHREAD_NAMESPACE::ThreadPool;
+
+
+
+struct CompositeDeepScanLine::Data{
+ public :
+ vector<DeepScanLineInputFile *> _file; // array of files
+ vector<DeepScanLineInputPart *> _part; // array of parts
+ FrameBuffer _outputFrameBuffer; // output frame buffer provided
+ bool _zback; // true if we are using zback (otherwise channel 1 = channel 0)
+ vector< vector<float> > _channeldata; // pixel values, read from the input, one array per channel
+ vector< int > _sampleCounts; // total per-pixel sample counts,
+ Box2i _dataWindow; // data window of combined inputs
+ DeepCompositing * _comp; // user-provided compositor
+ vector<string> _channels; // names of channels that will be composited
+ vector<int> _bufferMap; // entry _outputFrameBuffer[n].name() == _channels[ _bufferMap[n] ].name()
+
+ void check_valid(const Header & header); // check newly added part/file is OK; on first good call, set _zback/_dataWindow
+
+ //
+ // set up the given deep frame buffer to contain the required channels
+ // resize counts and pointers to the width of _dataWindow
+ // zero-out all counts, since the datawindow may be smaller than/not include this part
+ //
+
+ void handleDeepFrameBuffer (DeepFrameBuffer & buf,
+ vector<unsigned int> & counts, //per-pixel counts
+ vector< vector<float *> > & pointers, //per-channel-per-pixel pointers to data
+ const Header & header,
+ int start,
+ int end);
+
+ Data();
+};
+
+CompositeDeepScanLine::Data::Data() : _zback(false) , _comp(NULL) {}
+
+CompositeDeepScanLine::CompositeDeepScanLine() : _Data(new Data) {}
+
+CompositeDeepScanLine::~CompositeDeepScanLine()
+{
+ delete _Data;
+}
+
+void
+CompositeDeepScanLine::addSource(DeepScanLineInputPart* part)
+{
+ _Data->check_valid(part->header());
+ _Data->_part.push_back(part);
+}
+
+void
+CompositeDeepScanLine::addSource(DeepScanLineInputFile* file)
+{
+ _Data->check_valid(file->header());
+ _Data->_file.push_back(file);
+}
+
+int
+CompositeDeepScanLine::sources() const
+{
+ return int(_Data->_part.size())+int(_Data->_file.size());
+}
+
+void
+CompositeDeepScanLine::Data::check_valid(const Header & header)
+{
+
+ bool has_z=false;
+ bool has_alpha=false;
+ // check good channel names
+ for( ChannelList::ConstIterator i=header.channels().begin();i!=header.channels().end();++i)
+ {
+ std::string n(i.name());
+ if(n=="ZBack")
+ {
+ _zback=true;
+ }
+ else if(n=="Z")
+ {
+ has_z=true;
+ }
+ else if(n=="A")
+ {
+ has_alpha=true;
+ }
+ }
+
+ if(!has_z)
+ {
+ throw IEX_NAMESPACE::ArgExc("Deep data provided to CompositeDeepScanLine is missing a Z channel");
+ }
+
+ if(!has_alpha)
+ {
+ throw IEX_NAMESPACE::ArgExc("Deep data provided to CompositeDeepScanLine is missing an alpha channel");
+ }
+
+
+ if(_part.size()==0 && _file.size()==0)
+ {
+ // first in - update and return
+
+ _dataWindow = header.dataWindow();
+
+ return;
+ }
+
+
+ const Header * const match_header = _part.size()>0 ? &_part[0]->header() : &_file[0]->header();
+
+ // check the sizes match
+ if(match_header->displayWindow() != header.displayWindow())
+ {
+ throw IEX_NAMESPACE::ArgExc("Deep data provided to CompositeDeepScanLine has a different displayWindow to previously provided data");
+ }
+
+ _dataWindow.extendBy(header.dataWindow());
+
+}
+void
+CompositeDeepScanLine::Data::handleDeepFrameBuffer (DeepFrameBuffer& buf,
+ std::vector< unsigned int > & counts,
+ vector< std::vector< float* > > & pointers,
+ const Header& header,
+ int start,
+ int end)
+{
+ int width=_dataWindow.size().x+1;
+ size_t pixelcount = width * (end-start+1);
+ pointers.resize(_channels.size());
+ counts.resize(pixelcount);
+ buf.insertSampleCountSlice (Slice (OPENEXR_IMF_INTERNAL_NAMESPACE::UINT,
+ (char *) (&counts[0]-_dataWindow.min.x-start*width),
+ sizeof(unsigned int),
+ sizeof(unsigned int)*width));
+
+ pointers[0].resize(pixelcount);
+ buf.insert ("Z", DeepSlice (OPENEXR_IMF_INTERNAL_NAMESPACE::FLOAT,
+ (char *)(&pointers[0][0]-_dataWindow.min.x-start*width),
+ sizeof(float *),
+ sizeof(float *)*width,
+ sizeof(float) ));
+
+ if(_zback)
+ {
+ pointers[1].resize(pixelcount);
+ buf.insert ("ZBack", DeepSlice (OPENEXR_IMF_INTERNAL_NAMESPACE::FLOAT,
+ (char *)(&pointers[1][0]-_dataWindow.min.x-start*width),
+ sizeof(float *),
+ sizeof(float *)*width,
+ sizeof(float) ));
+ }
+
+ pointers[2].resize(pixelcount);
+ buf.insert ("A", DeepSlice (OPENEXR_IMF_INTERNAL_NAMESPACE::FLOAT,
+ (char *)(&pointers[2][0]-_dataWindow.min.x-start*width),
+ sizeof(float *),
+ sizeof(float *)*width,
+ sizeof(float) ));
+
+
+ size_t i =0;
+ for(FrameBuffer::ConstIterator qt = _outputFrameBuffer.begin();
+ qt != _outputFrameBuffer.end();
+ qt++)
+ {
+ int channel_in_source = _bufferMap[i];
+ if(channel_in_source>2)
+ {
+ // not dealt with yet (0,1,2 previously inserted)
+ pointers[channel_in_source].resize(pixelcount);
+ buf.insert (qt.name(),
+ DeepSlice (OPENEXR_IMF_INTERNAL_NAMESPACE::FLOAT,
+ (char *)(&pointers[channel_in_source][0]-_dataWindow.min.x-start*width),
+ sizeof(float *),
+ sizeof(float *)*width,
+ sizeof(float) ));
+ }
+
+ i++;
+ }
+
+}
+
+void
+CompositeDeepScanLine::setCompositing(DeepCompositing* c)
+{
+ _Data->_comp=c;
+}
+
+const IMATH_NAMESPACE::Box2i& CompositeDeepScanLine::dataWindow() const
+{
+ return _Data->_dataWindow;
+}
+
+
+void
+CompositeDeepScanLine::setFrameBuffer(const FrameBuffer& fr)
+{
+
+ //
+ // count channels; build map between channels in frame buffer
+ // and channels in internal buffers
+ //
+
+ _Data->_channels.resize(3);
+ _Data->_channels[0]="Z";
+ _Data->_channels[1]=_Data->_zback ? "ZBack" : "Z";
+ _Data->_channels[2]="A";
+ _Data->_bufferMap.resize(0);
+
+ for(FrameBuffer::ConstIterator q=fr.begin();q!=fr.end();q++)
+ {
+ string name(q.name());
+ if(name=="ZBack")
+ {
+ _Data->_bufferMap.push_back(1);
+ }else if(name=="Z")
+ {
+ _Data->_bufferMap.push_back(0);
+ }else if(name=="A")
+ {
+ _Data->_bufferMap.push_back(2);
+ }else{
+ _Data->_bufferMap.push_back(_Data->_channels.size());
+ _Data->_channels.push_back(name);
+ }
+ }
+
+ _Data->_outputFrameBuffer=fr;
+}
+
+namespace
+{
+
+class LineCompositeTask : public Task
+{
+ public:
+
+ LineCompositeTask ( TaskGroup* group ,
+ CompositeDeepScanLine::Data * data,
+ int y,
+ int start,
+ vector<const char*>* names,
+ vector<vector< vector<float *> > >* pointers,
+ vector<unsigned int>* total_sizes,
+ vector<unsigned int>* num_sources
+ ) : Task(group) ,
+ _Data(data),
+ _y(y),
+ _start(start),
+ _names(names),
+ _pointers(pointers),
+ _total_sizes(total_sizes),
+ _num_sources(num_sources)
+ {}
+
+ virtual ~LineCompositeTask () {}
+
+ virtual void execute ();
+ CompositeDeepScanLine::Data* _Data;
+ int _y;
+ int _start;
+ vector<const char *>* _names;
+ vector<vector< vector<float *> > >* _pointers;
+ vector<unsigned int>* _total_sizes;
+ vector<unsigned int>* _num_sources;
+
+};
+
+
+void
+composite_line(int y,
+ int start,
+ CompositeDeepScanLine::Data * _Data,
+ vector<const char *> & names,
+ const vector<vector< vector<float *> > > & pointers,
+ const vector<unsigned int> & total_sizes,
+ const vector<unsigned int> & num_sources
+ )
+{
+ vector<float> output_pixel(names.size()); //the pixel we'll output to
+ vector<const float *> inputs(names.size());
+ DeepCompositing d; // fallback compositing engine
+ DeepCompositing * comp= _Data->_comp ? _Data->_comp : &d;
+
+ int pixel = (y-start)*(_Data->_dataWindow.max.x+1-_Data->_dataWindow.min.x);
+
+ for(int x=_Data->_dataWindow.min.x;x<=_Data->_dataWindow.max.x;x++)
+ {
+ // set inputs[] to point to the first sample of the first part of each channel
+ // if there's a zback, set all channel independently...
+
+ if(_Data->_zback)
+ {
+
+ for(size_t channel=0;channel<names.size();channel++)
+ {
+ inputs[channel]=pointers[0][channel][pixel];
+ }
+
+ }else{
+
+ // otherwise, set 0 and 1 to point to Z
+
+
+ inputs[0]=pointers[0][0][pixel];
+ inputs[1]=pointers[0][0][pixel];
+ for(size_t channel=2;channel<names.size();channel++)
+ {
+ inputs[channel]=pointers[0][channel][pixel];
+ }
+
+ }
+ comp->composite_pixel(&output_pixel[0],
+ &inputs[0],
+ &names[0],
+ names.size(),
+ total_sizes[pixel],
+ num_sources[pixel]
+ );
+
+
+ size_t channel_number=0;
+
+
+ //
+ // write out composited value into internal frame buffer
+ //
+ for(FrameBuffer::Iterator it = _Data->_outputFrameBuffer.begin();it !=_Data->_outputFrameBuffer.end();it++)
+ {
+
+ float value = output_pixel[ _Data->_bufferMap[channel_number] ]; // value to write
+
+
+ // cast to half float if necessary
+ if(it.slice().type==OPENEXR_IMF_INTERNAL_NAMESPACE::FLOAT)
+ {
+ * (float *)(it.slice().base + y*it.slice().yStride + x*it.slice().xStride) = value;
+ }
+ else if(it.slice().type==HALF)
+ {
+ * (half *)(it.slice().base + y*it.slice().yStride + x*it.slice().xStride) = half(value);
+ }
+
+ channel_number++;
+
+ }
+
+ pixel++;
+
+ }// next pixel on row
+}
+
+void LineCompositeTask::execute()
+{
+ composite_line(_y,_start,_Data,*_names,*_pointers,*_total_sizes,*_num_sources);
+}
+
+
+}
+
+void
+CompositeDeepScanLine::readPixels(int start, int end)
+{
+ size_t parts = _Data->_file.size() + _Data->_part.size(); // total of files+parts
+
+ vector<DeepFrameBuffer> framebuffers(parts);
+ vector< vector<unsigned int> > counts(parts);
+
+ //
+ // for each part, a pointer to an array of channels
+ //
+ vector<vector< vector<float *> > > pointers(parts);
+ vector<const Header *> headers(parts);
+
+ {
+ size_t i;
+ for(i=0;i<_Data->_file.size();i++)
+ {
+ headers[i] = &_Data->_file[i]->header();
+ }
+
+ for(size_t j=0;j<_Data->_part.size();j++)
+ {
+ headers[i+j] = &_Data->_part[j]->header();
+ }
+ }
+
+
+ for(size_t i=0;i<parts;i++)
+ {
+ _Data->handleDeepFrameBuffer(framebuffers[i],counts[i],pointers[i],*headers[i],start,end);
+ }
+
+ //
+ // set frame buffers and read scanlines from all parts
+ // TODO what happens if SCANLINE not in data window?
+ //
+
+ {
+ size_t i=0;
+ for(i=0;i<_Data->_file.size();i++)
+ {
+ _Data->_file[i]->setFrameBuffer(framebuffers[i]);
+ _Data->_file[i]->readPixelSampleCounts(start,end);
+ }
+ for(size_t j=0;j<_Data->_part.size();j++)
+ {
+ _Data->_part[j]->setFrameBuffer(framebuffers[i+j]);
+ _Data->_part[j]->readPixelSampleCounts(start,end);
+ }
+ }
+
+
+ //
+ // total width
+ //
+
+ size_t total_width = _Data->_dataWindow.size().x+1;
+ size_t total_pixels = total_width*(end-start+1);
+ vector<unsigned int> total_sizes(total_pixels);
+ vector<unsigned int> num_sources(total_pixels); //number of parts with non-zero sample count
+
+ size_t overall_sample_count=0; // sum of all samples in all images between start and end
+
+
+ //
+ // accumulate pixel counts
+ //
+ for(size_t ptr=0;ptr<total_pixels;ptr++)
+ {
+ total_sizes[ptr]=0;
+ num_sources[ptr]=0;
+ for(size_t j=0;j<parts;j++)
+ {
+ total_sizes[ptr]+=counts[j][ptr];
+ if(counts[j][ptr]>0) num_sources[ptr]++;
+ }
+ overall_sample_count+=total_sizes[ptr];
+
+
+
+ }
+
+
+
+
+ //
+ // allocate arrays for pixel data
+ // samples array accessed as in pixels[channel][sample]
+ //
+
+ vector<vector<float> > samples( _Data->_channels.size() );
+
+ for(size_t channel=0;channel<_Data->_channels.size();channel++)
+ {
+ if( channel!=1 || _Data->_zback)
+ {
+ samples[channel].resize(overall_sample_count);
+ }
+ }
+
+ for(size_t channel=0;channel<samples.size();channel++)
+ {
+
+ if( channel!=1 || _Data->_zback)
+ {
+
+ samples[channel].resize(overall_sample_count);
+
+
+ //
+ // allocate pointers for channel data
+ //
+
+ size_t offset=0;
+
+ for(size_t pixel=0;pixel<total_pixels;pixel++)
+ {
+ for(size_t part=0 ; part<parts && offset<overall_sample_count ; part++ )
+ {
+ pointers[part][channel][pixel]=&samples[channel][offset];
+ offset+=counts[part][pixel];
+ }
+ }
+
+ }
+ }
+
+ //
+ // read data
+ //
+
+ for(size_t i=0;i<_Data->_file.size();i++)
+ {
+ _Data->_file[i]->readPixels(start,end);
+ }
+ for(size_t j=0;j<_Data->_part.size();j++)
+ {
+ _Data->_part[j]->readPixels(start,end);
+ }
+
+
+
+
+ //
+ // composite pixels and write back to framebuffer
+ //
+
+
+ // turn vector of strings into array of char *
+ // and make sure 'ZBack' channel is correct
+ vector<const char *> names(_Data->_channels.size());
+ for(size_t i=0;i<names.size();i++)
+ {
+ names[i]=_Data->_channels[i].c_str();
+ }
+
+ if(!_Data->_zback) names[1]=names[0]; // no zback channel, so make it point to z
+
+
+
+ TaskGroup g;
+ for(int y=start;y<=end;y++)
+ {
+ ThreadPool::addGlobalTask(new LineCompositeTask(&g,_Data,y,start,&names,&pointers,&total_sizes,&num_sources));
+ }//next row
+}
+
+const FrameBuffer&
+CompositeDeepScanLine::frameBuffer() const
+{
+ return _Data->_outputFrameBuffer;
+}
+
+OPENEXR_IMF_INTERNAL_NAMESPACE_SOURCE_EXIT
--- /dev/null
+///////////////////////////////////////////////////////////////////////////
+//
+// Copyright (c) 2012, Weta Digital Ltd
+//
+// All rights reserved.
+//
+// Redistribution and use in source and binary forms, with or without
+// modification, are permitted provided that the following conditions are
+// met:
+// * Redistributions of source code must retain the above copyright
+// notice, this list of conditions and the following disclaimer.
+// * Redistributions in binary form must reproduce the above
+// copyright notice, this list of conditions and the following disclaimer
+// in the documentation and/or other materials provided with the
+// distribution.
+// * Neither the name of Weta Digital nor the names of
+// its contributors may be used to endorse or promote products derived
+// from this software without specific prior written permission.
+//
+// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+//
+///////////////////////////////////////////////////////////////////////////
+
+
+#ifndef INCLUDED_IMF_COMPOSITEDEEPSCANLINE_H
+#define INCLUDED_IMF_COMPOSITEDEEPSCANLINE_H
+
+//-----------------------------------------------------------------------------
+//
+// Class to composite deep samples into a frame buffer
+// Initialise with a deep input part or deep inputfile
+// (also supports multiple files and parts, and will
+// composite them together, as long as their sizes and channelmaps agree)
+//
+// Then call setFrameBuffer, and readPixels, exactly as for reading
+// regular scanline images.
+//
+// Restrictions - source file(s) must contain at least Z and alpha channels
+// - if multiple files/parts are provided, sizes must match
+// - all requested channels will be composited as premultiplied
+// - only half and float channels can be requested
+//
+// This object should not be considered threadsafe
+//
+// The default compositing engine will give spurious results with overlapping
+// volumetric samples - you may derive from DeepCompositing class, override the
+// sort_pixel() and composite_pixel() functions, and pass an instance to
+// setCompositing().
+//
+//-----------------------------------------------------------------------------
+
+#include "ImfForward.h"
+#include "ImfNamespace.h"
+#include "ImfExport.h"
+#include <ImathBox.h>
+
+OPENEXR_IMF_INTERNAL_NAMESPACE_HEADER_ENTER
+
+class CompositeDeepScanLine
+{
+ public:
+ IMF_EXPORT
+ CompositeDeepScanLine();
+ IMF_EXPORT
+ virtual ~CompositeDeepScanLine();
+
+ /// set the source data as a part
+ ///@note all parts must remain valid until after last interaction with DeepComp
+ IMF_EXPORT
+ void addSource(DeepScanLineInputPart * part);
+
+ /// set the source data as a file
+ ///@note all file must remain valid until after last interaction with DeepComp
+ IMF_EXPORT
+ void addSource(DeepScanLineInputFile * file);
+
+
+ /////////////////////////////////////////
+ //
+ // set the frame buffer for output values
+ // the buffers specified must be large enough
+ // to handle the dataWindow()
+ //
+ /////////////////////////////////////////
+ IMF_EXPORT
+ void setFrameBuffer(const FrameBuffer & fr);
+
+
+
+ /////////////////////////////////////////
+ //
+ // retrieve frameBuffer
+ //
+ ////////////////////////////////////////
+ IMF_EXPORT
+ const FrameBuffer & frameBuffer() const;
+
+
+ //////////////////////////////////////////////////
+ //
+ // read scanlines start to end from the source(s)
+ // storing the result in the frame buffer provided
+ //
+ //////////////////////////////////////////////////
+
+ IMF_EXPORT
+ void readPixels(int start,int end);
+
+ IMF_EXPORT
+ int sources() const; // return number of sources
+
+ /////////////////////////////////////////////////
+ //
+ // retrieve the datawindow
+ // If multiple parts are specified, this will
+ // be the union of the dataWindow of all parts
+ //
+ ////////////////////////////////////////////////
+
+ IMF_EXPORT
+ const IMATH_NAMESPACE::Box2i & dataWindow() const;
+
+
+ //
+ // override default sorting/compositing operation
+ // (otherwise an instance of the base class will be used)
+ //
+
+ IMF_EXPORT
+ void setCompositing(DeepCompositing *);
+
+ struct Data;
+ private :
+ struct Data *_Data;
+
+ CompositeDeepScanLine(const CompositeDeepScanLine &); // not implemented
+ const CompositeDeepScanLine & operator=(const CompositeDeepScanLine &); // not implemented
+};
+
+OPENEXR_IMF_INTERNAL_NAMESPACE_HEADER_EXIT
+
+#endif
//
// Copyright (c) 2004, Industrial Light & Magic, a division of Lucas
// Digital Ltd. LLC
-//
+//
// All rights reserved.
-//
+//
// Redistribution and use in source and binary forms, with or without
// modification, are permitted provided that the following conditions are
// met:
// distribution.
// * Neither the name of Industrial Light & Magic nor the names of
// its contributors may be used to endorse or promote products derived
-// from this software without specific prior written permission.
-//
+// from this software without specific prior written permission.
+//
// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
// enum Compression
//
//-----------------------------------------------------------------------------
+#include "ImfNamespace.h"
-namespace Imf {
-
+OPENEXR_IMF_INTERNAL_NAMESPACE_HEADER_ENTER
enum Compression
{
PXR24_COMPRESSION = 5, // lossy 24-bit float compression
B44_COMPRESSION = 6, // lossy 4-by-4 pixel block compression,
- // fixed compression rate
+ // fixed compression rate
B44A_COMPRESSION = 7, // lossy 4-by-4 pixel block compression,
- // flat fields are compressed more
+ // flat fields are compressed more
+
+ DWAA_COMPRESSION = 8, // lossy DCT based compression, in blocks
+ // of 32 scanlines. More efficient for partial
+ // buffer access.
+
+ DWAB_COMPRESSION = 9, // lossy DCT based compression, in blocks
+ // of 256 scanlines. More efficient space
+ // wise and faster to decode full frames
+ // than DWAA_COMPRESSION.
NUM_COMPRESSION_METHODS // number of different compression methods
};
+OPENEXR_IMF_INTERNAL_NAMESPACE_HEADER_EXIT
-} // namespace Imf
#endif
//
// Copyright (c) 2002, Industrial Light & Magic, a division of Lucas
// Digital Ltd. LLC
-//
+//
// All rights reserved.
-//
+//
// Redistribution and use in source and binary forms, with or without
// modification, are permitted provided that the following conditions are
// met:
// distribution.
// * Neither the name of Industrial Light & Magic nor the names of
// its contributors may be used to endorse or promote products derived
-// from this software without specific prior written permission.
-//
+// from this software without specific prior written permission.
+//
// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
//
//-----------------------------------------------------------------------------
-#include <ImfCompressionAttribute.h>
+#include "ImfCompressionAttribute.h"
+
+OPENEXR_IMF_INTERNAL_NAMESPACE_SOURCE_ENTER
-namespace Imf {
+using namespace OPENEXR_IMF_INTERNAL_NAMESPACE;
template <>
template <>
void
-CompressionAttribute::writeValueTo (OStream &os, int) const
+CompressionAttribute::writeValueTo (OPENEXR_IMF_INTERNAL_NAMESPACE::OStream &os, int version) const
{
unsigned char tmp = _value;
Xdr::write <StreamIO> (os, tmp);
template <>
void
-CompressionAttribute::readValueFrom (IStream &is, int, int)
+CompressionAttribute::readValueFrom (OPENEXR_IMF_INTERNAL_NAMESPACE::IStream &is, int size, int version)
{
unsigned char tmp;
Xdr::read <StreamIO> (is, tmp);
}
-} // namespace Imf
+OPENEXR_IMF_INTERNAL_NAMESPACE_SOURCE_EXIT
//
// Copyright (c) 2002, Industrial Light & Magic, a division of Lucas
// Digital Ltd. LLC
-//
+//
// All rights reserved.
-//
+//
// Redistribution and use in source and binary forms, with or without
// modification, are permitted provided that the following conditions are
// met:
// distribution.
// * Neither the name of Industrial Light & Magic nor the names of
// its contributors may be used to endorse or promote products derived
-// from this software without specific prior written permission.
-//
+// from this software without specific prior written permission.
+//
// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
//
//-----------------------------------------------------------------------------
-#include <ImfAttribute.h>
-#include <ImfCompression.h>
+#include "ImfAttribute.h"
+#include "ImfCompression.h"
+OPENEXR_IMF_INTERNAL_NAMESPACE_HEADER_ENTER
-namespace Imf {
+typedef TypedAttribute<OPENEXR_IMF_INTERNAL_NAMESPACE::Compression> CompressionAttribute;
+template <> IMF_EXPORT const char *CompressionAttribute::staticTypeName ();
+template <> IMF_EXPORT void CompressionAttribute::writeValueTo (OPENEXR_IMF_INTERNAL_NAMESPACE::OStream &,
+ int) const;
+template <> IMF_EXPORT void CompressionAttribute::readValueFrom (OPENEXR_IMF_INTERNAL_NAMESPACE::IStream &,
+ int,
+ int);
-typedef TypedAttribute<Compression> CompressionAttribute;
-template <> const char *CompressionAttribute::staticTypeName ();
-template <> void CompressionAttribute::writeValueTo (OStream &, int) const;
-template <> void CompressionAttribute::readValueFrom (IStream &, int, int);
+OPENEXR_IMF_INTERNAL_NAMESPACE_HEADER_EXIT
-} // namespace Imf
-
-// Metrowerks compiler wants the .cpp file inlined, too
-#ifdef __MWERKS__
-#include <ImfCompressionAttribute.cpp>
-#endif
#endif
//
// Copyright (c) 2004, Industrial Light & Magic, a division of Lucas
// Digital Ltd. LLC
-//
+//
// All rights reserved.
-//
+//
// Redistribution and use in source and binary forms, with or without
// modification, are permitted provided that the following conditions are
// met:
// distribution.
// * Neither the name of Industrial Light & Magic nor the names of
// its contributors may be used to endorse or promote products derived
-// from this software without specific prior written permission.
-//
+// from this software without specific prior written permission.
+//
// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
//
//-----------------------------------------------------------------------------
-#include <ImfCompressor.h>
-#include <ImfRleCompressor.h>
-#include <ImfZipCompressor.h>
-#include <ImfPizCompressor.h>
-#include <ImfPxr24Compressor.h>
-#include <ImfB44Compressor.h>
-#include <ImfCheckedArithmetic.h>
+#include "ImfCompressor.h"
+#include "ImfRleCompressor.h"
+#include "ImfZipCompressor.h"
+#include "ImfPizCompressor.h"
+#include "ImfPxr24Compressor.h"
+#include "ImfB44Compressor.h"
+#include "ImfDwaCompressor.h"
+#include "ImfCheckedArithmetic.h"
+#include "ImfNamespace.h"
-namespace Imf {
+OPENEXR_IMF_INTERNAL_NAMESPACE_SOURCE_ENTER
-using Imath::Box2i;
+using IMATH_NAMESPACE::Box2i;
Compressor::Compressor (const Header &hdr): _header (hdr) {}
int
Compressor::compressTile (const char *inPtr,
- int inSize,
- Box2i range,
- const char *&outPtr)
+ int inSize,
+ Box2i range,
+ const char *&outPtr)
{
return compress (inPtr, inSize, range.min.y, outPtr);
}
-
+
int
Compressor::uncompressTile (const char *inPtr,
- int inSize,
- Box2i range,
- const char *&outPtr)
+ int inSize,
+ Box2i range,
+ const char *&outPtr)
{
return uncompress (inPtr, inSize, range.min.y, outPtr);
}
-bool
+bool
isValidCompression (Compression c)
{
switch (c)
case PXR24_COMPRESSION:
case B44_COMPRESSION:
case B44A_COMPRESSION:
+ case DWAA_COMPRESSION:
+ case DWAB_COMPRESSION:
- return true;
+ return true;
default:
- return false;
+ return false;
}
}
+bool isValidDeepCompression(Compression c)
+{
+ switch(c)
+ {
+ case NO_COMPRESSION:
+ case RLE_COMPRESSION:
+ case ZIPS_COMPRESSION:
+ return true;
+ default :
+ return false;
+ }
+}
+
Compressor *
newCompressor (Compression c, size_t maxScanLineSize, const Header &hdr)
{
case RLE_COMPRESSION:
- return new RleCompressor (hdr, maxScanLineSize);
+ return new RleCompressor (hdr, maxScanLineSize);
case ZIPS_COMPRESSION:
- return new ZipCompressor (hdr, maxScanLineSize, 1);
+ return new ZipCompressor (hdr, maxScanLineSize, 1);
case ZIP_COMPRESSION:
- return new ZipCompressor (hdr, maxScanLineSize, 16);
+ return new ZipCompressor (hdr, maxScanLineSize, 16);
case PIZ_COMPRESSION:
- return new PizCompressor (hdr, maxScanLineSize, 32);
+ return new PizCompressor (hdr, maxScanLineSize, 32);
case PXR24_COMPRESSION:
- return new Pxr24Compressor (hdr, maxScanLineSize, 16);
+ return new Pxr24Compressor (hdr, maxScanLineSize, 16);
case B44_COMPRESSION:
- return new B44Compressor (hdr, maxScanLineSize, 32, false);
+ return new B44Compressor (hdr, maxScanLineSize, 32, false);
case B44A_COMPRESSION:
- return new B44Compressor (hdr, maxScanLineSize, 32, true);
+ return new B44Compressor (hdr, maxScanLineSize, 32, true);
+
+ case DWAA_COMPRESSION:
+
+ return new DwaCompressor (hdr, maxScanLineSize, 32,
+ DwaCompressor::STATIC_HUFFMAN);
+
+ case DWAB_COMPRESSION:
+
+ return new DwaCompressor (hdr, maxScanLineSize, 256,
+ DwaCompressor::STATIC_HUFFMAN);
default:
- return 0;
+ return 0;
}
}
Compressor *
newTileCompressor (Compression c,
- size_t tileLineSize,
- size_t numTileLines,
- const Header &hdr)
+ size_t tileLineSize,
+ size_t numTileLines,
+ const Header &hdr)
{
switch (c)
{
case RLE_COMPRESSION:
- return new RleCompressor (hdr, uiMult (tileLineSize, numTileLines));
+ return new RleCompressor (hdr, uiMult (tileLineSize, numTileLines));
case ZIPS_COMPRESSION:
case ZIP_COMPRESSION:
- return new ZipCompressor (hdr, tileLineSize, numTileLines);
+ return new ZipCompressor (hdr, tileLineSize, numTileLines);
case PIZ_COMPRESSION:
- return new PizCompressor (hdr, tileLineSize, numTileLines);
+ return new PizCompressor (hdr, tileLineSize, numTileLines);
case PXR24_COMPRESSION:
- return new Pxr24Compressor (hdr, tileLineSize, numTileLines);
+ return new Pxr24Compressor (hdr, tileLineSize, numTileLines);
case B44_COMPRESSION:
- return new B44Compressor (hdr, tileLineSize, numTileLines, false);
+ return new B44Compressor (hdr, tileLineSize, numTileLines, false);
case B44A_COMPRESSION:
- return new B44Compressor (hdr, tileLineSize, numTileLines, true);
+ return new B44Compressor (hdr, tileLineSize, numTileLines, true);
+
+ case DWAA_COMPRESSION:
+ case DWAB_COMPRESSION:
+
+ return new DwaCompressor (hdr, tileLineSize, numTileLines,
+ DwaCompressor::DEFLATE);
default:
- return 0;
+ return 0;
}
}
-} // namespace Imf
+OPENEXR_IMF_INTERNAL_NAMESPACE_SOURCE_EXIT
+
//
// Copyright (c) 2002, Industrial Light & Magic, a division of Lucas
// Digital Ltd. LLC
-//
+//
// All rights reserved.
-//
+//
// Redistribution and use in source and binary forms, with or without
// modification, are permitted provided that the following conditions are
// met:
// distribution.
// * Neither the name of Industrial Light & Magic nor the names of
// its contributors may be used to endorse or promote products derived
-// from this software without specific prior written permission.
-//
+// from this software without specific prior written permission.
+//
// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
//
//-----------------------------------------------------------------------------
-#include <ImfCompression.h>
+#include "ImfCompression.h"
#include "ImathBox.h"
+#include "ImfNamespace.h"
+#include "ImfExport.h"
+#include "ImfForward.h"
+
#include <stdlib.h>
-namespace Imf {
-class Header;
+OPENEXR_IMF_INTERNAL_NAMESPACE_HEADER_ENTER
class Compressor
// that will be compressed or uncompressed
//---------------------------------------------
+ IMF_EXPORT
Compressor (const Header &hdr);
// Destructor
//-----------
+ IMF_EXPORT
virtual ~Compressor ();
// a single call to compress() and uncompress().
//----------------------------------------------
+ IMF_EXPORT
virtual int numScanLines () const = 0;
enum Format
{
- NATIVE, // the machine's native format
- XDR // Xdr format
+ NATIVE, // the machine's native format
+ XDR // Xdr format
};
+ IMF_EXPORT
virtual Format format () const;
//
//-------------------------------------------------------------------------
+ IMF_EXPORT
virtual int compress (const char *inPtr,
- int inSize,
- int minY,
- const char *&outPtr) = 0;
+ int inSize,
+ int minY,
+ const char *&outPtr) = 0;
+ IMF_EXPORT
virtual int compressTile (const char *inPtr,
- int inSize,
- Imath::Box2i range,
- const char *&outPtr);
+ int inSize,
+ IMATH_NAMESPACE::Box2i range,
+ const char *&outPtr);
//-------------------------------------------------------------------------
// Uncompress an array of bytes that has been compressed by compress():
//
//-------------------------------------------------------------------------
+ IMF_EXPORT
virtual int uncompress (const char *inPtr,
- int inSize,
- int minY,
- const char *&outPtr) = 0;
+ int inSize,
+ int minY,
+ const char *&outPtr) = 0;
+ IMF_EXPORT
virtual int uncompressTile (const char *inPtr,
- int inSize,
- Imath::Box2i range,
- const char *&outPtr);
+ int inSize,
+ IMATH_NAMESPACE::Box2i range,
+ const char *&outPtr);
private:
// Test if c is a valid compression type
//--------------------------------------
-bool isValidCompression (Compression c);
+IMF_EXPORT
+bool isValidCompression (Compression c);
+
+//--------------------------------------
+// Test if c is valid for deep data
+//--------------------------------------
+
+IMF_EXPORT
+bool isValidDeepCompression (Compression c);
//-----------------------------------------------------------------
//
// header Header of the input or output file whose
// pixels will be compressed or uncompressed.
-//
+//
// return value A pointer to a new Compressor object (it
// is the caller's responsibility to delete
// the object), or 0 (if c is NO_COMPRESSION).
//
//-----------------------------------------------------------------
+IMF_EXPORT
Compressor * newCompressor (Compression c,
- size_t maxScanLineSize,
- const Header &hdr);
+ size_t maxScanLineSize,
+ const Header &hdr);
//-----------------------------------------------------------------
//
//-----------------------------------------------------------------
+IMF_EXPORT
Compressor * newTileCompressor (Compression c,
- size_t tileLineSize,
- size_t numTileLines,
- const Header &hdr);
+ size_t tileLineSize,
+ size_t numTileLines,
+ const Header &hdr);
-} // namespace Imf
+OPENEXR_IMF_INTERNAL_NAMESPACE_HEADER_EXIT
#endif
//
// Copyright (c) 2002, Industrial Light & Magic, a division of Lucas
// Digital Ltd. LLC
-//
+//
// All rights reserved.
-//
+//
// Redistribution and use in source and binary forms, with or without
// modification, are permitted provided that the following conditions are
// met:
// distribution.
// * Neither the name of Industrial Light & Magic nor the names of
// its contributors may be used to endorse or promote products derived
-// from this software without specific prior written permission.
-//
+// from this software without specific prior written permission.
+//
// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
//
//-----------------------------------------------------------------------------
-#include <ImfConvert.h>
+#include "ImfConvert.h"
+#include "ImfNamespace.h"
+
#include <limits.h>
-namespace Imf {
+
+OPENEXR_IMF_INTERNAL_NAMESPACE_SOURCE_ENTER
+
namespace {
inline bool
halfToUint (half h)
{
if (h.isNegative() || h.isNan())
- return 0;
+ return 0;
if (h.isInfinity())
- return UINT_MAX;
+ return UINT_MAX;
return (unsigned int) h;
}
floatToUint (float f)
{
if (isNegative (f) || isNan (f))
- return 0;
+ return 0;
if (isInfinity (f) || f > UINT_MAX)
- return UINT_MAX;
+ return UINT_MAX;
return (unsigned int) f;
}
-half
+half
uintToHalf (unsigned int ui)
{
if (ui > HALF_MAX)
- return half::posInf();
+ return half::posInf();
- return half (ui);
+ return half ((float) ui);
}
-half
+half
floatToHalf (float f)
{
if (isFinite (f))
{
- if (f > HALF_MAX)
- return half::posInf();
+ if (f > HALF_MAX)
+ return half::posInf();
- if (f < -HALF_MAX)
- return half::negInf();
+ if (f < -HALF_MAX)
+ return half::negInf();
}
return half (f);
}
-} // namespace Imf
+OPENEXR_IMF_INTERNAL_NAMESPACE_SOURCE_EXIT
//
// Copyright (c) 2002, Industrial Light & Magic, a division of Lucas
// Digital Ltd. LLC
-//
+//
// All rights reserved.
-//
+//
// Redistribution and use in source and binary forms, with or without
// modification, are permitted provided that the following conditions are
// met:
// distribution.
// * Neither the name of Industrial Light & Magic nor the names of
// its contributors may be used to endorse or promote products derived
-// from this software without specific prior written permission.
-//
+// from this software without specific prior written permission.
+//
// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
//-----------------------------------------------------------------------------
#include "half.h"
+#include "ImfExport.h"
+#include "ImfNamespace.h"
+OPENEXR_IMF_INTERNAL_NAMESPACE_HEADER_ENTER
-namespace Imf {
//---------------------------------------------------------
// Conversion from half or float to unsigned int:
//
//---------------------------------------------------------
-unsigned int halfToUint (half h);
-unsigned int floatToUint (float f);
+IMF_EXPORT unsigned int halfToUint (half h);
+IMF_EXPORT unsigned int floatToUint (float f);
//---------------------------------------------------------
//
//---------------------------------------------------------
-half uintToHalf (unsigned int ui);
-half floatToHalf (float f);
+IMF_EXPORT half uintToHalf (unsigned int ui);
+IMF_EXPORT half floatToHalf (float f);
+
+OPENEXR_IMF_INTERNAL_NAMESPACE_HEADER_EXIT
-} // namespace Imf
#endif
--- /dev/null
+///////////////////////////////////////////////////////////////////////////
+//
+// Copyright (c) 2012, Weta Digital Ltd
+//
+// All rights reserved.
+//
+// Redistribution and use in source and binary forms, with or without
+// modification, are permitted provided that the following conditions are
+// met:
+// * Redistributions of source code must retain the above copyright
+// notice, this list of conditions and the following disclaimer.
+// * Redistributions in binary form must reproduce the above
+// copyright notice, this list of conditions and the following disclaimer
+// in the documentation and/or other materials provided with the
+// distribution.
+// * Neither the name of Weta Digital nor the names of
+// its contributors may be used to endorse or promote products derived
+// from this software without specific prior written permission.
+//
+// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+//
+///////////////////////////////////////////////////////////////////////////
+
+#include "ImfDeepCompositing.h"
+
+#include "ImfNamespace.h"
+#include <algorithm>
+#include <vector>
+
+OPENEXR_IMF_INTERNAL_NAMESPACE_SOURCE_ENTER
+
+using std::sort;
+using std::vector;
+DeepCompositing::DeepCompositing()
+{
+}
+
+DeepCompositing::~DeepCompositing()
+{
+}
+
+void
+DeepCompositing::composite_pixel (float outputs[],
+ const float* inputs[],
+ const char*channel_names[],
+ int num_channels,
+ int num_samples,
+ int sources)
+{
+ for(int i=0;i<num_channels;i++) outputs[i]=0.0;
+ // no samples? do nothing
+ if(num_samples==0)
+ {
+ return;
+ }
+
+ vector<int> sort_order;
+ if(sources>1)
+ {
+ sort_order.resize(num_samples);
+ for(int i=0;i<num_samples;i++) sort_order[i]=i;
+ sort(&sort_order[0],inputs,channel_names,num_channels,num_samples,sources);
+ }
+
+
+ for(int i=0;i<num_samples;i++)
+ {
+ int s=(sources>1) ? sort_order[i] : i;
+ float alpha=outputs[2];
+ if(alpha>=1.0) return;
+
+ for(int c=0;c<num_channels;c++)
+ {
+ outputs[c]+=(1.0-alpha)*inputs[c][s];
+ }
+ }
+}
+
+struct sort_helper
+{
+ const float ** inputs;
+ bool operator() (int a,int b)
+ {
+ if(inputs[0][a] < inputs[0][b]) return true;
+ if(inputs[0][a] > inputs[0][b]) return false;
+ if(inputs[1][a] < inputs[1][b]) return true;
+ if(inputs[1][a] > inputs[1][b]) return false;
+ return a<b;
+ }
+ sort_helper(const float ** i) : inputs(i) {}
+};
+
+void
+DeepCompositing::sort(int order[], const float* inputs[], const char* channel_names[], int num_channels, int num_samples, int sources)
+{
+ std::sort(order+0,order+num_samples,sort_helper(inputs));
+}
+
+
+OPENEXR_IMF_INTERNAL_NAMESPACE_SOURCE_EXIT
--- /dev/null
+///////////////////////////////////////////////////////////////////////////
+//
+// Copyright (c) 2012, Weta Digital Ltd
+//
+// All rights reserved.
+//
+// Redistribution and use in source and binary forms, with or without
+// modification, are permitted provided that the following conditions are
+// met:
+// * Redistributions of source code must retain the above copyright
+// notice, this list of conditions and the following disclaimer.
+// * Redistributions in binary form must reproduce the above
+// copyright notice, this list of conditions and the following disclaimer
+// in the documentation and/or other materials provided with the
+// distribution.
+// * Neither the name of Weta Digital nor the names of
+// its contributors may be used to endorse or promote products derived
+// from this software without specific prior written permission.
+//
+// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+//
+///////////////////////////////////////////////////////////////////////////
+
+
+#ifndef INCLUDED_IMF_DEEPCOMPOSITING_H
+#define INCLUDED_IMF_DEEPCOMPOSITING_H
+
+//-----------------------------------------------------------------------------
+//
+// Class to sort and composite deep samples into a frame buffer
+// You may derive from this class to change the way that CompositeDeepScanLine
+// and CompositeDeepTile combine samples together - pass an instance of your derived
+// class to the compositing engine
+//
+//-----------------------------------------------------------------------------
+
+#include "ImfForward.h"
+#include "ImfNamespace.h"
+#include "ImfExport.h"
+
+OPENEXR_IMF_INTERNAL_NAMESPACE_HEADER_ENTER
+
+class DeepCompositing
+{
+ public:
+ IMF_EXPORT
+ DeepCompositing();
+ IMF_EXPORT
+ virtual ~DeepCompositing();
+
+
+ //////////////////////////////////////////////
+ ///
+ /// composite together the given channels
+ ///
+ /// @param outputs - return array of pixel values -
+ /// @param inputs - arrays of input sample
+ /// @param channel_names - array of channel names for corresponding channels
+ /// @param num_channels - number of active channels (3 or greater)
+ /// @param num_samples - number of values in all input arrays
+ /// @param sources - number of different sources
+ ///
+ /// each array input has num_channels entries: outputs[n] should be the composited
+ /// values in array inputs[n], whose name will be given by channel_names[n]
+ ///
+ /// The channel ordering shall be as follows:
+ /// Position Channel
+ /// 0 Z
+ /// 1 ZBack (if no ZBack, then inputs[1]==inputs[0] and channel_names[1]==channel_names[0])
+ /// 2 A (alpha channel)
+ /// 3-n other channels - only channels in the frame buffer will appear here
+ ///
+ /// since a Z and Alpha channel is required, and channel[1] is ZBack or another copy of Z
+ /// there will always be 3 or more channels.
+ ///
+ /// The default implementation calls sort() if and only if more than one source is active,
+ /// composites all samples together using the Over operator from front to back,
+ /// stopping as soon as a sample with alpha=1 is found
+ /// It also blanks all outputs if num_samples==0
+ ///
+ /// note - multiple threads may call composite_pixel simultaneously for different pixels
+ ///
+ ///
+ //////////////////////////////////////////////
+ IMF_EXPORT
+ virtual void composite_pixel(float outputs[],
+ const float * inputs[],
+ const char * channel_names[],
+ int num_channels,
+ int num_samples,
+ int sources
+ );
+
+
+
+ ////////////////////////////////////////////////////////////////
+ ///
+ /// find the depth order for samples with given channel values
+ /// does not sort the values in-place. Instead it populates
+ /// array 'order' with the desired sorting order
+ ///
+ /// the default operation sorts samples from front to back according to their Z channel
+ ///
+ /// @param order - required output order. order[n] shall be the nth closest sample
+ /// @param inputs - arrays of input samples, one array per channel_name
+ /// @param channel_names - array of channel names for corresponding channels
+ /// @param num_channels - number of channels (3 or greater)
+ /// @param num_samples - number of samples in each array
+ /// @param sources - number of different sources the data arises from
+ ///
+ /// the channel layout is identical to composite_pixel()
+ ///
+ ///////////////////////////////////////////////////////////////
+
+ IMF_EXPORT
+ virtual void sort(int order[],
+ const float * inputs[],
+ const char * channel_names[],
+ int num_channels,
+ int num_samples,
+ int sources);
+};
+
+OPENEXR_IMF_INTERNAL_NAMESPACE_HEADER_EXIT
+
+#endif
--- /dev/null
+///////////////////////////////////////////////////////////////////////////
+//
+// Copyright (c) 2011, Industrial Light & Magic, a division of Lucas
+// Digital Ltd. LLC
+//
+// All rights reserved.
+//
+// Redistribution and use in source and binary forms, with or without
+// modification, are permitted provided that the following conditions are
+// met:
+// * Redistributions of source code must retain the above copyright
+// notice, this list of conditions and the following disclaimer.
+// * Redistributions in binary form must reproduce the above
+// copyright notice, this list of conditions and the following disclaimer
+// in the documentation and/or other materials provided with the
+// distribution.
+// * Neither the name of Industrial Light & Magic nor the names of
+// its contributors may be used to endorse or promote products derived
+// from this software without specific prior written permission.
+//
+// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+//
+///////////////////////////////////////////////////////////////////////////
+
+#include "ImfDeepFrameBuffer.h"
+#include "Iex.h"
+
+
+using namespace std;
+#include "ImfNamespace.h"
+
+OPENEXR_IMF_INTERNAL_NAMESPACE_SOURCE_ENTER
+
+DeepSlice::DeepSlice (PixelType t,
+ char *b,
+ size_t xst,
+ size_t yst,
+ size_t spst,
+ int xsm,
+ int ysm,
+ double fv,
+ bool xtc,
+ bool ytc)
+:
+ Slice (t, b, xst, yst, xsm, ysm, fv, xtc, ytc),
+ sampleStride (spst)
+{
+ // empty
+}
+
+
+void
+DeepFrameBuffer::insert (const char name[], const DeepSlice &slice)
+{
+ if (name[0] == 0)
+ {
+ THROW (IEX_NAMESPACE::ArgExc,
+ "Frame buffer slice name cannot be an empty string.");
+ }
+
+ _map[name] = slice;
+}
+
+
+void
+DeepFrameBuffer::insert (const string &name, const DeepSlice &slice)
+{
+ insert (name.c_str(), slice);
+}
+
+
+DeepSlice &
+DeepFrameBuffer::operator [] (const char name[])
+{
+ SliceMap::iterator i = _map.find (name);
+
+ if (i == _map.end())
+ {
+ THROW (IEX_NAMESPACE::ArgExc,
+ "Cannot find frame buffer slice \"" << name << "\".");
+ }
+
+ return i->second;
+}
+
+
+const DeepSlice &
+DeepFrameBuffer::operator [] (const char name[]) const
+{
+ SliceMap::const_iterator i = _map.find (name);
+
+ if (i == _map.end())
+ {
+ THROW (IEX_NAMESPACE::ArgExc,
+ "Cannot find frame buffer slice \"" << name << "\".");
+ }
+
+ return i->second;
+}
+
+
+DeepSlice &
+DeepFrameBuffer::operator [] (const string &name)
+{
+ return this->operator[] (name.c_str());
+}
+
+
+const DeepSlice &
+DeepFrameBuffer::operator [] (const string &name) const
+{
+ return this->operator[] (name.c_str());
+}
+
+
+DeepSlice *
+DeepFrameBuffer::findSlice (const char name[])
+{
+ SliceMap::iterator i = _map.find (name);
+ return (i == _map.end())? 0: &i->second;
+}
+
+
+const DeepSlice *
+DeepFrameBuffer::findSlice (const char name[]) const
+{
+ SliceMap::const_iterator i = _map.find (name);
+ return (i == _map.end())? 0: &i->second;
+}
+
+
+DeepSlice *
+DeepFrameBuffer::findSlice (const string &name)
+{
+ return findSlice (name.c_str());
+}
+
+
+const DeepSlice *
+DeepFrameBuffer::findSlice (const string &name) const
+{
+ return findSlice (name.c_str());
+}
+
+
+DeepFrameBuffer::Iterator
+DeepFrameBuffer::begin ()
+{
+ return _map.begin();
+}
+
+
+DeepFrameBuffer::ConstIterator
+DeepFrameBuffer::begin () const
+{
+ return _map.begin();
+}
+
+
+DeepFrameBuffer::Iterator
+DeepFrameBuffer::end ()
+{
+ return _map.end();
+}
+
+
+DeepFrameBuffer::ConstIterator
+DeepFrameBuffer::end () const
+{
+ return _map.end();
+}
+
+
+DeepFrameBuffer::Iterator
+DeepFrameBuffer::find (const char name[])
+{
+ return _map.find (name);
+}
+
+
+DeepFrameBuffer::ConstIterator
+DeepFrameBuffer::find (const char name[]) const
+{
+ return _map.find (name);
+}
+
+
+DeepFrameBuffer::Iterator
+DeepFrameBuffer::find (const string &name)
+{
+ return find (name.c_str());
+}
+
+
+DeepFrameBuffer::ConstIterator
+DeepFrameBuffer::find (const string &name) const
+{
+ return find (name.c_str());
+}
+
+
+void
+DeepFrameBuffer::insertSampleCountSlice(const Slice & slice)
+{
+ if (slice.type != UINT)
+ {
+ throw IEX_NAMESPACE::ArgExc("The type of sample count slice should be UINT.");
+ }
+
+ _sampleCounts = slice;
+}
+
+
+const Slice &
+DeepFrameBuffer::getSampleCountSlice() const
+{
+ return _sampleCounts;
+}
+
+OPENEXR_IMF_INTERNAL_NAMESPACE_SOURCE_EXIT
--- /dev/null
+///////////////////////////////////////////////////////////////////////////
+//
+// Copyright (c) 2011, Industrial Light & Magic, a division of Lucas
+// Digital Ltd. LLC
+//
+// All rights reserved.
+//
+// Redistribution and use in source and binary forms, with or without
+// modification, are permitted provided that the following conditions are
+// met:
+// * Redistributions of source code must retain the above copyright
+// notice, this list of conditions and the following disclaimer.
+// * Redistributions in binary form must reproduce the above
+// copyright notice, this list of conditions and the following disclaimer
+// in the documentation and/or other materials provided with the
+// distribution.
+// * Neither the name of Industrial Light & Magic nor the names of
+// its contributors may be used to endorse or promote products derived
+// from this software without specific prior written permission.
+//
+// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+//
+///////////////////////////////////////////////////////////////////////////
+
+#ifndef IMFDEEPFRAMEBUFFER_H_
+#define IMFDEEPFRAMEBUFFER_H_
+
+#include "ImfFrameBuffer.h"
+#include "ImfNamespace.h"
+#include "ImfExport.h"
+
+OPENEXR_IMF_INTERNAL_NAMESPACE_HEADER_ENTER
+
+//--------------------------------------------------------
+// Description of a single deep slice of the frame buffer:
+//--------------------------------------------------------
+
+struct DeepSlice : public Slice
+{
+ //---------------------------------------------------------------------
+ // The stride for each sample in this slice.
+ //
+ // Memory layout: The address of sample i in pixel (x, y) is
+ //
+ // base + (xp / xSampling) * xStride + (yp / ySampling) * yStride
+ // + i * sampleStride
+ //
+ // where xp and yp are computed as follows:
+ //
+ // * If we are reading or writing a scanline-based file:
+ //
+ // xp = x
+ // yp = y
+ //
+ // * If we are reading a tile whose upper left coorner is at (xt, yt):
+ //
+ // if xTileCoords is true then xp = x - xt, else xp = x
+ // if yTileCoords is true then yp = y - yt, else yp = y
+ //
+ //---------------------------------------------------------------------
+
+ int sampleStride;
+
+ //------------
+ // Constructor
+ //------------
+ IMF_EXPORT
+ DeepSlice (PixelType type = HALF,
+ char * base = 0,
+ size_t xStride = 0,
+ size_t yStride = 0,
+ size_t sampleStride = 0,
+ int xSampling = 1,
+ int ySampling = 1,
+ double fillValue = 0.0,
+ bool xTileCoords = false,
+ bool yTileCoords = false);
+};
+
+//-----------------
+// DeepFrameBuffer.
+//-----------------
+
+class DeepFrameBuffer
+{
+ public:
+
+
+ //------------
+ // Add a slice
+ //------------
+
+ IMF_EXPORT
+ void insert (const char name[],
+ const DeepSlice &slice);
+
+ IMF_EXPORT
+ void insert (const std::string &name,
+ const DeepSlice &slice);
+
+ //----------------------------------------------------------------
+ // Access to existing slices:
+ //
+ // [n] Returns a reference to the slice with name n.
+ // If no slice with name n exists, an IEX_NAMESPACE::ArgExc
+ // is thrown.
+ //
+ // findSlice(n) Returns a pointer to the slice with name n,
+ // or 0 if no slice with name n exists.
+ //
+ //----------------------------------------------------------------
+
+ IMF_EXPORT
+ DeepSlice & operator [] (const char name[]);
+ IMF_EXPORT
+ const DeepSlice & operator [] (const char name[]) const;
+
+ IMF_EXPORT
+ DeepSlice & operator [] (const std::string &name);
+ IMF_EXPORT
+ const DeepSlice & operator [] (const std::string &name) const;
+
+ IMF_EXPORT
+ DeepSlice * findSlice (const char name[]);
+ IMF_EXPORT
+ const DeepSlice * findSlice (const char name[]) const;
+
+ IMF_EXPORT
+ DeepSlice * findSlice (const std::string &name);
+ IMF_EXPORT
+ const DeepSlice * findSlice (const std::string &name) const;
+
+
+ //-----------------------------------------
+ // Iterator-style access to existing slices
+ //-----------------------------------------
+
+ typedef std::map <Name, DeepSlice> SliceMap;
+
+ class Iterator;
+ class ConstIterator;
+
+ IMF_EXPORT
+ Iterator begin ();
+ IMF_EXPORT
+ ConstIterator begin () const;
+
+ IMF_EXPORT
+ Iterator end ();
+ IMF_EXPORT
+ ConstIterator end () const;
+
+ IMF_EXPORT
+ Iterator find (const char name[]);
+ IMF_EXPORT
+ ConstIterator find (const char name[]) const;
+
+ IMF_EXPORT
+ Iterator find (const std::string &name);
+ IMF_EXPORT
+ ConstIterator find (const std::string &name) const;
+
+ //----------------------------------------------------
+ // Public function for accessing a sample count slice.
+ //----------------------------------------------------
+
+ IMF_EXPORT
+ void insertSampleCountSlice(const Slice & slice);
+ IMF_EXPORT
+ const Slice & getSampleCountSlice() const;
+
+ private:
+
+ SliceMap _map;
+ Slice _sampleCounts;
+};
+
+//----------
+// Iterators
+//----------
+
+class DeepFrameBuffer::Iterator
+{
+ public:
+
+ IMF_EXPORT
+ Iterator ();
+ IMF_EXPORT
+ Iterator (const DeepFrameBuffer::SliceMap::iterator &i);
+
+ IMF_EXPORT
+ Iterator & operator ++ ();
+ IMF_EXPORT
+ Iterator operator ++ (int);
+
+ IMF_EXPORT
+ const char * name () const;
+ IMF_EXPORT
+ DeepSlice & slice () const;
+
+ private:
+
+ friend class DeepFrameBuffer::ConstIterator;
+
+ DeepFrameBuffer::SliceMap::iterator _i;
+};
+
+
+class DeepFrameBuffer::ConstIterator
+{
+ public:
+
+ IMF_EXPORT
+ ConstIterator ();
+ IMF_EXPORT
+ ConstIterator (const DeepFrameBuffer::SliceMap::const_iterator &i);
+ IMF_EXPORT
+ ConstIterator (const DeepFrameBuffer::Iterator &other);
+
+ IMF_EXPORT
+ ConstIterator & operator ++ ();
+ IMF_EXPORT
+ ConstIterator operator ++ (int);
+
+ IMF_EXPORT
+ const char * name () const;
+ IMF_EXPORT
+ const DeepSlice & slice () const;
+
+ private:
+
+ friend bool operator == (const ConstIterator &, const ConstIterator &);
+ friend bool operator != (const ConstIterator &, const ConstIterator &);
+
+ DeepFrameBuffer::SliceMap::const_iterator _i;
+};
+
+
+//-----------------
+// Inline Functions
+//-----------------
+
+inline
+DeepFrameBuffer::Iterator::Iterator (): _i()
+{
+ // empty
+}
+
+
+inline
+DeepFrameBuffer::Iterator::Iterator (const DeepFrameBuffer::SliceMap::iterator &i):
+ _i (i)
+{
+ // empty
+}
+
+
+inline DeepFrameBuffer::Iterator &
+DeepFrameBuffer::Iterator::operator ++ ()
+{
+ ++_i;
+ return *this;
+}
+
+
+inline DeepFrameBuffer::Iterator
+DeepFrameBuffer::Iterator::operator ++ (int)
+{
+ Iterator tmp = *this;
+ ++_i;
+ return tmp;
+}
+
+
+inline const char *
+DeepFrameBuffer::Iterator::name () const
+{
+ return *_i->first;
+}
+
+
+inline DeepSlice &
+DeepFrameBuffer::Iterator::slice () const
+{
+ return _i->second;
+}
+
+
+inline
+DeepFrameBuffer::ConstIterator::ConstIterator (): _i()
+{
+ // empty
+}
+
+inline
+DeepFrameBuffer::ConstIterator::ConstIterator
+ (const DeepFrameBuffer::SliceMap::const_iterator &i): _i (i)
+{
+ // empty
+}
+
+
+inline
+DeepFrameBuffer::ConstIterator::ConstIterator (const DeepFrameBuffer::Iterator &other):
+ _i (other._i)
+{
+ // empty
+}
+
+inline DeepFrameBuffer::ConstIterator &
+DeepFrameBuffer::ConstIterator::operator ++ ()
+{
+ ++_i;
+ return *this;
+}
+
+
+inline DeepFrameBuffer::ConstIterator
+DeepFrameBuffer::ConstIterator::operator ++ (int)
+{
+ ConstIterator tmp = *this;
+ ++_i;
+ return tmp;
+}
+
+
+inline const char *
+DeepFrameBuffer::ConstIterator::name () const
+{
+ return *_i->first;
+}
+
+inline const DeepSlice &
+DeepFrameBuffer::ConstIterator::slice () const
+{
+ return _i->second;
+}
+
+
+inline bool
+operator == (const DeepFrameBuffer::ConstIterator &x,
+ const DeepFrameBuffer::ConstIterator &y)
+{
+ return x._i == y._i;
+}
+
+
+inline bool
+operator != (const DeepFrameBuffer::ConstIterator &x,
+ const DeepFrameBuffer::ConstIterator &y)
+{
+ return !(x == y);
+}
+
+
+OPENEXR_IMF_INTERNAL_NAMESPACE_HEADER_EXIT
+
+
+
+
+
+
+#endif /* IMFDEEPFRAMEBUFFER_H_ */
--- /dev/null
+///////////////////////////////////////////////////////////////////////////
+//
+// Copyright (c) 2013, Industrial Light & Magic, a division of Lucas
+// Digital Ltd. LLC
+//
+// All rights reserved.
+//
+// Redistribution and use in source and binary forms, with or without
+// modification, are permitted provided that the following conditions are
+// met:
+// * Redistributions of source code must retain the above copyright
+// notice, this list of conditions and the following disclaimer.
+// * Redistributions in binary form must reproduce the above
+// copyright notice, this list of conditions and the following disclaimer
+// in the documentation and/or other materials provided with the
+// distribution.
+// * Neither the name of Industrial Light & Magic nor the names of
+// its contributors may be used to endorse or promote products derived
+// from this software without specific prior written permission.
+//
+// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+//
+///////////////////////////////////////////////////////////////////////////
+
+
+#ifndef INCLUDED_IMF_DEEPIMAGESTATE_H
+#define INCLUDED_IMF_DEEPIMAGESTATE_H
+
+//-----------------------------------------------------------------------------
+//
+// enum DeepImageState -- describes how orderly the pixel data
+// in a deep image are
+//
+// The samples in a deep image pixel may be sorted according to
+// depth, and the sample depths or depth ranges may or may not
+// overlap each other. A pixel is
+//
+// - SORTED if for every i and j with i < j
+//
+// (Z[i] < Z[j]) || (Z[i] == Z[j] && ZBack[i] < ZBack[j]),
+//
+// - NON_OVERLAPPING if for every i and j with i != j
+//
+// (Z[i] < Z[j] && ZBack[i] <= Z[j]) ||
+// (Z[j] < Z[i] && ZBack[j] <= Z[i]) ||
+// (Z[i] == Z[j] && ZBack[i] <= Z[i] & ZBack[j] > Z[j]) ||
+// (Z[i] == Z[j] && ZBack[j] <= Z[j] & ZBack[i] > Z[i]),
+//
+// - TIDY if it is SORTED and NON_OVERLAPPING,
+//
+// - MESSY if it is neither SORTED nor NON_OVERLAPPING.
+//
+// A deep image is
+//
+// - MESSY if at least one of its pixels is MESSY,
+// - SORTED if all of its pixels are SORTED,
+// - NON_OVERLAPPING if all of its pixels are NON_OVERLAPPING,
+// - TIDY if all of its pixels are TIDY.
+//
+// Note: the rather complicated definition of NON_OVERLAPPING prohibits
+// overlapping volume samples, coincident point samples and point samples
+// in the middle of a volume sample, but it does allow point samples at
+// the front or back of a volume sample.
+//
+//-----------------------------------------------------------------------------
+
+#include "ImfNamespace.h"
+#include "ImfExport.h"
+
+
+OPENEXR_IMF_INTERNAL_NAMESPACE_HEADER_ENTER
+
+enum DeepImageState
+{
+ DIS_MESSY = 0,
+ DIS_SORTED = 1,
+ DIS_NON_OVERLAPPING = 2,
+ DIS_TIDY = 3,
+
+ DIS_NUMSTATES // Number of different image states
+};
+
+OPENEXR_IMF_INTERNAL_NAMESPACE_HEADER_EXIT
+
+
+#endif
--- /dev/null
+///////////////////////////////////////////////////////////////////////////
+//
+// Copyright (c) 2013, Industrial Light & Magic, a division of Lucas
+// Digital Ltd. LLC
+//
+// All rights reserved.
+//
+// Redistribution and use in source and binary forms, with or without
+// modification, are permitted provided that the following conditions are
+// met:
+// * Redistributions of source code must retain the above copyright
+// notice, this list of conditions and the following disclaimer.
+// * Redistributions in binary form must reproduce the above
+// copyright notice, this list of conditions and the following disclaimer
+// in the documentation and/or other materials provided with the
+// distribution.
+// * Neither the name of Industrial Light & Magic nor the names of
+// its contributors may be used to endorse or promote products derived
+// from this software without specific prior written permission.
+//
+// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+//
+///////////////////////////////////////////////////////////////////////////
+
+
+//-----------------------------------------------------------------------------
+//
+// class DeepImageStateAttribute
+//
+//-----------------------------------------------------------------------------
+
+#include <ImfDeepImageStateAttribute.h>
+
+
+OPENEXR_IMF_INTERNAL_NAMESPACE_SOURCE_ENTER
+
+using namespace OPENEXR_IMF_INTERNAL_NAMESPACE;
+
+template <>
+const char *
+DeepImageStateAttribute::staticTypeName ()
+{
+ return "deepImageState";
+}
+
+
+template <>
+void
+DeepImageStateAttribute::writeValueTo
+ (OPENEXR_IMF_INTERNAL_NAMESPACE::OStream &os, int version) const
+{
+ unsigned char tmp = _value;
+ Xdr::write <StreamIO> (os, tmp);
+}
+
+
+template <>
+void
+DeepImageStateAttribute::readValueFrom
+ (OPENEXR_IMF_INTERNAL_NAMESPACE::IStream &is, int size, int version)
+{
+ unsigned char tmp;
+ Xdr::read <StreamIO> (is, tmp);
+ _value = DeepImageState (tmp);
+}
+
+
+OPENEXR_IMF_INTERNAL_NAMESPACE_SOURCE_EXIT
--- /dev/null
+///////////////////////////////////////////////////////////////////////////
+//
+// Copyright (c) 2013, Industrial Light & Magic, a division of Lucas
+// Digital Ltd. LLC
+//
+// All rights reserved.
+//
+// Redistribution and use in source and binary forms, with or without
+// modification, are permitted provided that the following conditions are
+// met:
+// * Redistributions of source code must retain the above copyright
+// notice, this list of conditions and the following disclaimer.
+// * Redistributions in binary form must reproduce the above
+// copyright notice, this list of conditions and the following disclaimer
+// in the documentation and/or other materials provided with the
+// distribution.
+// * Neither the name of Industrial Light & Magic nor the names of
+// its contributors may be used to endorse or promote products derived
+// from this software without specific prior written permission.
+//
+// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+//
+///////////////////////////////////////////////////////////////////////////
+
+#ifndef INCLUDED_IMF_DEEPIMAGESTATE_ATTRIBUTE_H
+#define INCLUDED_IMF_DEEPIMAGESTATE_ATTRIBUTE_H
+
+
+//-----------------------------------------------------------------------------
+//
+// class DeepImageStateAttribute
+//
+//-----------------------------------------------------------------------------
+
+#include "ImfAttribute.h"
+#include "ImfDeepImageState.h"
+#include "ImfExport.h"
+
+OPENEXR_IMF_INTERNAL_NAMESPACE_HEADER_ENTER
+
+
+typedef TypedAttribute<OPENEXR_IMF_INTERNAL_NAMESPACE::DeepImageState>
+ DeepImageStateAttribute;
+
+template <> IMF_EXPORT const char *DeepImageStateAttribute::staticTypeName ();
+
+template <> IMF_EXPORT
+void DeepImageStateAttribute::writeValueTo
+ (OPENEXR_IMF_INTERNAL_NAMESPACE::OStream &, int) const;
+
+template <> IMF_EXPORT
+void DeepImageStateAttribute::readValueFrom
+ (OPENEXR_IMF_INTERNAL_NAMESPACE::IStream &, int, int);
+
+
+OPENEXR_IMF_INTERNAL_NAMESPACE_HEADER_EXIT
+
+#endif
--- /dev/null
+///////////////////////////////////////////////////////////////////////////
+//
+// Copyright (c) 2011, Industrial Light & Magic, a division of Lucas
+// Digital Ltd. LLC
+//
+// All rights reserved.
+//
+// Redistribution and use in source and binary forms, with or without
+// modification, are permitted provided that the following conditions are
+// met:
+// * Redistributions of source code must retain the above copyright
+// notice, this list of conditions and the following disclaimer.
+// * Redistributions in binary form must reproduce the above
+// copyright notice, this list of conditions and the following disclaimer
+// in the documentation and/or other materials provided with the
+// distribution.
+// * Neither the name of Industrial Light & Magic nor the names of
+// its contributors may be used to endorse or promote products derived
+// from this software without specific prior written permission.
+//
+// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+//
+///////////////////////////////////////////////////////////////////////////
+
+
+//-----------------------------------------------------------------------------
+//
+// class DeepScanLineInputFile
+//
+//-----------------------------------------------------------------------------
+
+#include <ImfDeepScanLineInputFile.h>
+#include <ImfChannelList.h>
+#include <ImfMisc.h>
+#include <ImfStdIO.h>
+#include <ImfCompressor.h>
+#include <ImfXdr.h>
+#include <ImfConvert.h>
+#include <ImfThreading.h>
+#include <ImfPartType.h>
+#include <ImfVersion.h>
+#include "ImfMultiPartInputFile.h"
+#include "ImfDeepFrameBuffer.h"
+#include "ImfInputStreamMutex.h"
+#include "ImfInputPartData.h"
+
+
+#include "ImathBox.h"
+#include "ImathFun.h"
+
+
+#include "IlmThreadPool.h"
+#include "IlmThreadSemaphore.h"
+#include "IlmThreadMutex.h"
+
+#include "Iex.h"
+
+#include <string>
+#include <vector>
+#include <assert.h>
+#include <limits>
+#include <algorithm>
+
+
+#include "ImfNamespace.h"
+OPENEXR_IMF_INTERNAL_NAMESPACE_SOURCE_ENTER
+
+using IMATH_NAMESPACE::Box2i;
+using IMATH_NAMESPACE::divp;
+using IMATH_NAMESPACE::modp;
+using std::string;
+using std::vector;
+using std::ifstream;
+using std::min;
+using std::max;
+using ILMTHREAD_NAMESPACE::Mutex;
+using ILMTHREAD_NAMESPACE::Lock;
+using ILMTHREAD_NAMESPACE::Semaphore;
+using ILMTHREAD_NAMESPACE::Task;
+using ILMTHREAD_NAMESPACE::TaskGroup;
+using ILMTHREAD_NAMESPACE::ThreadPool;
+
+namespace {
+
+struct InSliceInfo
+{
+ PixelType typeInFrameBuffer;
+ PixelType typeInFile;
+ char * base;
+ char* pointerArrayBase;
+ size_t xPointerStride;
+ size_t yPointerStride;
+ size_t sampleStride;
+ int xSampling;
+ int ySampling;
+ bool fill;
+ bool skip;
+ double fillValue;
+
+ InSliceInfo (PixelType typeInFrameBuffer = HALF,
+ char * base = NULL,
+ PixelType typeInFile = HALF,
+ size_t xPointerStride = 0,
+ size_t yPointerStride = 0,
+ size_t sampleStride = 0,
+ int xSampling = 1,
+ int ySampling = 1,
+ bool fill = false,
+ bool skip = false,
+ double fillValue = 0.0);
+};
+
+
+InSliceInfo::InSliceInfo (PixelType tifb,
+ char * b,
+ PixelType tifl,
+ size_t xpst,
+ size_t ypst,
+ size_t spst,
+ int xsm, int ysm,
+ bool f, bool s,
+ double fv)
+:
+ typeInFrameBuffer (tifb),
+ typeInFile (tifl),
+ base(b),
+ xPointerStride (xpst),
+ yPointerStride (ypst),
+ sampleStride (spst),
+ xSampling (xsm),
+ ySampling (ysm),
+ fill (f),
+ skip (s),
+ fillValue (fv)
+{
+ // empty
+}
+
+
+struct LineBuffer
+{
+ const char * uncompressedData;
+ char * buffer;
+ Int64 packedDataSize;
+ Int64 unpackedDataSize;
+
+ int minY;
+ int maxY;
+ Compressor * compressor;
+ Compressor::Format format;
+ int number;
+ bool hasException;
+ string exception;
+
+ LineBuffer ();
+ ~LineBuffer ();
+
+ inline void wait () {_sem.wait();}
+ inline void post () {_sem.post();}
+
+ private:
+
+ Semaphore _sem;
+};
+
+
+LineBuffer::LineBuffer ():
+ uncompressedData (0),
+ buffer (0),
+ packedDataSize (0),
+ compressor (0),
+ format (defaultFormat(compressor)),
+ number (-1),
+ hasException (false),
+ exception (),
+ _sem (1)
+{
+ // empty
+}
+
+
+LineBuffer::~LineBuffer ()
+{
+ if (compressor != 0)
+ delete compressor;
+}
+
+} // namespace
+
+
+struct DeepScanLineInputFile::Data: public Mutex
+{
+ Header header; // the image header
+ int version; // file's version
+ DeepFrameBuffer frameBuffer; // framebuffer to write into
+ LineOrder lineOrder; // order of the scanlines in file
+ int minX; // data window's min x coord
+ int maxX; // data window's max x coord
+ int minY; // data window's min y coord
+ int maxY; // data window's max x coord
+ vector<Int64> lineOffsets; // stores offsets in file for
+ // each line
+ bool fileIsComplete; // True if no scanlines are missing
+ // in the file
+ int nextLineBufferMinY; // minimum y of the next linebuffer
+ vector<size_t> bytesPerLine; // combined size of a line over all
+ // channels
+ vector<size_t> offsetInLineBuffer; // offset for each scanline in its
+ // linebuffer
+ vector<InSliceInfo*> slices; // info about channels in file
+
+ vector<LineBuffer*> lineBuffers; // each holds one line buffer
+ int linesInBuffer; // number of scanlines each buffer
+ // holds
+ int partNumber; // part number
+ int numThreads; // number of threads
+
+ bool multiPartBackwardSupport; // if we are reading a multipart file using single file API
+ MultiPartInputFile* multiPartFile; // for multipart files opened as single part
+ bool memoryMapped; // if the stream is memory mapped
+
+ Array2D<unsigned int> sampleCount; // the number of samples
+ // in each pixel
+
+ Array<unsigned int> lineSampleCount; // the number of samples
+ // in each line
+
+ Array<bool> gotSampleCount; // for each scanline, indicating if
+ // we have got its sample count table
+
+ char* sampleCountSliceBase; // pointer to the start of
+ // the sample count array
+ int sampleCountXStride; // x stride of the sample count array
+ int sampleCountYStride; // y stride of the sample count array
+ bool frameBufferValid; // set by setFrameBuffer: excepts if readPixelSampleCounts if false
+
+ Array<char> sampleCountTableBuffer;
+ // the buffer for sample count table
+
+ Compressor* sampleCountTableComp;
+ // the decompressor for sample count table
+
+ int combinedSampleSize; // total size of all channels combined: used to sanity check sample table size
+
+ int maxSampleCountTableSize;
+ // the max size in bytes for a pixel
+ // sample count table
+ InputStreamMutex* _streamData;
+ bool _deleteStream;
+
+
+ Data (int numThreads);
+ ~Data ();
+
+ inline LineBuffer * getLineBuffer (int number); // hash function from line
+ // buffer indices into our
+ // vector of line buffers
+};
+
+
+DeepScanLineInputFile::Data::Data (int numThreads):
+ partNumber(-1),
+ numThreads(numThreads),
+ multiPartBackwardSupport(false),
+ multiPartFile(NULL),
+ memoryMapped(false),
+ frameBufferValid(false),
+ _streamData(NULL),
+ _deleteStream(false)
+{
+ //
+ // We need at least one lineBuffer, but if threading is used,
+ // to keep n threads busy we need 2*n lineBuffers
+ //
+
+ lineBuffers.resize (max (1, 2 * numThreads));
+
+ for (size_t i = 0; i < lineBuffers.size(); i++)
+ lineBuffers[i] = 0;
+
+ sampleCountTableComp = 0;
+}
+
+
+DeepScanLineInputFile::Data::~Data ()
+{
+ for (size_t i = 0; i < lineBuffers.size(); i++)
+ if (lineBuffers[i] != 0)
+ delete lineBuffers[i];
+
+ for (size_t i = 0; i < slices.size(); i++)
+ delete slices[i];
+
+ if (sampleCountTableComp != 0)
+ delete sampleCountTableComp;
+
+ if (multiPartBackwardSupport)
+ delete multiPartFile;
+}
+
+
+inline LineBuffer *
+DeepScanLineInputFile::Data::getLineBuffer (int lineBufferNumber)
+{
+ return lineBuffers[lineBufferNumber % lineBuffers.size()];
+}
+
+
+namespace {
+
+
+void
+reconstructLineOffsets (OPENEXR_IMF_INTERNAL_NAMESPACE::IStream &is,
+ LineOrder lineOrder,
+ vector<Int64> &lineOffsets)
+{
+ Int64 position = is.tellg();
+
+ try
+ {
+ for (unsigned int i = 0; i < lineOffsets.size(); i++)
+ {
+ Int64 lineOffset = is.tellg();
+
+ int y;
+ OPENEXR_IMF_INTERNAL_NAMESPACE::Xdr::read <OPENEXR_IMF_INTERNAL_NAMESPACE::StreamIO> (is, y);
+
+ Int64 packed_offset;
+ Int64 packed_sample;
+ OPENEXR_IMF_INTERNAL_NAMESPACE::Xdr::read <OPENEXR_IMF_INTERNAL_NAMESPACE::StreamIO> (is, packed_offset);
+ OPENEXR_IMF_INTERNAL_NAMESPACE::Xdr::read <OPENEXR_IMF_INTERNAL_NAMESPACE::StreamIO> (is, packed_sample);
+ //next is unpacked sample table size - skip this too
+ Xdr::skip <StreamIO> (is, packed_offset+packed_sample+8);
+
+ if (lineOrder == INCREASING_Y)
+ lineOffsets[i] = lineOffset;
+ else
+ lineOffsets[lineOffsets.size() - i - 1] = lineOffset;
+ }
+ }
+ catch (...)
+ {
+ //
+ // Suppress all exceptions. This functions is
+ // called only to reconstruct the line offset
+ // table for incomplete files, and exceptions
+ // are likely.
+ //
+ }
+
+ is.clear();
+ is.seekg (position);
+}
+
+
+void
+readLineOffsets (OPENEXR_IMF_INTERNAL_NAMESPACE::IStream &is,
+ LineOrder lineOrder,
+ vector<Int64> &lineOffsets,
+ bool &complete)
+{
+ for (unsigned int i = 0; i < lineOffsets.size(); i++)
+ {
+ OPENEXR_IMF_INTERNAL_NAMESPACE::Xdr::read <OPENEXR_IMF_INTERNAL_NAMESPACE::StreamIO> (is, lineOffsets[i]);
+ }
+
+ complete = true;
+
+ for (unsigned int i = 0; i < lineOffsets.size(); i++)
+ {
+ if (lineOffsets[i] <= 0)
+ {
+ //
+ // Invalid data in the line offset table mean that
+ // the file is probably incomplete (the table is
+ // the last thing written to the file). Either
+ // some process is still busy writing the file,
+ // or writing the file was aborted.
+ //
+ // We should still be able to read the existing
+ // parts of the file. In order to do this, we
+ // have to make a sequential scan over the scan
+ // line data to reconstruct the line offset table.
+ //
+
+ complete = false;
+ reconstructLineOffsets (is, lineOrder, lineOffsets);
+ break;
+ }
+ }
+}
+
+
+void
+readPixelData (InputStreamMutex *streamData,
+ DeepScanLineInputFile::Data *ifd,
+ int minY,
+ char *&buffer,
+ Int64 &packedDataSize,
+ Int64 &unpackedDataSize)
+{
+ //
+ // Read a single line buffer from the input file.
+ //
+ // If the input file is not memory-mapped, we copy the pixel data into
+ // into the array pointed to by buffer. If the file is memory-mapped,
+ // then we change where buffer points to instead of writing into the
+ // array (hence buffer needs to be a reference to a char *).
+ //
+
+ int lineBufferNumber = (minY - ifd->minY) / ifd->linesInBuffer;
+
+ Int64 lineOffset = ifd->lineOffsets[lineBufferNumber];
+
+ if (lineOffset == 0)
+ THROW (IEX_NAMESPACE::InputExc, "Scan line " << minY << " is missing.");
+
+ //
+ // Seek to the start of the scan line in the file,
+ // if necessary.
+ //
+
+ if (!isMultiPart(ifd->version))
+ {
+ if (ifd->nextLineBufferMinY != minY)
+ streamData->is->seekg (lineOffset);
+ }
+ else
+ {
+ //
+ // In a multi-part file, the file pointer may have been moved by
+ // other parts, so we have to ask tellg() where we are.
+ //
+ if (streamData->is->tellg() != ifd->lineOffsets[lineBufferNumber])
+ streamData->is->seekg (lineOffset);
+ }
+
+ //
+ // Read the data block's header.
+ //
+
+ int yInFile;
+
+ //
+ // Read the part number when we are dealing with a multi-part file.
+ //
+
+ if (isMultiPart(ifd->version))
+ {
+ int partNumber;
+ OPENEXR_IMF_INTERNAL_NAMESPACE::Xdr::read <OPENEXR_IMF_INTERNAL_NAMESPACE::StreamIO> (*streamData->is, partNumber);
+ if (partNumber != ifd->partNumber)
+ {
+ THROW (IEX_NAMESPACE::ArgExc, "Unexpected part number " << partNumber
+ << ", should be " << ifd->partNumber << ".");
+ }
+ }
+
+ OPENEXR_IMF_INTERNAL_NAMESPACE::Xdr::read <OPENEXR_IMF_INTERNAL_NAMESPACE::StreamIO> (*streamData->is, yInFile);
+
+ if (yInFile != minY)
+ throw IEX_NAMESPACE::InputExc ("Unexpected data block y coordinate.");
+
+ Int64 sampleCountTableSize;
+ OPENEXR_IMF_INTERNAL_NAMESPACE::Xdr::read <OPENEXR_IMF_INTERNAL_NAMESPACE::StreamIO> (*streamData->is, sampleCountTableSize);
+ OPENEXR_IMF_INTERNAL_NAMESPACE::Xdr::read <OPENEXR_IMF_INTERNAL_NAMESPACE::StreamIO> (*streamData->is, packedDataSize);
+ OPENEXR_IMF_INTERNAL_NAMESPACE::Xdr::read <OPENEXR_IMF_INTERNAL_NAMESPACE::StreamIO> (*streamData->is, unpackedDataSize);
+
+
+ //
+ // We make a check on the data size requirements here.
+ // Whilst we wish to store 64bit sizes on disk, not all the compressors
+ // have been made to work with such data sizes and are still limited to
+ // using signed 32 bit (int) for the data size. As such, this version
+ // insists that we validate that the data size does not exceed the data
+ // type max limit.
+ // @TODO refactor the compressor code to ensure full 64-bit support.
+ //
+
+ int compressorMaxDataSize = std::numeric_limits<int>::max();
+ if (packedDataSize > Int64(compressorMaxDataSize) ||
+ unpackedDataSize > Int64(compressorMaxDataSize))
+ {
+ THROW (IEX_NAMESPACE::ArgExc, "This version of the library does not support "
+ << "the allocation of data with size > " << compressorMaxDataSize
+ << " file unpacked size :" << unpackedDataSize
+ << " file packed size :" << packedDataSize << ".\n");
+ }
+
+ //
+ // Skip the pixel sample count table because we have read this data.
+ //
+
+ Xdr::skip <StreamIO> (*streamData->is, sampleCountTableSize);
+
+ //
+ // Read the pixel data.
+ //
+
+ if (streamData->is->isMemoryMapped ())
+ buffer = streamData->is->readMemoryMapped (packedDataSize);
+ else
+ {
+ // (TODO) check if the packed data size is too big?
+ // (TODO) better memory management. Don't delete buffer all the time.
+ if (buffer != 0) delete[] buffer;
+ buffer = new char[packedDataSize];
+ streamData->is->read (buffer, packedDataSize);
+ }
+
+ //
+ // Keep track of which scan line is the next one in
+ // the file, so that we can avoid redundant seekg()
+ // operations (seekg() can be fairly expensive).
+ //
+
+ if (ifd->lineOrder == INCREASING_Y)
+ ifd->nextLineBufferMinY = minY + ifd->linesInBuffer;
+ else
+ ifd->nextLineBufferMinY = minY - ifd->linesInBuffer;
+}
+
+//
+// A LineBufferTask encapsulates the task uncompressing a set of
+// scanlines (line buffer) and copying them into the frame buffer.
+//
+
+class LineBufferTask : public Task
+{
+ public:
+
+ LineBufferTask (TaskGroup *group,
+ DeepScanLineInputFile::Data *ifd,
+ LineBuffer *lineBuffer,
+ int scanLineMin,
+ int scanLineMax);
+
+ virtual ~LineBufferTask ();
+
+ virtual void execute ();
+
+ private:
+
+ DeepScanLineInputFile::Data * _ifd;
+ LineBuffer * _lineBuffer;
+ int _scanLineMin;
+ int _scanLineMax;
+};
+
+
+LineBufferTask::LineBufferTask
+ (TaskGroup *group,
+ DeepScanLineInputFile::Data *ifd,
+ LineBuffer *lineBuffer,
+ int scanLineMin,
+ int scanLineMax)
+:
+ Task (group),
+ _ifd (ifd),
+ _lineBuffer (lineBuffer),
+ _scanLineMin (scanLineMin),
+ _scanLineMax (scanLineMax)
+{
+ // empty
+}
+
+
+LineBufferTask::~LineBufferTask ()
+{
+ //
+ // Signal that the line buffer is now free
+ //
+
+ _lineBuffer->post ();
+}
+
+
+void
+LineBufferTask::execute ()
+{
+ try
+ {
+ //
+ // Uncompress the data, if necessary
+ //
+
+ if (_lineBuffer->uncompressedData == 0)
+ {
+ Int64 uncompressedSize = 0;
+ int maxY = min (_lineBuffer->maxY, _ifd->maxY);
+
+ for (int i = _lineBuffer->minY - _ifd->minY;
+ i <= maxY - _ifd->minY;
+ ++i)
+ {
+ uncompressedSize += (int) _ifd->bytesPerLine[i];
+ }
+
+ //
+ // Create the compressor everytime when we want to use it,
+ // because we don't know maxBytesPerLine beforehand.
+ // (TODO) optimize this. don't do this every time.
+ //
+
+ if (_lineBuffer->compressor != 0)
+ delete _lineBuffer->compressor;
+ Int64 maxBytesPerLine = 0;
+ for (int i = _lineBuffer->minY - _ifd->minY;
+ i <= maxY - _ifd->minY;
+ ++i)
+ {
+ if (_ifd->bytesPerLine[i] > maxBytesPerLine)
+ maxBytesPerLine = _ifd->bytesPerLine[i];
+ }
+ _lineBuffer->compressor = newCompressor(_ifd->header.compression(),
+ maxBytesPerLine,
+ _ifd->header);
+
+ if (_lineBuffer->compressor &&
+ _lineBuffer->packedDataSize < uncompressedSize)
+ {
+ _lineBuffer->format = _lineBuffer->compressor->format();
+
+ _lineBuffer->packedDataSize = _lineBuffer->compressor->uncompress
+ (_lineBuffer->buffer, _lineBuffer->packedDataSize,
+ _lineBuffer->minY, _lineBuffer->uncompressedData);
+ }
+ else
+ {
+ //
+ // If the line is uncompressed, it's in XDR format,
+ // regardless of the compressor's output format.
+ //
+
+ _lineBuffer->format = Compressor::XDR;
+ _lineBuffer->uncompressedData = _lineBuffer->buffer;
+ }
+ }
+
+ int yStart, yStop, dy;
+
+ if (_ifd->lineOrder == INCREASING_Y)
+ {
+ yStart = _scanLineMin;
+ yStop = _scanLineMax + 1;
+ dy = 1;
+ }
+ else
+ {
+ yStart = _scanLineMax;
+ yStop = _scanLineMin - 1;
+ dy = -1;
+ }
+
+ for (int y = yStart; y != yStop; y += dy)
+ {
+ //
+ // Convert one scan line's worth of pixel data back
+ // from the machine-independent representation, and
+ // store the result in the frame buffer.
+ //
+
+ const char *readPtr = _lineBuffer->uncompressedData +
+ _ifd->offsetInLineBuffer[y - _ifd->minY];
+
+ //
+ // Iterate over all image channels.
+ //
+
+ for (unsigned int i = 0; i < _ifd->slices.size(); ++i)
+ {
+ //
+ // Test if scan line y of this channel contains any data
+ // (the scan line contains data only if y % ySampling == 0).
+ //
+
+ InSliceInfo &slice = *_ifd->slices[i];
+
+ if (modp (y, slice.ySampling) != 0)
+ continue;
+
+ //
+ // Find the x coordinates of the leftmost and rightmost
+ // sampled pixels (i.e. pixels within the data window
+ // for which x % xSampling == 0).
+ //
+
+ //
+ // Fill the frame buffer with pixel data.
+ //
+
+ if (slice.skip)
+ {
+ //
+ // The file contains data for this channel, but
+ // the frame buffer contains no slice for this channel.
+ //
+
+ skipChannel (readPtr, slice.typeInFile,
+ _ifd->lineSampleCount[y - _ifd->minY]);
+ }
+ else
+ {
+ //
+ // The frame buffer contains a slice for this channel.
+ //
+
+ int width = (_ifd->maxX - _ifd->minX + 1);
+
+ copyIntoDeepFrameBuffer (readPtr, slice.base,
+ (char*) (&_ifd->sampleCount[0][0]
+ - _ifd->minX
+ - _ifd->minY * width),
+ sizeof(unsigned int) * 1,
+ sizeof(unsigned int) * width,
+ y, _ifd->minX, _ifd->maxX,
+ 0, 0,
+ 0, 0,
+ slice.sampleStride,
+ slice.xPointerStride,
+ slice.yPointerStride,
+ slice.fill,
+ slice.fillValue, _lineBuffer->format,
+ slice.typeInFrameBuffer,
+ slice.typeInFile);
+ }
+ }
+ }
+ }
+ catch (std::exception &e)
+ {
+ if (!_lineBuffer->hasException)
+ {
+ _lineBuffer->exception = e.what();
+ _lineBuffer->hasException = true;
+ }
+ }
+ catch (...)
+ {
+ if (!_lineBuffer->hasException)
+ {
+ _lineBuffer->exception = "unrecognized exception";
+ _lineBuffer->hasException = true;
+ }
+ }
+}
+
+
+LineBufferTask *
+newLineBufferTask
+ (TaskGroup *group,
+ DeepScanLineInputFile::Data *ifd,
+ int number,
+ int scanLineMin,
+ int scanLineMax)
+{
+ //
+ // Wait for a line buffer to become available, fill the line
+ // buffer with raw data from the file if necessary, and create
+ // a new LineBufferTask whose execute() method will uncompress
+ // the contents of the buffer and copy the pixels into the
+ // frame buffer.
+ //
+
+ LineBuffer *lineBuffer = ifd->getLineBuffer (number);
+
+ try
+ {
+ lineBuffer->wait ();
+
+ if (lineBuffer->number != number)
+ {
+ lineBuffer->minY = ifd->minY + number * ifd->linesInBuffer;
+ lineBuffer->maxY = lineBuffer->minY + ifd->linesInBuffer - 1;
+
+ lineBuffer->number = number;
+ lineBuffer->uncompressedData = 0;
+
+ readPixelData (ifd->_streamData, ifd, lineBuffer->minY,
+ lineBuffer->buffer,
+ lineBuffer->packedDataSize,
+ lineBuffer->unpackedDataSize);
+ }
+ }
+ catch (std::exception &e)
+ {
+ if (!lineBuffer->hasException)
+ {
+ lineBuffer->exception = e.what();
+ lineBuffer->hasException = true;
+ }
+ lineBuffer->number = -1;
+ lineBuffer->post();
+ throw;
+ }
+ catch (...)
+ {
+ //
+ // Reading from the file caused an exception.
+ // Signal that the line buffer is free, and
+ // re-throw the exception.
+ //
+
+ lineBuffer->exception = "unrecognized exception";
+ lineBuffer->hasException = true;
+ lineBuffer->number = -1;
+ lineBuffer->post();
+ throw;
+ }
+
+ scanLineMin = max (lineBuffer->minY, scanLineMin);
+ scanLineMax = min (lineBuffer->maxY, scanLineMax);
+
+ return new LineBufferTask (group, ifd, lineBuffer,
+ scanLineMin, scanLineMax);
+}
+
+} // namespace
+
+
+void DeepScanLineInputFile::initialize(const Header& header)
+{
+ try
+ {
+ if (header.type() != DEEPSCANLINE)
+ throw IEX_NAMESPACE::ArgExc("Can't build a DeepScanLineInputFile from "
+ "a type-mismatched part.");
+
+ if(header.version()!=1)
+ {
+ THROW(IEX_NAMESPACE::ArgExc, "Version " << header.version() << " not supported for deepscanline images in this version of the library");
+ }
+
+ _data->header = header;
+
+ _data->lineOrder = _data->header.lineOrder();
+
+ const Box2i &dataWindow = _data->header.dataWindow();
+
+ _data->minX = dataWindow.min.x;
+ _data->maxX = dataWindow.max.x;
+ _data->minY = dataWindow.min.y;
+ _data->maxY = dataWindow.max.y;
+
+ _data->sampleCount.resizeErase(_data->maxY - _data->minY + 1,
+ _data->maxX - _data->minX + 1);
+ _data->lineSampleCount.resizeErase(_data->maxY - _data->minY + 1);
+
+ Compressor* compressor = newCompressor(_data->header.compression(),
+ 0,
+ _data->header);
+
+ _data->linesInBuffer = numLinesInBuffer (compressor);
+
+ delete compressor;
+
+ _data->nextLineBufferMinY = _data->minY - 1;
+
+ int lineOffsetSize = (dataWindow.max.y - dataWindow.min.y +
+ _data->linesInBuffer) / _data->linesInBuffer;
+
+ _data->lineOffsets.resize (lineOffsetSize);
+
+ for (size_t i = 0; i < _data->lineBuffers.size(); i++)
+ _data->lineBuffers[i] = new LineBuffer ();
+
+ _data->gotSampleCount.resizeErase(_data->maxY - _data->minY + 1);
+ for (int i = 0; i < _data->maxY - _data->minY + 1; i++)
+ _data->gotSampleCount[i] = false;
+
+ _data->maxSampleCountTableSize = min(_data->linesInBuffer, _data->maxY - _data->minY + 1) *
+ (_data->maxX - _data->minX + 1) *
+ sizeof(unsigned int);
+
+ _data->sampleCountTableBuffer.resizeErase(_data->maxSampleCountTableSize);
+
+ _data->sampleCountTableComp = newCompressor(_data->header.compression(),
+ _data->maxSampleCountTableSize,
+ _data->header);
+
+ _data->bytesPerLine.resize (_data->maxY - _data->minY + 1);
+
+ const ChannelList & c=header.channels();
+
+ _data->combinedSampleSize=0;
+ for(ChannelList::ConstIterator i=c.begin();i!=c.end();i++)
+ {
+ switch(i.channel().type)
+ {
+ case OPENEXR_IMF_INTERNAL_NAMESPACE::HALF :
+ _data->combinedSampleSize+=Xdr::size<half>();
+ break;
+ case OPENEXR_IMF_INTERNAL_NAMESPACE::FLOAT :
+ _data->combinedSampleSize+=Xdr::size<float>();
+ break;
+ case OPENEXR_IMF_INTERNAL_NAMESPACE::UINT :
+ _data->combinedSampleSize+=Xdr::size<unsigned int>();
+ break;
+ default :
+ THROW(IEX_NAMESPACE::ArgExc, "Bad type for channel " << i.name() << " initializing deepscanline reader");
+
+ }
+ }
+
+ }
+ catch (...)
+ {
+ delete _data;
+ _data=NULL;
+ throw;
+ }
+}
+
+
+DeepScanLineInputFile::DeepScanLineInputFile(InputPartData* part)
+
+{
+
+ _data = new Data(part->numThreads);
+ _data->_deleteStream=false;
+ _data->_streamData = part->mutex;
+ _data->memoryMapped = _data->_streamData->is->isMemoryMapped();
+ _data->version = part->version;
+
+ initialize(part->header);
+
+ _data->lineOffsets = part->chunkOffsets;
+
+ _data->partNumber = part->partNumber;
+}
+
+
+DeepScanLineInputFile::DeepScanLineInputFile
+ (const char fileName[], int numThreads)
+:
+ _data (new Data (numThreads))
+{
+ _data->_streamData = new InputStreamMutex();
+ _data->_deleteStream = true;
+ OPENEXR_IMF_INTERNAL_NAMESPACE::IStream* is = 0;
+
+ try
+ {
+ is = new StdIFStream (fileName);
+ readMagicNumberAndVersionField(*is, _data->version);
+ //
+ // Backward compatibility to read multpart file.
+ //
+ if (isMultiPart(_data->version))
+ {
+ compatibilityInitialize(*is);
+ return;
+ }
+ _data->_streamData->is = is;
+ _data->memoryMapped = is->isMemoryMapped();
+ _data->header.readFrom (*_data->_streamData->is, _data->version);
+ _data->header.sanityCheck (isTiled (_data->version));
+
+ initialize(_data->header);
+
+ readLineOffsets (*_data->_streamData->is,
+ _data->lineOrder,
+ _data->lineOffsets,
+ _data->fileIsComplete);
+ }
+ catch (IEX_NAMESPACE::BaseExc &e)
+ {
+ if (is) delete is;
+ if (_data && _data->_streamData) delete _data->_streamData;
+ if (_data) delete _data;
+
+ REPLACE_EXC (e, "Cannot read image file "
+ "\"" << fileName << "\". " << e.what());
+ throw;
+ }
+ catch (...)
+ {
+ if (is) delete is;
+ if (_data && _data->_streamData) delete _data->_streamData;
+ if (_data) delete _data;
+
+ throw;
+ }
+}
+
+
+DeepScanLineInputFile::DeepScanLineInputFile
+ (const Header &header,
+ OPENEXR_IMF_INTERNAL_NAMESPACE::IStream *is,
+ int version,
+ int numThreads)
+:
+ _data (new Data (numThreads))
+{
+ _data->_streamData=new InputStreamMutex();
+ _data->_deleteStream=false;
+ _data->_streamData->is = is;
+
+ _data->memoryMapped = is->isMemoryMapped();
+
+ _data->version =version;
+
+ initialize (header);
+
+ readLineOffsets (*_data->_streamData->is,
+ _data->lineOrder,
+ _data->lineOffsets,
+ _data->fileIsComplete);
+}
+
+
+DeepScanLineInputFile::~DeepScanLineInputFile ()
+{
+ if (_data->_deleteStream)
+ delete _data->_streamData->is;
+
+ if (_data)
+ {
+ if (!_data->memoryMapped)
+ for (size_t i = 0; i < _data->lineBuffers.size(); i++)
+ delete [] _data->lineBuffers[i]->buffer;
+
+ //
+ // Unless this file was opened via the multipart API, delete the streamdata
+ // object too.
+ // (TODO) it should be "isMultiPart(data->version)", but when there is only
+ // single part,
+ // (see the above constructor) the version field is not set.
+ //
+ // (TODO) we should have a way to tell if the stream data is owned by this
+ // file or by a parent multipart file.
+ //
+
+ if (_data->partNumber == -1 && _data->_streamData)
+ delete _data->_streamData;
+
+ delete _data;
+ }
+}
+
+void
+DeepScanLineInputFile::compatibilityInitialize(OPENEXR_IMF_INTERNAL_NAMESPACE::IStream& is)
+{
+ is.seekg(0);
+ //
+ // Construct a MultiPartInputFile, initialize TiledInputFile
+ // with the part 0 data.
+ // (TODO) maybe change the third parameter of the constructor of MultiPartInputFile later.
+ //
+ _data->multiPartBackwardSupport = true;
+ _data->multiPartFile = new MultiPartInputFile(is, _data->numThreads);
+ InputPartData* part = _data->multiPartFile->getPart(0);
+
+ multiPartInitialize(part);
+}
+
+void DeepScanLineInputFile::multiPartInitialize(InputPartData* part)
+{
+
+ _data->_streamData = part->mutex;
+ _data->memoryMapped = _data->_streamData->is->isMemoryMapped();
+ _data->version = part->version;
+
+ initialize(part->header);
+
+ _data->lineOffsets = part->chunkOffsets;
+
+ _data->partNumber = part->partNumber;
+
+}
+
+
+const char *
+DeepScanLineInputFile::fileName () const
+{
+ return _data->_streamData->is->fileName();
+}
+
+
+const Header &
+DeepScanLineInputFile::header () const
+{
+ return _data->header;
+}
+
+
+int
+DeepScanLineInputFile::version () const
+{
+ return _data->version;
+}
+
+
+void
+DeepScanLineInputFile::setFrameBuffer (const DeepFrameBuffer &frameBuffer)
+{
+ Lock lock (*_data->_streamData);
+
+
+ //
+ // Check if the new frame buffer descriptor is
+ // compatible with the image file header.
+ //
+
+ const ChannelList &channels = _data->header.channels();
+
+ for (DeepFrameBuffer::ConstIterator j = frameBuffer.begin();
+ j != frameBuffer.end();
+ ++j)
+ {
+ ChannelList::ConstIterator i = channels.find (j.name());
+
+ if (i == channels.end())
+ continue;
+
+ if (i.channel().xSampling != j.slice().xSampling ||
+ i.channel().ySampling != j.slice().ySampling)
+ THROW (IEX_NAMESPACE::ArgExc, "X and/or y subsampling factors "
+ "of \"" << i.name() << "\" channel "
+ "of input file \"" << fileName() << "\" are "
+ "not compatible with the frame buffer's "
+ "subsampling factors.");
+ }
+
+ //
+ // Store the pixel sample count table.
+ // (TODO) Support for different sampling rates?
+ //
+
+ const Slice& sampleCountSlice = frameBuffer.getSampleCountSlice();
+ if (sampleCountSlice.base == 0)
+ {
+ throw IEX_NAMESPACE::ArgExc ("Invalid base pointer, please set a proper sample count slice.");
+ }
+ else
+ {
+ _data->sampleCountSliceBase = sampleCountSlice.base;
+ _data->sampleCountXStride = sampleCountSlice.xStride;
+ _data->sampleCountYStride = sampleCountSlice.yStride;
+ }
+
+ //
+ // Initialize the slice table for readPixels().
+ //
+
+ vector<InSliceInfo*> slices;
+ ChannelList::ConstIterator i = channels.begin();
+
+ for (DeepFrameBuffer::ConstIterator j = frameBuffer.begin();
+ j != frameBuffer.end();
+ ++j)
+ {
+ while (i != channels.end() && strcmp (i.name(), j.name()) < 0)
+ {
+ //
+ // Channel i is present in the file but not
+ // in the frame buffer; data for channel i
+ // will be skipped during readPixels().
+ //
+
+ slices.push_back (new InSliceInfo (i.channel().type,
+ NULL,
+ i.channel().type,
+ 0,
+ 0,
+ 0, // sampleStride
+ i.channel().xSampling,
+ i.channel().ySampling,
+ false, // fill
+ true, // skip
+ 0.0)); // fillValue
+ ++i;
+ }
+
+ bool fill = false;
+
+ if (i == channels.end() || strcmp (i.name(), j.name()) > 0)
+ {
+ //
+ // Channel i is present in the frame buffer, but not in the file.
+ // In the frame buffer, slice j will be filled with a default value.
+ //
+
+ fill = true;
+ }
+
+ slices.push_back (new InSliceInfo (j.slice().type,
+ j.slice().base,
+ fill? j.slice().type:
+ i.channel().type,
+ j.slice().xStride,
+ j.slice().yStride,
+ j.slice().sampleStride,
+ j.slice().xSampling,
+ j.slice().ySampling,
+ fill,
+ false, // skip
+ j.slice().fillValue));
+
+
+ if (i != channels.end() && !fill)
+ ++i;
+ }
+
+ //
+ // Client may want data to be filled in multiple arrays,
+ // so we reset gotSampleCount and bytesPerLine.
+ //
+
+ for (long i = 0; i < _data->gotSampleCount.size(); i++)
+ _data->gotSampleCount[i] = false;
+ for (size_t i = 0; i < _data->bytesPerLine.size(); i++)
+ _data->bytesPerLine[i] = 0;
+
+ //
+ // Store the new frame buffer.
+ //
+
+ _data->frameBuffer = frameBuffer;
+
+ for (size_t i = 0; i < _data->slices.size(); i++)
+ delete _data->slices[i];
+ _data->slices = slices;
+ _data->frameBufferValid = true;
+}
+
+
+const DeepFrameBuffer &
+DeepScanLineInputFile::frameBuffer () const
+{
+ Lock lock (*_data->_streamData);
+ return _data->frameBuffer;
+}
+
+
+bool
+DeepScanLineInputFile::isComplete () const
+{
+ return _data->fileIsComplete;
+}
+
+
+void
+DeepScanLineInputFile::readPixels (int scanLine1, int scanLine2)
+{
+ try
+ {
+ Lock lock (*_data->_streamData);
+
+ if (_data->slices.size() == 0)
+ throw IEX_NAMESPACE::ArgExc ("No frame buffer specified "
+ "as pixel data destination.");
+
+ int scanLineMin = min (scanLine1, scanLine2);
+ int scanLineMax = max (scanLine1, scanLine2);
+
+ if (scanLineMin < _data->minY || scanLineMax > _data->maxY)
+ throw IEX_NAMESPACE::ArgExc ("Tried to read scan line outside "
+ "the image file's data window.");
+
+ for (int i = scanLineMin; i <= scanLineMax; i++)
+ {
+ if (_data->gotSampleCount[i - _data->minY] == false)
+ throw IEX_NAMESPACE::ArgExc ("Tried to read scan line without "
+ "knowing the sample counts, please"
+ "read the sample counts first.");
+ }
+
+
+ //
+ // We impose a numbering scheme on the lineBuffers where the first
+ // scanline is contained in lineBuffer 1.
+ //
+ // Determine the first and last lineBuffer numbers in this scanline
+ // range. We always attempt to read the scanlines in the order that
+ // they are stored in the file.
+ //
+
+ int start, stop, dl;
+
+ if (_data->lineOrder == INCREASING_Y)
+ {
+ start = (scanLineMin - _data->minY) / _data->linesInBuffer;
+ stop = (scanLineMax - _data->minY) / _data->linesInBuffer + 1;
+ dl = 1;
+ }
+ else
+ {
+ start = (scanLineMax - _data->minY) / _data->linesInBuffer;
+ stop = (scanLineMin - _data->minY) / _data->linesInBuffer - 1;
+ dl = -1;
+ }
+
+ //
+ // Create a task group for all line buffer tasks. When the
+ // task group goes out of scope, the destructor waits until
+ // all tasks are complete.
+ //
+
+ {
+ TaskGroup taskGroup;
+
+ //
+ // Add the line buffer tasks.
+ //
+ // The tasks will execute in the order that they are created
+ // because we lock the line buffers during construction and the
+ // constructors are called by the main thread. Hence, in order
+ // for a successive task to execute the previous task which
+ // used that line buffer must have completed already.
+ //
+
+ for (int l = start; l != stop; l += dl)
+ {
+ ThreadPool::addGlobalTask (newLineBufferTask (&taskGroup,
+ _data, l,
+ scanLineMin,
+ scanLineMax));
+ }
+
+ //
+ // finish all tasks
+ //
+ }
+
+ //
+ // Exeption handling:
+ //
+ // LineBufferTask::execute() may have encountered exceptions, but
+ // those exceptions occurred in another thread, not in the thread
+ // that is executing this call to ScanLineInputFile::readPixels().
+ // LineBufferTask::execute() has caught all exceptions and stored
+ // the exceptions' what() strings in the line buffers.
+ // Now we check if any line buffer contains a stored exception; if
+ // this is the case then we re-throw the exception in this thread.
+ // (It is possible that multiple line buffers contain stored
+ // exceptions. We re-throw the first exception we find and
+ // ignore all others.)
+ //
+
+ const string *exception = 0;
+
+ for (size_t i = 0; i < _data->lineBuffers.size(); ++i)
+ {
+ LineBuffer *lineBuffer = _data->lineBuffers[i];
+
+ if (lineBuffer->hasException && !exception)
+ exception = &lineBuffer->exception;
+
+ lineBuffer->hasException = false;
+ }
+
+ if (exception)
+ throw IEX_NAMESPACE::IoExc (*exception);
+ }
+ catch (IEX_NAMESPACE::BaseExc &e)
+ {
+ REPLACE_EXC (e, "Error reading pixel data from image "
+ "file \"" << fileName() << "\". " << e.what());
+ throw;
+ }
+}
+
+
+void
+DeepScanLineInputFile::readPixels (int scanLine)
+{
+ readPixels (scanLine, scanLine);
+}
+
+
+void
+DeepScanLineInputFile::rawPixelData (int firstScanLine,
+ char *pixelData,
+ Int64 &pixelDataSize)
+{
+
+
+ int minY = lineBufferMinY
+ (firstScanLine, _data->minY, _data->linesInBuffer);
+ int lineBufferNumber = (minY - _data->minY) / _data->linesInBuffer;
+
+ Int64 lineOffset = _data->lineOffsets[lineBufferNumber];
+
+ if (lineOffset == 0)
+ THROW (IEX_NAMESPACE::InputExc, "Scan line " << minY << " is missing.");
+
+
+ // enter the lock here - prevent another thread reseeking the file during read
+ Lock lock (*_data->_streamData);
+
+ //
+ // Seek to the start of the scan line in the file,
+ //
+
+ if (_data->_streamData->is->tellg() != _data->lineOffsets[lineBufferNumber])
+ _data->_streamData->is->seekg (lineOffset);
+
+ //
+ // Read the data block's header.
+ //
+
+ int yInFile;
+
+ //
+ // Read the part number when we are dealing with a multi-part file.
+ //
+
+ if (isMultiPart(_data->version))
+ {
+ int partNumber;
+ OPENEXR_IMF_INTERNAL_NAMESPACE::Xdr::read <OPENEXR_IMF_INTERNAL_NAMESPACE::StreamIO> (*_data->_streamData->is, partNumber);
+ if (partNumber != _data->partNumber)
+ {
+ THROW (IEX_NAMESPACE::ArgExc, "Unexpected part number " << partNumber
+ << ", should be " << _data->partNumber << ".");
+ }
+ }
+
+ OPENEXR_IMF_INTERNAL_NAMESPACE::Xdr::read <OPENEXR_IMF_INTERNAL_NAMESPACE::StreamIO> (*_data->_streamData->is, yInFile);
+
+ if (yInFile != minY)
+ throw IEX_NAMESPACE::InputExc ("Unexpected data block y coordinate.");
+
+ Int64 sampleCountTableSize;
+ Int64 packedDataSize;
+ OPENEXR_IMF_INTERNAL_NAMESPACE::Xdr::read <OPENEXR_IMF_INTERNAL_NAMESPACE::StreamIO> (*_data->_streamData->is, sampleCountTableSize);
+ OPENEXR_IMF_INTERNAL_NAMESPACE::Xdr::read <OPENEXR_IMF_INTERNAL_NAMESPACE::StreamIO> (*_data->_streamData->is, packedDataSize);
+
+ // total requirement for reading all the data
+
+ Int64 totalSizeRequired=28+sampleCountTableSize+packedDataSize;
+
+ bool big_enough = totalSizeRequired<=pixelDataSize;
+
+ pixelDataSize = totalSizeRequired;
+
+ // was the block we were given big enough?
+ if(!big_enough || pixelData==NULL)
+ {
+ // special case: seek stream back to start if we are at the beginning (regular reading pixels assumes it doesn't need to seek
+ // in single part files)
+ if(!isMultiPart(_data->version))
+ {
+ if (_data->nextLineBufferMinY == minY)
+ _data->_streamData->is->seekg (lineOffset);
+ }
+ // leave lock here - bail before reading more data
+ return;
+ }
+
+ // copy the values we have read into the output block
+ *(int *) pixelData = yInFile;
+ *(Int64 *) (pixelData+4) =sampleCountTableSize;
+ *(Int64 *) (pixelData+12) = packedDataSize;
+
+ // didn't read the unpackedsize - do that now
+ Xdr::read<StreamIO> (*_data->_streamData->is, *(Int64 *) (pixelData+20));
+
+ // read the actual data
+ _data->_streamData->is->read(pixelData+28, sampleCountTableSize+packedDataSize);
+
+ // special case: seek stream back to start if we are at the beginning (regular reading pixels assumes it doesn't need to seek
+ // in single part files)
+ if(!isMultiPart(_data->version))
+ {
+ if (_data->nextLineBufferMinY == minY)
+ _data->_streamData->is->seekg (lineOffset);
+ }
+
+ // leave lock here
+
+}
+
+void DeepScanLineInputFile::readPixels (const char* rawPixelData,
+ const DeepFrameBuffer& frameBuffer,
+ int scanLine1,
+ int scanLine2) const
+{
+ //
+ // read header from block - already converted from Xdr to native format
+ //
+ int data_scanline = *(int *) rawPixelData;
+ Int64 sampleCountTableDataSize=*(Int64 *) (rawPixelData+4);
+ Int64 packedDataSize = *(Int64 *) (rawPixelData+12);
+ Int64 unpackedDataSize = *(Int64 *) (rawPixelData+20);
+
+
+
+ //
+ // Uncompress the data, if necessary
+ //
+
+
+ Compressor * decomp = NULL;
+ const char * uncompressed_data;
+ Compressor::Format format = Compressor::XDR;
+ if(packedDataSize <unpackedDataSize)
+ {
+ decomp = newCompressor(_data->header.compression(),
+ unpackedDataSize,
+ _data->header);
+
+ decomp->uncompress(rawPixelData+28+sampleCountTableDataSize,
+ packedDataSize,
+ data_scanline, uncompressed_data);
+ format = decomp->format();
+ }
+ else
+ {
+ //
+ // If the line is uncompressed, it's in XDR format,
+ // regardless of the compressor's output format.
+ //
+
+ format = Compressor::XDR;
+ uncompressed_data = rawPixelData+28+sampleCountTableDataSize;
+ }
+
+
+ int yStart, yStop, dy;
+
+ if (_data->lineOrder == INCREASING_Y)
+ {
+ yStart = scanLine1;
+ yStop = scanLine2 + 1;
+ dy = 1;
+ }
+ else
+ {
+ yStart = scanLine2;
+ yStop = scanLine1 - 1;
+ dy = -1;
+ }
+
+
+
+ const char* samplecount_base = frameBuffer.getSampleCountSlice().base;
+ int samplecount_xstride = frameBuffer.getSampleCountSlice().xStride;
+ int samplecount_ystride = frameBuffer.getSampleCountSlice().yStride;
+
+ //
+ // For each line within the block, get the count of bytes.
+ //
+
+ int minYInLineBuffer = data_scanline;
+ int maxYInLineBuffer = min(minYInLineBuffer + _data->linesInBuffer - 1, _data->maxY);
+
+ vector<size_t> bytesPerLine(1+_data->maxY-_data->minY);
+
+
+ bytesPerDeepLineTable (_data->header,
+ minYInLineBuffer,
+ maxYInLineBuffer,
+ samplecount_base,
+ samplecount_xstride,
+ samplecount_ystride,
+ bytesPerLine);
+
+ //
+ // For each scanline within the block, get the offset.
+ //
+
+ vector<size_t> offsetInLineBuffer;
+ offsetInLineBufferTable (bytesPerLine,
+ minYInLineBuffer - _data->minY,
+ maxYInLineBuffer - _data->minY,
+ _data->linesInBuffer,
+ offsetInLineBuffer);
+
+
+ const ChannelList & channels=header().channels();
+
+
+ for (int y = yStart; y != yStop; y += dy)
+ {
+
+ const char *readPtr =uncompressed_data +
+ offsetInLineBuffer[y - _data->minY];
+
+ //
+ // need to know the total number of samples on a scanline to skip channels
+ // compute on demand: -1 means uncomputed
+ //
+ int lineSampleCount = -1;
+
+
+ //
+ // Iterate over all image channels in frame buffer
+ //
+
+
+ ChannelList::ConstIterator i = channels.begin();
+
+ for (DeepFrameBuffer::ConstIterator j = frameBuffer.begin();
+ j != frameBuffer.end();
+ ++j)
+ {
+ while (i != channels.end() && strcmp (i.name(), j.name()) < 0)
+ {
+ //
+ // Channel i is present in the file but not
+ // in the frame buffer; skip
+
+ if(lineSampleCount==-1)
+ {
+ lineSampleCount=0;
+ const char * ptr = (samplecount_base+y*samplecount_ystride + samplecount_xstride*_data->minX);
+ for(int x=_data->minX;x<=_data->maxX;x++)
+ {
+
+ lineSampleCount+=*(const unsigned int *) ptr;
+ ptr+=samplecount_xstride;
+ }
+ }
+
+ skipChannel (readPtr, i.channel().type, lineSampleCount );
+
+ ++i;
+ }
+
+ bool fill = false;
+
+ if (i == channels.end() || strcmp (i.name(), j.name()) > 0)
+ {
+ //
+ // Channel i is present in the frame buffer, but not in the file.
+ // In the frame buffer, slice j will be filled with a default value.
+ //
+
+ fill = true;
+ }
+ if (modp (y, i.channel().ySampling) == 0)
+ {
+
+ copyIntoDeepFrameBuffer (readPtr, j.slice().base,
+ samplecount_base,
+ samplecount_xstride,
+ samplecount_ystride,
+ y, _data->minX, _data->maxX,
+ 0, 0,
+ 0, 0,
+ j.slice().sampleStride,
+ j.slice().xStride,
+ j.slice().yStride,
+ fill,
+ j.slice().fillValue,
+ format,
+ j.slice().type,
+ i.channel().type);
+
+ ++i;
+
+ }
+ }//next slice in framebuffer
+ }//next row in image
+
+ //
+ // clean up
+ //
+
+ delete decomp;
+}
+
+
+
+void DeepScanLineInputFile::readPixelSampleCounts (const char* rawPixelData,
+ const DeepFrameBuffer& frameBuffer,
+ int scanLine1,
+ int scanLine2) const
+{
+ //
+ // read header from block - already converted from Xdr to native format
+ //
+ int data_scanline = *(int *) rawPixelData;
+ Int64 sampleCountTableDataSize=*(Int64 *) (rawPixelData+4);
+
+
+ int maxY;
+ maxY = min(data_scanline + _data->linesInBuffer - 1, _data->maxY);
+
+ if(scanLine1 != data_scanline)
+ {
+ THROW(IEX_NAMESPACE::ArgExc,"readPixelSampleCounts(rawPixelData,frameBuffer,"<< scanLine1 << ',' << scanLine2 << ") called with incorrect start scanline - should be " << data_scanline );
+ }
+
+ if(scanLine2 != maxY)
+ {
+ THROW(IEX_NAMESPACE::ArgExc,"readPixelSampleCounts(rawPixelData,frameBuffer,"<< scanLine1 << ',' << scanLine2 << ") called with incorrect end scanline - should be " << maxY );
+ }
+
+
+ //
+ // If the sample count table is compressed, we'll uncompress it.
+ //
+
+ Int64 rawSampleCountTableSize = (maxY - data_scanline + 1) * (_data->maxX - _data->minX + 1) *
+ Xdr::size <unsigned int> ();
+
+
+ Compressor * decomp=NULL;
+ const char* readPtr;
+ if (sampleCountTableDataSize < rawSampleCountTableSize)
+ {
+ decomp = newCompressor(_data->header.compression(),
+ rawSampleCountTableSize,
+ _data->header);
+
+ decomp->uncompress(rawPixelData+28,
+ sampleCountTableDataSize,
+ data_scanline,
+ readPtr);
+ }
+ else readPtr = rawPixelData+28;
+
+ char* base = frameBuffer.getSampleCountSlice().base;
+ int xStride = frameBuffer.getSampleCountSlice().xStride;
+ int yStride = frameBuffer.getSampleCountSlice().yStride;
+
+
+
+ for (int y = scanLine1; y <= scanLine2; y++)
+ {
+ int lastAccumulatedCount = 0;
+ for (int x = _data->minX; x <= _data->maxX; x++)
+ {
+ int accumulatedCount, count;
+
+ //
+ // Read the sample count for pixel (x, y).
+ //
+
+ Xdr::read <CharPtrIO> (readPtr, accumulatedCount);
+ if (x == _data->minX)
+ count = accumulatedCount;
+ else
+ count = accumulatedCount - lastAccumulatedCount;
+ lastAccumulatedCount = accumulatedCount;
+
+ //
+ // Store the data in both internal and external data structure.
+ //
+
+ sampleCount(base, xStride, yStride, x, y) = count;
+ }
+ }
+
+ if(decomp)
+ {
+ delete decomp;
+ }
+}
+
+
+
+namespace
+{
+
+void
+readSampleCountForLineBlock(InputStreamMutex* streamData,
+ DeepScanLineInputFile::Data* data,
+ int lineBlockId)
+{
+ streamData->is->seekg(data->lineOffsets[lineBlockId]);
+
+ if (isMultiPart(data->version))
+ {
+ int partNumber;
+ OPENEXR_IMF_INTERNAL_NAMESPACE::Xdr::read <OPENEXR_IMF_INTERNAL_NAMESPACE::StreamIO> (*streamData->is, partNumber);
+
+ if (partNumber != data->partNumber)
+ throw IEX_NAMESPACE::ArgExc("Unexpected part number.");
+ }
+
+ int minY;
+ OPENEXR_IMF_INTERNAL_NAMESPACE::Xdr::read <OPENEXR_IMF_INTERNAL_NAMESPACE::StreamIO> (*streamData->is, minY);
+
+ //
+ // Check the correctness of minY.
+ //
+
+ if (minY != data->minY + lineBlockId * data->linesInBuffer)
+ throw IEX_NAMESPACE::ArgExc("Unexpected data block y coordinate.");
+
+ int maxY;
+ maxY = min(minY + data->linesInBuffer - 1, data->maxY);
+
+ Int64 sampleCountTableDataSize;
+ OPENEXR_IMF_INTERNAL_NAMESPACE::Xdr::read <OPENEXR_IMF_INTERNAL_NAMESPACE::StreamIO> (*streamData->is, sampleCountTableDataSize);
+
+
+
+ if(sampleCountTableDataSize>data->maxSampleCountTableSize)
+ {
+ THROW (IEX_NAMESPACE::ArgExc, "Bad sampleCountTableDataSize read from chunk "<< lineBlockId << ": expected " << data->maxSampleCountTableSize << " or less, got "<< sampleCountTableDataSize);
+ }
+
+ Int64 packedDataSize;
+ Int64 unpackedDataSize;
+ OPENEXR_IMF_INTERNAL_NAMESPACE::Xdr::read <OPENEXR_IMF_INTERNAL_NAMESPACE::StreamIO> (*streamData->is, packedDataSize);
+ OPENEXR_IMF_INTERNAL_NAMESPACE::Xdr::read <OPENEXR_IMF_INTERNAL_NAMESPACE::StreamIO> (*streamData->is, unpackedDataSize);
+
+
+
+ //
+ // We make a check on the data size requirements here.
+ // Whilst we wish to store 64bit sizes on disk, not all the compressors
+ // have been made to work with such data sizes and are still limited to
+ // using signed 32 bit (int) for the data size. As such, this version
+ // insists that we validate that the data size does not exceed the data
+ // type max limit.
+ // @TODO refactor the compressor code to ensure full 64-bit support.
+ //
+
+ int compressorMaxDataSize = std::numeric_limits<int>::max();
+ if (sampleCountTableDataSize > Int64(compressorMaxDataSize))
+ {
+ THROW (IEX_NAMESPACE::ArgExc, "This version of the library does not "
+ << "support the allocation of data with size > "
+ << compressorMaxDataSize
+ << " file table size :" << sampleCountTableDataSize << ".\n");
+ }
+ streamData->is->read(data->sampleCountTableBuffer, sampleCountTableDataSize);
+
+ const char* readPtr;
+
+ //
+ // If the sample count table is compressed, we'll uncompress it.
+ //
+
+
+ if (sampleCountTableDataSize < data->maxSampleCountTableSize)
+ {
+ if(!data->sampleCountTableComp)
+ {
+ THROW(IEX_NAMESPACE::ArgExc,"Deep scanline data corrupt at chunk " << lineBlockId << " (sampleCountTableDataSize error)");
+ }
+ data->sampleCountTableComp->uncompress(data->sampleCountTableBuffer,
+ sampleCountTableDataSize,
+ minY,
+ readPtr);
+ }
+ else readPtr = data->sampleCountTableBuffer;
+
+ char* base = data->sampleCountSliceBase;
+ int xStride = data->sampleCountXStride;
+ int yStride = data->sampleCountYStride;
+
+ // total number of samples in block: used to check samplecount table doesn't
+ // reference more data than exists
+
+ size_t cumulative_total_samples=0;
+
+ for (int y = minY; y <= maxY; y++)
+ {
+ int yInDataWindow = y - data->minY;
+ data->lineSampleCount[yInDataWindow] = 0;
+
+ int lastAccumulatedCount = 0;
+ for (int x = data->minX; x <= data->maxX; x++)
+ {
+ int accumulatedCount, count;
+
+ //
+ // Read the sample count for pixel (x, y).
+ //
+
+ Xdr::read <CharPtrIO> (readPtr, accumulatedCount);
+
+ // sample count table should always contain monotonically
+ // increasing values.
+ if (accumulatedCount < lastAccumulatedCount)
+ {
+ THROW(IEX_NAMESPACE::ArgExc,"Deep scanline sampleCount data corrupt at chunk " << lineBlockId << " (negative sample count detected)");
+ }
+
+ count = accumulatedCount - lastAccumulatedCount;
+ lastAccumulatedCount = accumulatedCount;
+
+ //
+ // Store the data in both internal and external data structure.
+ //
+
+ data->sampleCount[yInDataWindow][x - data->minX] = count;
+ data->lineSampleCount[yInDataWindow] += count;
+ sampleCount(base, xStride, yStride, x, y) = count;
+ }
+ cumulative_total_samples+=data->lineSampleCount[yInDataWindow];
+ if(cumulative_total_samples*data->combinedSampleSize > unpackedDataSize)
+ {
+ THROW(IEX_NAMESPACE::ArgExc,"Deep scanline sampleCount data corrupt at chunk " << lineBlockId << ": pixel data only contains " << unpackedDataSize
+ << " bytes of data but table references at least " << cumulative_total_samples*data->combinedSampleSize << " bytes of sample data" );
+ }
+ data->gotSampleCount[y - data->minY] = true;
+ }
+}
+
+
+void
+fillSampleCountFromCache(int y, DeepScanLineInputFile::Data* data)
+{
+ int yInDataWindow = y - data->minY;
+ char* base = data->sampleCountSliceBase;
+ int xStride = data->sampleCountXStride;
+ int yStride = data->sampleCountYStride;
+
+ for (int x = data->minX; x <= data->maxX; x++)
+ {
+ unsigned int count = data->sampleCount[yInDataWindow][x - data->minX];
+ sampleCount(base, xStride, yStride, x, y) = count;
+ }
+}
+
+} // namespace
+
+void
+DeepScanLineInputFile::readPixelSampleCounts (int scanline1, int scanline2)
+{
+ Int64 savedFilePos = 0;
+
+ if(!_data->frameBufferValid)
+ {
+ throw IEX_NAMESPACE::ArgExc("readPixelSampleCounts called with no valid frame buffer");
+ }
+
+ try
+ {
+ Lock lock (*_data->_streamData);
+
+ savedFilePos = _data->_streamData->is->tellg();
+
+ int scanLineMin = min (scanline1, scanline2);
+ int scanLineMax = max (scanline1, scanline2);
+
+ if (scanLineMin < _data->minY || scanLineMax > _data->maxY)
+ throw IEX_NAMESPACE::ArgExc ("Tried to read scan line sample counts outside "
+ "the image file's data window.");
+
+ for (int i = scanLineMin; i <= scanLineMax; i++)
+ {
+ //
+ // if scanline is already read, it'll be in the cache
+ // otherwise, read from file, store in cache and in caller's framebuffer
+ //
+ if (_data->gotSampleCount[i - _data->minY])
+ {
+ fillSampleCountFromCache(i,_data);
+
+ }else{
+
+ int lineBlockId = ( i - _data->minY ) / _data->linesInBuffer;
+
+ readSampleCountForLineBlock ( _data->_streamData, _data, lineBlockId );
+
+ int minYInLineBuffer = lineBlockId * _data->linesInBuffer + _data->minY;
+ int maxYInLineBuffer = min ( minYInLineBuffer + _data->linesInBuffer - 1, _data->maxY );
+
+ //
+ // For each line within the block, get the count of bytes.
+ //
+
+ bytesPerDeepLineTable ( _data->header,
+ minYInLineBuffer,
+ maxYInLineBuffer,
+ _data->sampleCountSliceBase,
+ _data->sampleCountXStride,
+ _data->sampleCountYStride,
+ _data->bytesPerLine );
+
+ //
+ // For each scanline within the block, get the offset.
+ //
+
+ offsetInLineBufferTable ( _data->bytesPerLine,
+ minYInLineBuffer - _data->minY,
+ maxYInLineBuffer - _data->minY,
+ _data->linesInBuffer,
+ _data->offsetInLineBuffer );
+ }
+ }
+
+ _data->_streamData->is->seekg(savedFilePos);
+ }
+ catch (IEX_NAMESPACE::BaseExc &e)
+ {
+ REPLACE_EXC (e, "Error reading sample count data from image "
+ "file \"" << fileName() << "\". " << e.what());
+
+ _data->_streamData->is->seekg(savedFilePos);
+
+ throw;
+ }
+}
+
+void
+DeepScanLineInputFile::readPixelSampleCounts(int scanline)
+{
+ readPixelSampleCounts(scanline, scanline);
+}
+
+int
+DeepScanLineInputFile::firstScanLineInChunk(int y) const
+{
+ return int((y-_data->minY)/_data->linesInBuffer)*_data->linesInBuffer + _data->minY;
+}
+
+int
+DeepScanLineInputFile::lastScanLineInChunk(int y) const
+{
+ int minY = firstScanLineInChunk(y);
+ return min(minY+_data->linesInBuffer-1,_data->maxY);
+}
+
+
+OPENEXR_IMF_INTERNAL_NAMESPACE_SOURCE_EXIT
--- /dev/null
+///////////////////////////////////////////////////////////////////////////
+//
+// Copyright (c) 2011, Industrial Light & Magic, a division of Lucas
+// Digital Ltd. LLC
+//
+// All rights reserved.
+//
+// Redistribution and use in source and binary forms, with or without
+// modification, are permitted provided that the following conditions are
+// met:
+// * Redistributions of source code must retain the above copyright
+// notice, this list of conditions and the following disclaimer.
+// * Redistributions in binary form must reproduce the above
+// copyright notice, this list of conditions and the following disclaimer
+// in the documentation and/or other materials provided with the
+// distribution.
+// * Neither the name of Industrial Light & Magic nor the names of
+// its contributors may be used to endorse or promote products derived
+// from this software without specific prior written permission.
+//
+// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+//
+///////////////////////////////////////////////////////////////////////////
+
+
+#ifndef INCLUDED_IMF_DEEP_SCAN_LINE_INPUT_FILE_H
+#define INCLUDED_IMF_DEEP_SCAN_LINE_INPUT_FILE_H
+
+//-----------------------------------------------------------------------------
+//
+// class DeepScanLineInputFile
+//
+//-----------------------------------------------------------------------------
+
+#include "ImfThreading.h"
+#include "ImfGenericInputFile.h"
+#include "ImfNamespace.h"
+#include "ImfForward.h"
+#include "ImfExport.h"
+#include "ImfDeepScanLineOutputFile.h"
+
+OPENEXR_IMF_INTERNAL_NAMESPACE_HEADER_ENTER
+
+
+class DeepScanLineInputFile : public GenericInputFile
+{
+ public:
+
+ //------------
+ // Constructor
+ //------------
+
+ IMF_EXPORT
+ DeepScanLineInputFile (const char fileName[],
+ int numThreads = globalThreadCount());
+
+ IMF_EXPORT
+ DeepScanLineInputFile (const Header &header, OPENEXR_IMF_INTERNAL_NAMESPACE::IStream *is,
+ int version, /*version field from file*/
+ int numThreads = globalThreadCount());
+
+
+ //-----------------------------------------
+ // Destructor -- deallocates internal data
+ // structures, but does not close the file.
+ //-----------------------------------------
+
+ IMF_EXPORT
+ virtual ~DeepScanLineInputFile ();
+
+
+ //------------------------
+ // Access to the file name
+ //------------------------
+
+ IMF_EXPORT
+ const char * fileName () const;
+
+
+ //--------------------------
+ // Access to the file header
+ //--------------------------
+
+ IMF_EXPORT
+ const Header & header () const;
+
+
+ //----------------------------------
+ // Access to the file format version
+ //----------------------------------
+
+ IMF_EXPORT
+ int version () const;
+
+
+ //-----------------------------------------------------------
+ // Set the current frame buffer -- copies the FrameBuffer
+ // object into the InputFile object.
+ //
+ // The current frame buffer is the destination for the pixel
+ // data read from the file. The current frame buffer must be
+ // set at least once before readPixels() is called.
+ // The current frame buffer can be changed after each call
+ // to readPixels().
+ //-----------------------------------------------------------
+
+ IMF_EXPORT
+ void setFrameBuffer (const DeepFrameBuffer &frameBuffer);
+
+
+ //-----------------------------------
+ // Access to the current frame buffer
+ //-----------------------------------
+
+ IMF_EXPORT
+ const DeepFrameBuffer & frameBuffer () const;
+
+
+ //---------------------------------------------------------------
+ // Check if the file is complete:
+ //
+ // isComplete() returns true if all pixels in the data window are
+ // present in the input file, or false if any pixels are missing.
+ // (Another program may still be busy writing the file, or file
+ // writing may have been aborted prematurely.)
+ //---------------------------------------------------------------
+
+ IMF_EXPORT
+ bool isComplete () const;
+
+
+ //---------------------------------------------------------------
+ // Read pixel data:
+ //
+ // readPixels(s1,s2) reads all scan lines with y coordinates
+ // in the interval [min (s1, s2), max (s1, s2)] from the file,
+ // and stores them in the current frame buffer.
+ //
+ // Both s1 and s2 must be within the interval
+ // [header().dataWindow().min.y, header.dataWindow().max.y]
+ //
+ // The scan lines can be read from the file in random order, and
+ // individual scan lines may be skipped or read multiple times.
+ // For maximum efficiency, the scan lines should be read in the
+ // order in which they were written to the file.
+ //
+ // readPixels(s) calls readPixels(s,s).
+ //
+ // If threading is enabled, readPixels (s1, s2) tries to perform
+ // decopmression of multiple scanlines in parallel.
+ //
+ //---------------------------------------------------------------
+
+ IMF_EXPORT
+ void readPixels (int scanLine1, int scanLine2);
+ IMF_EXPORT
+ void readPixels (int scanLine);
+
+
+
+ //---------------------------------------------------------------
+ // Extract pixel data from pre-read block
+ //
+ // readPixels(rawPixelData,frameBuffer,s1,s2) reads all scan lines with y coordinates
+ // in the interval [min (s1, s2), max (s1, s2)] from the data provided and
+ // stores them in the provided frameBuffer.
+ // the data can be obtained from a call to rawPixelData()
+ //
+ //
+ // Both s1 and s2 must be within the data specified
+ //
+ // you must provide a frameBuffer with a samplecountslice, which must have been read
+ // and the data valid - readPixels uses your sample count buffer to compute
+ // offsets to the data it needs
+ //
+ // This call does not block, and is thread safe for clients with an existing
+ // threading model. The InputFile's frameBuffer is not used in this call.
+ //
+ // This call is only provided for clients which have an existing threading model in place
+ // and unpredictable access patterns to the data.
+ // The fastest way to read an entire image is to enable threading,use setFrameBuffer then
+ // readPixels(header().dataWindow().min.y, header.dataWindow().max.y)
+ //
+ //---------------------------------------------------------------
+
+ IMF_EXPORT
+ void readPixels (const char * rawPixelData,
+ const DeepFrameBuffer & frameBuffer,
+ int scanLine1,
+ int scanLine2) const;
+
+ //----------------------------------------------
+ // Read a block of raw pixel data from the file,
+ // without uncompressing it (this function is
+ // used to implement OutputFile::copyPixels()).
+ // note: returns the entire payload of the relevant chunk of data, not including part number
+ // including compressed and uncompressed sizes
+ // on entry, if pixelDataSize is insufficiently large, no bytes are read (pixelData can safely be NULL)
+ // on exit, pixelDataSize is the number of bytes required to read the chunk
+ //
+ //----------------------------------------------
+
+ IMF_EXPORT
+ void rawPixelData (int firstScanLine,
+ char * pixelData,
+ Int64 &pixelDataSize);
+
+
+ //-------------------------------------------------
+ // firstScanLineInChunk() returns the row number of the first row that's stored in the
+ // same chunk as scanline y. Depending on the compression mode, this may not be the same as y
+ //
+ // lastScanLineInChunk() returns the row number of the last row that's stored in the same
+ // chunk as scanline y. Depending on the compression mode, this may not be the same as y.
+ // The last chunk in the file may be smaller than all the others
+ //
+ //------------------------------------------------
+ IMF_EXPORT
+ int firstScanLineInChunk(int y) const;
+ IMF_EXPORT
+ int lastScanLineInChunk (int y) const;
+
+ //-----------------------------------------------------------
+ // Read pixel sample counts into a slice in the frame buffer.
+ //
+ // readPixelSampleCounts(s1, s2) reads all the counts of
+ // pixel samples with y coordinates in the interval
+ // [min (s1, s2), max (s1, s2)] from the file, and stores
+ // them in the slice naming "sample count".
+ //
+ // Both s1 and s2 must be within the interval
+ // [header().dataWindow().min.y, header.dataWindow().max.y]
+ //
+ // readPixelSampleCounts(s) calls readPixelSampleCounts(s,s).
+ //
+ //-----------------------------------------------------------
+
+ IMF_EXPORT
+ void readPixelSampleCounts (int scanline1,
+ int scanline2);
+ IMF_EXPORT
+ void readPixelSampleCounts (int scanline);
+
+
+ //----------------------------------------------------------
+ // Read pixel sample counts into the provided frameBuffer
+ // using a block read of data read by rawPixelData
+ // for multi-scanline compression schemes, you must decode the entire block
+ // so scanline1=firstScanLineInChunk(y) and scanline2=lastScanLineInChunk(y)
+ //
+ // This call does not block, and is thread safe for clients with an existing
+ // threading model. The InputFile's frameBuffer is not used in this call.
+ //
+ // The fastest way to read an entire image is to enable threading in OpenEXR, use setFrameBuffer then
+ // readPixelSampleCounts(header().dataWindow().min.y, header.dataWindow().max.y)
+ //
+ //----------------------------------------------------------
+ IMF_EXPORT
+ void readPixelSampleCounts (const char * rawdata ,
+ const DeepFrameBuffer & frameBuffer,
+ int scanLine1 ,
+ int scanLine2) const;
+
+ struct Data;
+
+ private:
+
+ Data * _data;
+
+ DeepScanLineInputFile (InputPartData* part);
+
+ void initialize(const Header& header);
+ void compatibilityInitialize(OPENEXR_IMF_INTERNAL_NAMESPACE::IStream & is);
+ void multiPartInitialize(InputPartData* part);
+
+ friend class InputFile;
+ friend class MultiPartInputFile;
+ friend void DeepScanLineOutputFile::copyPixels(DeepScanLineInputFile &);
+};
+
+
+OPENEXR_IMF_INTERNAL_NAMESPACE_HEADER_EXIT
+
+#endif
--- /dev/null
+///////////////////////////////////////////////////////////////////////////
+//
+// Copyright (c) 2004, Industrial Light & Magic, a division of Lucas
+// Digital Ltd. LLC
+//
+// All rights reserved.
+//
+// Redistribution and use in source and binary forms, with or without
+// modification, are permitted provided that the following conditions are
+// met:
+// * Redistributions of source code must retain the above copyright
+// notice, this list of conditions and the following disclaimer.
+// * Redistributions in binary form must reproduce the above
+// copyright notice, this list of conditions and the following disclaimer
+// in the documentation and/or other materials provided with the
+// distribution.
+// * Neither the name of Industrial Light & Magic nor the names of
+// its contributors may be used to endorse or promote products derived
+// from this software without specific prior written permission.
+//
+// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+//
+///////////////////////////////////////////////////////////////////////////
+
+
+#include "ImfDeepScanLineInputPart.h"
+#include "ImfNamespace.h"
+
+OPENEXR_IMF_INTERNAL_NAMESPACE_SOURCE_ENTER
+
+DeepScanLineInputPart::DeepScanLineInputPart(MultiPartInputFile& multiPartFile, int partNumber)
+{
+ file = multiPartFile.getInputPart<DeepScanLineInputFile>(partNumber);
+}
+
+
+const char *
+DeepScanLineInputPart::fileName () const
+{
+ return file->fileName();
+}
+
+
+const Header &
+DeepScanLineInputPart::header () const
+{
+ return file->header();
+}
+
+
+int
+DeepScanLineInputPart::version () const
+{
+ return file->version();
+}
+
+
+void
+DeepScanLineInputPart::setFrameBuffer (const DeepFrameBuffer &frameBuffer)
+{
+ file->setFrameBuffer(frameBuffer);
+}
+
+
+const DeepFrameBuffer &
+DeepScanLineInputPart::frameBuffer () const
+{
+ return file->frameBuffer();
+}
+
+
+bool
+DeepScanLineInputPart::isComplete () const
+{
+ return file->isComplete();
+}
+
+
+void
+DeepScanLineInputPart::readPixels (int scanLine1, int scanLine2)
+{
+ file->readPixels(scanLine1, scanLine2);
+}
+
+
+void
+DeepScanLineInputPart::readPixels (int scanLine)
+{
+ file->readPixels(scanLine);
+}
+
+
+void
+DeepScanLineInputPart::rawPixelData (int firstScanLine,
+ char *pixelData,
+ Int64 &pixelDataSize)
+{
+ file->rawPixelData(firstScanLine, pixelData, pixelDataSize);
+}
+
+
+void
+DeepScanLineInputPart::readPixelSampleCounts(int scanline1,
+ int scanline2)
+{
+ file->readPixelSampleCounts(scanline1, scanline2);
+}
+
+
+void
+DeepScanLineInputPart::readPixelSampleCounts(int scanline)
+{
+ file->readPixelSampleCounts(scanline);
+}
+
+int
+DeepScanLineInputPart::firstScanLineInChunk(int y) const
+{
+ return file->firstScanLineInChunk(y);
+}
+
+int
+DeepScanLineInputPart::lastScanLineInChunk(int y) const
+{
+ return file->lastScanLineInChunk(y);
+}
+
+void
+DeepScanLineInputPart::readPixels(const char* rawPixelData, const DeepFrameBuffer& frameBuffer, int scanLine1, int scanLine2) const
+{
+ return file->readPixels(rawPixelData,frameBuffer,scanLine1,scanLine2);
+}
+void
+DeepScanLineInputPart::readPixelSampleCounts(const char* rawdata, const DeepFrameBuffer& frameBuffer, int scanLine1, int scanLine2) const
+{
+ return file->readPixelSampleCounts(rawdata,frameBuffer,scanLine1,scanLine2);
+}
+
+OPENEXR_IMF_INTERNAL_NAMESPACE_SOURCE_EXIT
--- /dev/null
+///////////////////////////////////////////////////////////////////////////
+//
+// Copyright (c) 2011, Industrial Light & Magic, a division of Lucas
+// Digital Ltd. LLC
+//
+// All rights reserved.
+//
+// Redistribution and use in source and binary forms, with or without
+// modification, are permitted provided that the following conditions are
+// met:
+// * Redistributions of source code must retain the above copyright
+// notice, this list of conditions and the following disclaimer.
+// * Redistributions in binary form must reproduce the above
+// copyright notice, this list of conditions and the following disclaimer
+// in the documentation and/or other materials provided with the
+// distribution.
+// * Neither the name of Industrial Light & Magic nor the names of
+// its contributors may be used to endorse or promote products derived
+// from this software without specific prior written permission.
+//
+// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+//
+///////////////////////////////////////////////////////////////////////////
+
+
+#ifndef IMFDEEPSCANLINEINPUTPART_H_
+#define IMFDEEPSCANLINEINPUTPART_H_
+
+#include "ImfMultiPartInputFile.h"
+#include "ImfDeepScanLineInputFile.h"
+#include "ImfDeepScanLineOutputFile.h"
+#include "ImfNamespace.h"
+#include "ImfExport.h"
+
+OPENEXR_IMF_INTERNAL_NAMESPACE_HEADER_ENTER
+
+class DeepScanLineInputPart
+{
+ public:
+
+ IMF_EXPORT
+ DeepScanLineInputPart(MultiPartInputFile& file, int partNumber);
+
+ //------------------------
+ // Access to the file name
+ //------------------------
+
+ IMF_EXPORT
+ const char * fileName () const;
+
+
+ //--------------------------
+ // Access to the file header
+ //--------------------------
+
+ IMF_EXPORT
+ const Header & header () const;
+
+
+ //----------------------------------
+ // Access to the file format version
+ //----------------------------------
+
+ IMF_EXPORT
+ int version () const;
+
+
+ //-----------------------------------------------------------
+ // Set the current frame buffer -- copies the FrameBuffer
+ // object into the InputFile object.
+ //
+ // The current frame buffer is the destination for the pixel
+ // data read from the file. The current frame buffer must be
+ // set at least once before readPixels() is called.
+ // The current frame buffer can be changed after each call
+ // to readPixels().
+ //-----------------------------------------------------------
+
+ IMF_EXPORT
+ void setFrameBuffer (const DeepFrameBuffer &frameBuffer);
+
+
+ //-----------------------------------
+ // Access to the current frame buffer
+ //-----------------------------------
+
+ IMF_EXPORT
+ const DeepFrameBuffer & frameBuffer () const;
+
+
+ //---------------------------------------------------------------
+ // Check if the file is complete:
+ //
+ // isComplete() returns true if all pixels in the data window are
+ // present in the input file, or false if any pixels are missing.
+ // (Another program may still be busy writing the file, or file
+ // writing may have been aborted prematurely.)
+ //---------------------------------------------------------------
+
+ IMF_EXPORT
+ bool isComplete () const;
+
+
+ //---------------------------------------------------------------
+ // Read pixel data:
+ //
+ // readPixels(s1,s2) reads all scan lines with y coordinates
+ // in the interval [min (s1, s2), max (s1, s2)] from the file,
+ // and stores them in the current frame buffer.
+ //
+ // Both s1 and s2 must be within the interval
+ // [header().dataWindow().min.y, header.dataWindow().max.y]
+ //
+ // The scan lines can be read from the file in random order, and
+ // individual scan lines may be skipped or read multiple times.
+ // For maximum efficiency, the scan lines should be read in the
+ // order in which they were written to the file.
+ //
+ // readPixels(s) calls readPixels(s,s).
+ //
+ // If threading is enabled, readPixels (s1, s2) tries to perform
+ // decopmression of multiple scanlines in parallel.
+ //
+ //---------------------------------------------------------------
+
+ IMF_EXPORT
+ void readPixels (int scanLine1, int scanLine2);
+ IMF_EXPORT
+ void readPixels (int scanLine);
+ IMF_EXPORT
+ void readPixels (const char * rawPixelData,const DeepFrameBuffer & frameBuffer,
+ int scanLine1,int scanLine2) const;
+
+ //----------------------------------------------
+ // Read a block of raw pixel data from the file,
+ // without uncompressing it (this function is
+ // used to implement OutputFile::copyPixels()).
+ //----------------------------------------------
+
+ IMF_EXPORT
+ void rawPixelData (int firstScanLine,
+ char * pixelData,
+ Int64 &pixelDataSize);
+
+
+ //-----------------------------------------------------------
+ // Read pixel sample counts into a slice in the frame buffer.
+ //
+ // readPixelSampleCounts(s1, s2) reads all the counts of
+ // pixel samples with y coordinates in the interval
+ // [min (s1, s2), max (s1, s2)] from the file, and stores
+ // them in the slice naming "sample count".
+ //
+ // Both s1 and s2 must be within the interval
+ // [header().dataWindow().min.y, header.dataWindow().max.y]
+ //
+ // readPixelSampleCounts(s) calls readPixelSampleCounts(s,s).
+ //-----------------------------------------------------------
+
+ IMF_EXPORT
+ void readPixelSampleCounts(int scanline1,
+ int scanline2);
+ IMF_EXPORT
+ void readPixelSampleCounts(int scanline);
+
+ IMF_EXPORT
+ void readPixelSampleCounts( const char * rawdata , const DeepFrameBuffer & frameBuffer,
+ int scanLine1 , int scanLine2) const;
+
+ IMF_EXPORT
+ int firstScanLineInChunk(int y) const;
+ IMF_EXPORT
+ int lastScanLineInChunk (int y) const;
+ private:
+ DeepScanLineInputFile *file;
+
+ // needed for copyPixels
+ friend void DeepScanLineOutputFile::copyPixels(DeepScanLineInputPart &);
+};
+
+OPENEXR_IMF_INTERNAL_NAMESPACE_HEADER_EXIT
+
+
+
+
+
+#endif /* IMFDEEPSCANLINEINPUTPART_H_ */
--- /dev/null
+///////////////////////////////////////////////////////////////////////////
+//
+// Copyright (c) 2011, Industrial Light & Magic, a division of Lucas
+// Digital Ltd. LLC
+//
+// All rights reserved.
+//
+// Redistribution and use in source and binary forms, with or without
+// modification, are permitted provided that the following conditions are
+// met:
+// * Redistributions of source code must retain the above copyright
+// notice, this list of conditions and the following disclaimer.
+// * Redistributions in binary form must reproduce the above
+// copyright notice, this list of conditions and the following disclaimer
+// in the documentation and/or other materials provided with the
+// distribution.
+// * Neither the name of Industrial Light & Magic nor the names of
+// its contributors may be used to endorse or promote products derived
+// from this software without specific prior written permission.
+//
+// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+//
+///////////////////////////////////////////////////////////////////////////
+
+
+//-----------------------------------------------------------------------------
+//
+// class DeepScanLineOutputFile
+//
+//-----------------------------------------------------------------------------
+
+#include <ImfDeepScanLineOutputFile.h>
+#include <ImfDeepScanLineInputFile.h>
+#include <ImfDeepScanLineInputPart.h>
+#include <ImfChannelList.h>
+#include <ImfMisc.h>
+#include <ImfStdIO.h>
+#include <ImfCompressor.h>
+#include "ImathBox.h"
+#include "ImathFun.h"
+#include <ImfArray.h>
+#include <ImfXdr.h>
+#include <ImfPreviewImageAttribute.h>
+#include <ImfPartType.h>
+#include "ImfDeepFrameBuffer.h"
+#include "ImfOutputStreamMutex.h"
+#include "ImfOutputPartData.h"
+
+#include "IlmThreadPool.h"
+#include "IlmThreadSemaphore.h"
+#include "IlmThreadMutex.h"
+#include "Iex.h"
+#include <string>
+#include <vector>
+#include <fstream>
+#include <assert.h>
+#include <algorithm>
+
+#include "ImfNamespace.h"
+
+OPENEXR_IMF_INTERNAL_NAMESPACE_SOURCE_ENTER
+
+using IMATH_NAMESPACE::Box2i;
+using IMATH_NAMESPACE::divp;
+using IMATH_NAMESPACE::modp;
+using std::string;
+using std::vector;
+using std::ofstream;
+using std::min;
+using std::max;
+using ILMTHREAD_NAMESPACE::Mutex;
+using ILMTHREAD_NAMESPACE::Lock;
+using ILMTHREAD_NAMESPACE::Semaphore;
+using ILMTHREAD_NAMESPACE::Task;
+using ILMTHREAD_NAMESPACE::TaskGroup;
+using ILMTHREAD_NAMESPACE::ThreadPool;
+
+namespace {
+
+
+struct OutSliceInfo
+{
+ PixelType type;
+ const char * base;
+ ptrdiff_t sampleStride;
+ ptrdiff_t xStride;
+ ptrdiff_t yStride;
+ int xSampling;
+ int ySampling;
+ bool zero;
+
+ OutSliceInfo (PixelType type = HALF,
+ const char * base =NULL,
+ ptrdiff_t sampleStride = 0,
+ ptrdiff_t xStride = 0,
+ ptrdiff_t yStride =0,
+ int xSampling = 1,
+ int ySampling = 1,
+ bool zero = false);
+};
+
+
+OutSliceInfo::OutSliceInfo (PixelType t,
+ const char * base,
+ ptrdiff_t spstride,
+ ptrdiff_t xst,
+ ptrdiff_t yst,
+ int xsm, int ysm,
+ bool z)
+:
+ type (t),
+ base (base),
+ sampleStride (spstride),
+ xStride(xst),
+ yStride(yst),
+ xSampling (xsm),
+ ySampling (ysm),
+ zero (z)
+{
+ // empty
+}
+
+
+struct LineBuffer
+{
+ Array< Array<char> > buffer;
+ Array<char> consecutiveBuffer;
+ const char * dataPtr;
+ Int64 uncompressedDataSize;
+ Int64 dataSize;
+ Array<char> sampleCountTableBuffer;
+ const char * sampleCountTablePtr;
+ Int64 sampleCountTableSize;
+ Compressor* sampleCountTableCompressor;
+ int minY; // the min y scanline stored
+ int maxY; // the max y scanline stored
+ int scanLineMin; // the min y scanline writing out
+ int scanLineMax; // the max y scanline writing out
+ Compressor * compressor;
+ bool partiallyFull; // has incomplete data
+ bool hasException;
+ string exception;
+
+ LineBuffer (int linesInBuffer);
+ ~LineBuffer ();
+
+ void wait () {_sem.wait();}
+ void post () {_sem.post();}
+
+ private:
+
+ Semaphore _sem;
+};
+
+
+LineBuffer::LineBuffer (int linesInBuffer) :
+ dataPtr (0),
+ dataSize (0),
+ sampleCountTablePtr (0),
+ sampleCountTableCompressor (0),
+ compressor (0),
+ partiallyFull (false),
+ hasException (false),
+ exception (),
+ _sem (1)
+{
+ buffer.resizeErase(linesInBuffer);
+}
+
+
+LineBuffer::~LineBuffer ()
+{
+ if (compressor != 0)
+ delete compressor;
+
+ if (sampleCountTableCompressor != 0)
+ delete sampleCountTableCompressor;
+}
+
+} // namespace
+
+
+struct DeepScanLineOutputFile::Data
+{
+ Header header; // the image header
+ int version; // file format version
+ bool multipart; // from a multipart file
+ Int64 previewPosition; // file position for preview
+ DeepFrameBuffer frameBuffer; // framebuffer to write into
+ int currentScanLine; // next scanline to be written
+ int missingScanLines; // number of lines to write
+ LineOrder lineOrder; // the file's lineorder
+ int minX; // data window's min x coord
+ int maxX; // data window's max x coord
+ int minY; // data window's min y coord
+ int maxY; // data window's max x coord
+ vector<Int64> lineOffsets; // stores offsets in file for
+ // each scanline
+ vector<size_t> bytesPerLine; // combined size of a line over
+ // all channels
+ Compressor::Format format; // compressor's data format
+ vector<OutSliceInfo*> slices; // info about channels in file
+ Int64 lineOffsetsPosition; // file position for line
+ // offset table
+
+ vector<LineBuffer*> lineBuffers; // each holds one line buffer
+ int linesInBuffer; // number of scanlines each
+ // buffer holds
+ int partNumber; // the output part number
+
+ char* sampleCountSliceBase; // the pointer to the number
+ // of samples in each pixel
+ int sampleCountXStride; // the x stride for sampleCountSliceBase
+ int sampleCountYStride; // the y stride for sampleCountSliceBase
+
+ Array<unsigned int> lineSampleCount; // the number of samples
+ // in each line
+
+ Int64 maxSampleCountTableSize;
+ // the max size in bytes for a pixel
+ // sample count table
+ OutputStreamMutex* _streamData;
+ bool _deleteStream;
+
+ Data (int numThreads);
+ ~Data ();
+
+
+ inline LineBuffer * getLineBuffer (int number);// hash function from line
+ // buffer indices into our
+ // vector of line buffers
+
+ inline int& getSampleCount(int x, int y); // get the number of samples
+ // in each pixel
+};
+
+
+DeepScanLineOutputFile::Data::Data (int numThreads):
+ lineOffsetsPosition (0),
+ partNumber (-1) ,
+ _streamData(NULL),
+ _deleteStream(false)
+{
+ //
+ // We need at least one lineBuffer, but if threading is used,
+ // to keep n threads busy we need 2*n lineBuffers.
+ //
+
+ lineBuffers.resize (max (1, 2 * numThreads));
+ for (size_t i = 0; i < lineBuffers.size(); i++)
+ lineBuffers[i] = 0;
+}
+
+
+DeepScanLineOutputFile::Data::~Data ()
+{
+ for (size_t i = 0; i < lineBuffers.size(); i++)
+ if (lineBuffers[i] != 0)
+ delete lineBuffers[i];
+
+ for (size_t i = 0; i < slices.size(); i++)
+ delete slices[i];
+}
+
+
+int&
+DeepScanLineOutputFile::Data::getSampleCount(int x, int y)
+{
+ return sampleCount(sampleCountSliceBase,
+ sampleCountXStride,
+ sampleCountYStride,
+ x, y);
+}
+
+
+LineBuffer*
+DeepScanLineOutputFile::Data::getLineBuffer (int number)
+{
+ return lineBuffers[number % lineBuffers.size()];
+}
+
+
+namespace {
+
+Int64
+writeLineOffsets (OPENEXR_IMF_INTERNAL_NAMESPACE::OStream &os, const vector<Int64> &lineOffsets)
+{
+ Int64 pos = os.tellp();
+
+ if (pos == -1)
+ IEX_NAMESPACE::throwErrnoExc ("Cannot determine current file position (%T).");
+
+ for (unsigned int i = 0; i < lineOffsets.size(); i++)
+ OPENEXR_IMF_INTERNAL_NAMESPACE::Xdr::write <OPENEXR_IMF_INTERNAL_NAMESPACE::StreamIO> (os, lineOffsets[i]);
+
+ return pos;
+}
+
+
+void
+writePixelData (OutputStreamMutex *filedata,
+ DeepScanLineOutputFile::Data *partdata,
+ int lineBufferMinY,
+ const char pixelData[],
+ Int64 packedDataSize,
+ Int64 unpackedDataSize,
+ const char sampleCountTableData[],
+ Int64 sampleCountTableSize)
+{
+ //
+ // Store a block of pixel data in the output file, and try
+ // to keep track of the current writing position the file
+ // without calling tellp() (tellp() can be fairly expensive).
+ //
+
+ Int64 currentPosition = filedata->currentPosition;
+ filedata->currentPosition = 0;
+
+ if (currentPosition == 0)
+ currentPosition = filedata->os->tellp();
+
+ partdata->lineOffsets[(partdata->currentScanLine - partdata->minY) / partdata->linesInBuffer] =
+ currentPosition;
+
+ #ifdef DEBUG
+
+ assert (filedata->os->tellp() == currentPosition);
+
+ #endif
+
+ //
+ // Write the optional part number.
+ //
+
+ if (partdata->multipart)
+ {
+ OPENEXR_IMF_INTERNAL_NAMESPACE::Xdr::write <OPENEXR_IMF_INTERNAL_NAMESPACE::StreamIO> (*filedata->os, partdata->partNumber);
+ }
+
+ //
+ // Write the y coordinate of the first scanline in the chunk.
+ //
+
+ OPENEXR_IMF_INTERNAL_NAMESPACE::Xdr::write <OPENEXR_IMF_INTERNAL_NAMESPACE::StreamIO> (*filedata->os, lineBufferMinY);
+
+ //
+ // Write the packed size of the pixel sample count table.
+ //
+
+ OPENEXR_IMF_INTERNAL_NAMESPACE::Xdr::write <OPENEXR_IMF_INTERNAL_NAMESPACE::StreamIO> (*filedata->os, sampleCountTableSize);
+
+ //
+ // Write the packed pixel data size.
+ //
+
+ OPENEXR_IMF_INTERNAL_NAMESPACE::Xdr::write <OPENEXR_IMF_INTERNAL_NAMESPACE::StreamIO> (*filedata->os, packedDataSize);
+
+ //
+ // Write the unpacked pixel data size.
+ //
+
+ OPENEXR_IMF_INTERNAL_NAMESPACE::Xdr::write <OPENEXR_IMF_INTERNAL_NAMESPACE::StreamIO> (*filedata->os, unpackedDataSize);
+
+ //
+ // Write the packed pixel sample count table.
+ //
+
+ filedata->os->write (sampleCountTableData, sampleCountTableSize);
+
+ //
+ // Write the compressed data.
+ //
+
+ filedata->os->write (pixelData, packedDataSize);
+
+ //
+ // Update stream position.
+ //
+
+ filedata->currentPosition = currentPosition +
+ Xdr::size<int>() + // y coordinate
+ Xdr::size<Int64>() + // packed sample count table size
+ Xdr::size<Int64>() + // packed data size
+ Xdr::size<Int64>() + // unpacked data size
+ sampleCountTableSize + // pixel sample count table
+ packedDataSize; // pixel data
+
+ if (partdata->multipart)
+ {
+ filedata->currentPosition += Xdr::size<int>(); // optional part number
+ }
+}
+
+
+inline void
+writePixelData (OutputStreamMutex* filedata,
+ DeepScanLineOutputFile::Data *partdata,
+ const LineBuffer *lineBuffer)
+{
+ writePixelData (filedata, partdata,
+ lineBuffer->minY,
+ lineBuffer->dataPtr,
+ lineBuffer->dataSize,
+ lineBuffer->uncompressedDataSize,
+ lineBuffer->sampleCountTablePtr,
+ lineBuffer->sampleCountTableSize);
+}
+
+
+void
+convertToXdr (DeepScanLineOutputFile::Data *ofd,
+ Array<char> &lineBuffer,
+ int lineBufferMinY,
+ int lineBufferMaxY,
+ int inSize)
+{
+ //
+ // Convert the contents of a lineBuffer from the machine's native
+ // representation to Xdr format. This function is called by
+ // CompressLineBuffer::execute(), below, if the compressor wanted
+ // its input pixel data in the machine's native format, but then
+ // failed to compress the data (most compressors will expand rather
+ // than compress random input data).
+ //
+ // Note that this routine assumes that the machine's native
+ // representation of the pixel data has the same size as the
+ // Xdr representation. This makes it possible to convert the
+ // pixel data in place, without an intermediate temporary buffer.
+ //
+
+ //
+ // Iterate over all scanlines in the lineBuffer to convert.
+ //
+
+ char* writePtr = &lineBuffer[0];
+ for (int y = lineBufferMinY; y <= lineBufferMaxY; y++)
+ {
+ //
+ // Set these to point to the start of line y.
+ // We will write to writePtr from readPtr.
+ //
+
+ const char *readPtr = writePtr;
+
+ //
+ // Iterate over all slices in the file.
+ //
+
+ for (unsigned int i = 0; i < ofd->slices.size(); ++i)
+ {
+ //
+ // Test if scan line y of this channel is
+ // contains any data (the scan line contains
+ // data only if y % ySampling == 0).
+ //
+
+ const OutSliceInfo &slice = *ofd->slices[i];
+
+ if (modp (y, slice.ySampling) != 0)
+ continue;
+
+ //
+ // Find the number of sampled pixels, dMaxX-dMinX+1, for
+ // slice i in scan line y (i.e. pixels within the data window
+ // for which x % xSampling == 0).
+ //
+
+ int xSampleCount = ofd->lineSampleCount[y - ofd->minY];
+
+ //
+ // Convert the samples in place.
+ //
+
+ convertInPlace (writePtr, readPtr, slice.type, xSampleCount);
+ }
+ }
+}
+
+
+//
+// A LineBufferTask encapsulates the task of copying a set of scanlines
+// from the user's frame buffer into a LineBuffer object, compressing
+// the data if necessary.
+//
+
+class LineBufferTask: public Task
+{
+ public:
+
+ LineBufferTask (TaskGroup *group,
+ DeepScanLineOutputFile::Data *ofd,
+ int number,
+ int scanLineMin,
+ int scanLineMax);
+
+ virtual ~LineBufferTask ();
+
+ virtual void execute ();
+
+ private:
+
+ DeepScanLineOutputFile::Data * _ofd;
+ LineBuffer * _lineBuffer;
+};
+
+
+LineBufferTask::LineBufferTask
+ (TaskGroup *group,
+ DeepScanLineOutputFile::Data *ofd,
+ int number,
+ int scanLineMin,
+ int scanLineMax)
+:
+ Task (group),
+ _ofd (ofd),
+ _lineBuffer (_ofd->getLineBuffer(number))
+{
+ //
+ // Wait for the lineBuffer to become available
+ //
+
+ _lineBuffer->wait ();
+
+ //
+ // Initialize the lineBuffer data if necessary
+ //
+
+ if (!_lineBuffer->partiallyFull)
+ {
+
+ _lineBuffer->minY = _ofd->minY + number * _ofd->linesInBuffer;
+
+ _lineBuffer->maxY = min (_lineBuffer->minY + _ofd->linesInBuffer - 1,
+ _ofd->maxY);
+
+ _lineBuffer->partiallyFull = true;
+ }
+
+ _lineBuffer->scanLineMin = max (_lineBuffer->minY, scanLineMin);
+ _lineBuffer->scanLineMax = min (_lineBuffer->maxY, scanLineMax);
+}
+
+
+LineBufferTask::~LineBufferTask ()
+{
+ //
+ // Signal that the line buffer is now free
+ //
+
+ _lineBuffer->post ();
+}
+
+
+void
+LineBufferTask::execute ()
+{
+ try
+ {
+ //
+ // First copy the pixel data from the
+ // frame buffer into the line buffer
+ //
+
+ int yStart, yStop, dy;
+
+ if (_ofd->lineOrder == INCREASING_Y)
+ {
+ yStart = _lineBuffer->scanLineMin;
+ yStop = _lineBuffer->scanLineMax + 1;
+ dy = 1;
+ }
+ else
+ {
+ yStart = _lineBuffer->scanLineMax;
+ yStop = _lineBuffer->scanLineMin - 1;
+ dy = -1;
+ }
+
+ //
+ // Allocate buffers for scanlines.
+ // And calculate the sample counts for each line.
+ //
+
+ bytesPerDeepLineTable (_ofd->header,
+ _lineBuffer->scanLineMin,
+ _lineBuffer->scanLineMax,
+ _ofd->sampleCountSliceBase,
+ _ofd->sampleCountXStride,
+ _ofd->sampleCountYStride,
+ _ofd->bytesPerLine);
+ for (int i = _lineBuffer->scanLineMin; i <= _lineBuffer->scanLineMax; i++)
+ {
+ // (TODO) don't do this all the time.
+ _lineBuffer->buffer[i - _lineBuffer->minY].resizeErase(
+ _ofd->bytesPerLine[i - _ofd->minY]);
+
+ for (int j = _ofd->minX; j <= _ofd->maxX; j++)
+ _ofd->lineSampleCount[i - _ofd->minY] += _ofd->getSampleCount(j, i);
+ }
+
+ //
+ // Copy data from frame buffer to line buffer.
+ //
+
+ int y;
+
+ for (y = yStart; y != yStop; y += dy)
+ {
+ //
+ // Gather one scan line's worth of pixel data and store
+ // them in _ofd->lineBuffer.
+ //
+
+ char *writePtr = &_lineBuffer->buffer[y - _lineBuffer->minY][0];
+ //
+ // Iterate over all image channels.
+ //
+
+ for (unsigned int i = 0; i < _ofd->slices.size(); ++i)
+ {
+ //
+ // Test if scan line y of this channel contains any data
+ // (the scan line contains data only if y % ySampling == 0).
+ //
+
+ const OutSliceInfo &slice = *_ofd->slices[i];
+
+ if (modp (y, slice.ySampling) != 0)
+ continue;
+
+ //
+ // Fill the line buffer with with pixel data.
+ //
+
+ if (slice.zero)
+ {
+ //
+ // The frame buffer contains no data for this channel.
+ // Store zeroes in _lineBuffer->buffer.
+ //
+
+ fillChannelWithZeroes (writePtr, _ofd->format, slice.type,
+ _ofd->lineSampleCount[y - _ofd->minY]);
+ }
+ else
+ {
+
+ copyFromDeepFrameBuffer (writePtr, slice.base,
+ _ofd->sampleCountSliceBase,
+ _ofd->sampleCountXStride,
+ _ofd->sampleCountYStride,
+ y, _ofd->minX, _ofd->maxX,
+ 0, 0,//offsets for samplecount
+ 0, 0,//offsets for data
+ slice.sampleStride,
+ slice.xStride,
+ slice.yStride,
+ _ofd->format,
+ slice.type);
+ }
+ }
+ }
+
+ //
+ // If the next scanline isn't past the bounds of the lineBuffer
+ // then we have partially filled the linebuffer,
+ // otherwise the whole linebuffer is filled and then
+ // we compress the linebuffer and write it out.
+ //
+
+ if (y >= _lineBuffer->minY && y <= _lineBuffer->maxY)
+ return;
+
+ //
+ // Copy all data into a consecutive buffer.
+ //
+
+ Int64 totalBytes = 0;
+ Int64 maxBytesPerLine = 0;
+ for (int i = 0; i < _lineBuffer->maxY - _lineBuffer->minY + 1; i++)
+ {
+ totalBytes += _lineBuffer->buffer[i].size();
+ if (Int64(_lineBuffer->buffer[i].size()) > maxBytesPerLine)
+ maxBytesPerLine = _lineBuffer->buffer[i].size();
+ }
+ _lineBuffer->consecutiveBuffer.resizeErase(totalBytes);
+
+ int pos = 0;
+ for (int i = 0; i < _lineBuffer->maxY - _lineBuffer->minY + 1; i++)
+ {
+ memcpy(_lineBuffer->consecutiveBuffer + pos,
+ &_lineBuffer->buffer[i][0],
+ _lineBuffer->buffer[i].size());
+ pos += _lineBuffer->buffer[i].size();
+ }
+
+ _lineBuffer->dataPtr = _lineBuffer->consecutiveBuffer;
+
+ _lineBuffer->dataSize = totalBytes;
+ _lineBuffer->uncompressedDataSize = _lineBuffer->dataSize;
+
+ //
+ // Compress the pixel sample count table.
+ //
+
+ char* ptr = _lineBuffer->sampleCountTableBuffer;
+ Int64 tableDataSize = 0;
+ for (int i = _lineBuffer->minY; i <= _lineBuffer->maxY; i++)
+ {
+ int count = 0;
+ for (int j = _ofd->minX; j <= _ofd->maxX; j++)
+ {
+ count += _ofd->getSampleCount(j, i);
+ Xdr::write <CharPtrIO> (ptr, count);
+ tableDataSize += sizeof (int);
+ }
+ }
+
+ if(_lineBuffer->sampleCountTableCompressor)
+ {
+ _lineBuffer->sampleCountTableSize =
+ _lineBuffer->sampleCountTableCompressor->compress (
+ _lineBuffer->sampleCountTableBuffer,
+ tableDataSize,
+ _lineBuffer->minY,
+ _lineBuffer->sampleCountTablePtr);
+ }
+
+ //
+ // If we can't make data shrink (or we weren't compressing), then just use the raw data.
+ //
+
+ if (!_lineBuffer->sampleCountTableCompressor ||
+ _lineBuffer->sampleCountTableSize >= tableDataSize)
+ {
+ _lineBuffer->sampleCountTableSize = tableDataSize;
+ _lineBuffer->sampleCountTablePtr = _lineBuffer->sampleCountTableBuffer;
+ }
+
+ //
+ // Compress the sample data
+ //
+
+ // (TODO) don't do this all the time.
+ if (_lineBuffer->compressor != 0)
+ delete _lineBuffer->compressor;
+ _lineBuffer->compressor = newCompressor (_ofd->header.compression(),
+ maxBytesPerLine,
+ _ofd->header);
+
+ Compressor *compressor = _lineBuffer->compressor;
+
+ if (compressor)
+ {
+ const char *compPtr;
+
+ Int64 compSize = compressor->compress (_lineBuffer->dataPtr,
+ _lineBuffer->dataSize,
+ _lineBuffer->minY, compPtr);
+
+ if (compSize < _lineBuffer->dataSize)
+ {
+ _lineBuffer->dataSize = compSize;
+ _lineBuffer->dataPtr = compPtr;
+ }
+ else if (_ofd->format == Compressor::NATIVE)
+ {
+ //
+ // The data did not shrink during compression, but
+ // we cannot write to the file using the machine's
+ // native format, so we need to convert the lineBuffer
+ // to Xdr.
+ //
+
+ convertToXdr (_ofd, _lineBuffer->consecutiveBuffer, _lineBuffer->minY,
+ _lineBuffer->maxY, _lineBuffer->dataSize);
+ }
+ }
+
+ _lineBuffer->partiallyFull = false;
+ }
+ catch (std::exception &e)
+ {
+ if (!_lineBuffer->hasException)
+ {
+ _lineBuffer->exception = e.what ();
+ _lineBuffer->hasException = true;
+ }
+ }
+ catch (...)
+ {
+ if (!_lineBuffer->hasException)
+ {
+ _lineBuffer->exception = "unrecognized exception";
+ _lineBuffer->hasException = true;
+ }
+ }
+}
+
+} // namespace
+
+
+DeepScanLineOutputFile::DeepScanLineOutputFile
+ (const char fileName[],
+ const Header &header,
+ int numThreads)
+:
+ _data (new Data (numThreads))
+{
+ _data->_streamData=new OutputStreamMutex ();
+ _data->_deleteStream=true;
+ try
+ {
+ header.sanityCheck();
+ _data->_streamData->os = new StdOFStream (fileName);
+ initialize (header);
+ _data->_streamData->currentPosition = _data->_streamData->os->tellp();
+
+ // Write header and empty offset table to the file.
+ writeMagicNumberAndVersionField(*_data->_streamData->os, _data->header);
+ _data->previewPosition =
+ _data->header.writeTo (*_data->_streamData->os);
+ _data->lineOffsetsPosition =
+ writeLineOffsets (*_data->_streamData->os, _data->lineOffsets);
+ _data->multipart=false;// not multipart; only one header
+ }
+ catch (IEX_NAMESPACE::BaseExc &e)
+ {
+ delete _data->_streamData->os;
+ delete _data->_streamData;
+ delete _data;
+
+ REPLACE_EXC (e, "Cannot open image file "
+ "\"" << fileName << "\". " << e.what());
+ throw;
+ }
+ catch (...)
+ {
+ delete _data->_streamData->os;
+ delete _data->_streamData;
+ delete _data;
+ throw;
+ }
+}
+
+
+DeepScanLineOutputFile::DeepScanLineOutputFile
+ (OPENEXR_IMF_INTERNAL_NAMESPACE::OStream &os,
+ const Header &header,
+ int numThreads)
+:
+ _data (new Data (numThreads))
+
+{
+ _data->_streamData = new OutputStreamMutex ();
+ _data->_deleteStream = false;
+ try
+ {
+ header.sanityCheck();
+ _data->_streamData->os = &os;
+ initialize (header);
+ _data->_streamData->currentPosition = _data->_streamData->os->tellp();
+
+ // Write header and empty offset table to the file.
+ writeMagicNumberAndVersionField(*_data->_streamData->os, _data->header);
+ _data->previewPosition =
+ _data->header.writeTo (*_data->_streamData->os);
+ _data->lineOffsetsPosition =
+ writeLineOffsets (*_data->_streamData->os, _data->lineOffsets);
+ _data->multipart=false;
+ }
+ catch (IEX_NAMESPACE::BaseExc &e)
+ {
+ delete _data->_streamData;
+ delete _data;
+
+ REPLACE_EXC (e, "Cannot open image file "
+ "\"" << os.fileName() << "\". " << e.what());
+ throw;
+ }
+ catch (...)
+ {
+ delete _data->_streamData;
+ delete _data;
+ throw;
+ }
+}
+
+DeepScanLineOutputFile::DeepScanLineOutputFile(const OutputPartData* part)
+{
+ try
+ {
+ if (part->header.type() != DEEPSCANLINE)
+ throw IEX_NAMESPACE::ArgExc("Can't build a DeepScanLineOutputFile from a type-mismatched part.");
+
+ _data = new Data (part->numThreads);
+ _data->_streamData = part->mutex;
+ _data->_deleteStream=false;
+ initialize (part->header);
+ _data->partNumber = part->partNumber;
+ _data->lineOffsetsPosition = part->chunkOffsetTablePosition;
+ _data->previewPosition = part->previewPosition;
+ _data->multipart=part->multipart;
+ }
+ catch (IEX_NAMESPACE::BaseExc &e)
+ {
+ delete _data;
+
+ REPLACE_EXC (e, "Cannot initialize output part "
+ "\"" << part->partNumber << "\". " << e.what());
+ throw;
+ }
+ catch (...)
+ {
+ delete _data;
+ throw;
+ }
+}
+
+void
+DeepScanLineOutputFile::initialize (const Header &header)
+{
+ _data->header = header;
+
+ _data->header.setType(DEEPSCANLINE);
+
+ const Box2i &dataWindow = header.dataWindow();
+
+ _data->currentScanLine = (header.lineOrder() == INCREASING_Y)?
+ dataWindow.min.y: dataWindow.max.y;
+
+ _data->missingScanLines = dataWindow.max.y - dataWindow.min.y + 1;
+ _data->lineOrder = header.lineOrder();
+ _data->minX = dataWindow.min.x;
+ _data->maxX = dataWindow.max.x;
+ _data->minY = dataWindow.min.y;
+ _data->maxY = dataWindow.max.y;
+
+ _data->lineSampleCount.resizeErase(_data->maxY - _data->minY + 1);
+
+ Compressor* compressor = newCompressor (_data->header.compression(),
+ 0,
+ _data->header);
+ _data->format = defaultFormat (compressor);
+ _data->linesInBuffer = numLinesInBuffer (compressor);
+ if (compressor != 0)
+ delete compressor;
+
+ int lineOffsetSize = (_data->maxY - _data->minY +
+ _data->linesInBuffer) / _data->linesInBuffer;
+
+
+ _data->header.setChunkCount(lineOffsetSize);
+
+ _data->lineOffsets.resize (lineOffsetSize);
+
+ _data->bytesPerLine.resize (_data->maxY - _data->minY + 1);
+
+ _data->maxSampleCountTableSize = min(_data->linesInBuffer, _data->maxY - _data->minY + 1) *
+ (_data->maxX - _data->minX + 1) *
+ sizeof(unsigned int);
+
+ for (size_t i = 0; i < _data->lineBuffers.size(); ++i)
+ {
+ _data->lineBuffers[i] = new LineBuffer (_data->linesInBuffer);
+ _data->lineBuffers[i]->sampleCountTableBuffer.resizeErase(_data->maxSampleCountTableSize);
+
+ _data->lineBuffers[i]->sampleCountTableCompressor =
+ newCompressor (_data->header.compression(),
+ _data->maxSampleCountTableSize,
+ _data->header);
+ }
+}
+
+
+DeepScanLineOutputFile::~DeepScanLineOutputFile ()
+{
+ {
+ Lock lock(*_data->_streamData);
+ Int64 originalPosition = _data->_streamData->os->tellp();
+
+ if (_data->lineOffsetsPosition > 0)
+ {
+ try
+ {
+ _data->_streamData->os->seekp (_data->lineOffsetsPosition);
+ writeLineOffsets (*_data->_streamData->os, _data->lineOffsets);
+
+ //
+ // Restore the original position.
+ //
+ _data->_streamData->os->seekp (originalPosition);
+ }
+ catch (...)
+ {
+ //
+ // We cannot safely throw any exceptions from here.
+ // This destructor may have been called because the
+ // stack is currently being unwound for another
+ // exception.
+ //
+ }
+ }
+ }
+
+ if (_data->_deleteStream)
+ delete _data->_streamData->os;
+
+ //
+ // (TODO) we should have a way to tell if the stream data is owned by this file or
+ // by a parent multipart file.
+ //
+
+ if (_data->partNumber == -1)
+ delete _data->_streamData;
+
+ delete _data;
+}
+
+
+const char *
+DeepScanLineOutputFile::fileName () const
+{
+ return _data->_streamData->os->fileName();
+}
+
+
+const Header &
+DeepScanLineOutputFile::header () const
+{
+ return _data->header;
+}
+
+
+void
+DeepScanLineOutputFile::setFrameBuffer (const DeepFrameBuffer &frameBuffer)
+{
+ Lock lock (*_data->_streamData);
+
+ //
+ // Check if the new frame buffer descriptor
+ // is compatible with the image file header.
+ //
+
+ const ChannelList &channels = _data->header.channels();
+
+ for (ChannelList::ConstIterator i = channels.begin();
+ i != channels.end();
+ ++i)
+ {
+ DeepFrameBuffer::ConstIterator j = frameBuffer.find (i.name());
+
+ if (j == frameBuffer.end())
+ continue;
+
+ if (i.channel().type != j.slice().type)
+ {
+ THROW (IEX_NAMESPACE::ArgExc, "Pixel type of \"" << i.name() << "\" channel "
+ "of output file \"" << fileName() << "\" is "
+ "not compatible with the frame buffer's "
+ "pixel type.");
+ }
+
+ if (i.channel().xSampling != j.slice().xSampling ||
+ i.channel().ySampling != j.slice().ySampling)
+ {
+ THROW (IEX_NAMESPACE::ArgExc, "X and/or y subsampling factors "
+ "of \"" << i.name() << "\" channel "
+ "of output file \"" << fileName() << "\" are "
+ "not compatible with the frame buffer's "
+ "subsampling factors.");
+ }
+ }
+
+ //
+ // Store the pixel sample count table.
+ // (TODO) Support for different sampling rates?
+ //
+
+ const Slice& sampleCountSlice = frameBuffer.getSampleCountSlice();
+ if (sampleCountSlice.base == 0)
+ {
+ throw IEX_NAMESPACE::ArgExc ("Invalid base pointer, please set a proper sample count slice.");
+ }
+ else
+ {
+ _data->sampleCountSliceBase = sampleCountSlice.base;
+ _data->sampleCountXStride = sampleCountSlice.xStride;
+ _data->sampleCountYStride = sampleCountSlice.yStride;
+ }
+
+ //
+ // Initialize slice table for writePixels().
+ // Pixel sample count slice is not presented in the header,
+ // so it wouldn't be added here.
+ // Store the pixel base pointer table.
+ // (TODO) Support for different sampling rates?
+ //
+
+ vector<OutSliceInfo*> slices;
+
+ for (ChannelList::ConstIterator i = channels.begin();
+ i != channels.end();
+ ++i)
+ {
+ DeepFrameBuffer::ConstIterator j = frameBuffer.find (i.name());
+
+ if (j == frameBuffer.end())
+ {
+ //
+ // Channel i is not present in the frame buffer.
+ // In the file, channel i will contain only zeroes.
+ //
+
+ slices.push_back (new OutSliceInfo (i.channel().type,
+ NULL,// base
+ 0,// sampleStride,
+ 0,// xStride
+ 0,// yStride
+ i.channel().xSampling,
+ i.channel().ySampling,
+ true)); // zero
+ }
+ else
+ {
+ //
+ // Channel i is present in the frame buffer.
+ //
+
+ slices.push_back (new OutSliceInfo (j.slice().type,
+ j.slice().base,
+ j.slice().sampleStride,
+ j.slice().xStride,
+ j.slice().yStride,
+ j.slice().xSampling,
+ j.slice().ySampling,
+ false)); // zero
+
+ }
+ }
+
+ //
+ // Store the new frame buffer.
+ //
+
+ _data->frameBuffer = frameBuffer;
+
+ for (size_t i = 0; i < _data->slices.size(); i++)
+ delete _data->slices[i];
+ _data->slices = slices;
+}
+
+
+const DeepFrameBuffer &
+DeepScanLineOutputFile::frameBuffer () const
+{
+ Lock lock (*_data->_streamData);
+ return _data->frameBuffer;
+}
+
+
+void
+DeepScanLineOutputFile::writePixels (int numScanLines)
+{
+ try
+ {
+ Lock lock (*_data->_streamData);
+
+ if (_data->slices.size() == 0)
+ throw IEX_NAMESPACE::ArgExc ("No frame buffer specified "
+ "as pixel data source.");
+
+ //
+ // Maintain two iterators:
+ // nextWriteBuffer: next linebuffer to be written to the file
+ // nextCompressBuffer: next linebuffer to compress
+ //
+
+ int first = (_data->currentScanLine - _data->minY) /
+ _data->linesInBuffer;
+
+ int nextWriteBuffer = first;
+ int nextCompressBuffer;
+ int stop;
+ int step;
+ int scanLineMin;
+ int scanLineMax;
+
+ {
+ //
+ // Create a task group for all line buffer tasks. When the
+ // taskgroup goes out of scope, the destructor waits until
+ // all tasks are complete.
+ //
+
+ TaskGroup taskGroup;
+
+ //
+ // Determine the range of lineBuffers that intersect the scan
+ // line range. Then add the initial compression tasks to the
+ // thread pool. We always add in at least one task but the
+ // individual task might not do anything if numScanLines == 0.
+ //
+
+ if (_data->lineOrder == INCREASING_Y)
+ {
+ int last = (_data->currentScanLine + (numScanLines - 1) -
+ _data->minY) / _data->linesInBuffer;
+
+ scanLineMin = _data->currentScanLine;
+ scanLineMax = _data->currentScanLine + numScanLines - 1;
+
+ int numTasks = max (min ((int)_data->lineBuffers.size(),
+ last - first + 1),
+ 1);
+
+ for (int i = 0; i < numTasks; i++)
+ {
+ ThreadPool::addGlobalTask
+ (new LineBufferTask (&taskGroup, _data, first + i,
+ scanLineMin, scanLineMax));
+ }
+
+ nextCompressBuffer = first + numTasks;
+ stop = last + 1;
+ step = 1;
+ }
+ else
+ {
+ int last = (_data->currentScanLine - (numScanLines - 1) -
+ _data->minY) / _data->linesInBuffer;
+
+ scanLineMax = _data->currentScanLine;
+ scanLineMin = _data->currentScanLine - numScanLines + 1;
+
+ int numTasks = max (min ((int)_data->lineBuffers.size(),
+ first - last + 1),
+ 1);
+
+ for (int i = 0; i < numTasks; i++)
+ {
+ ThreadPool::addGlobalTask
+ (new LineBufferTask (&taskGroup, _data, first - i,
+ scanLineMin, scanLineMax));
+ }
+
+ nextCompressBuffer = first - numTasks;
+ stop = last - 1;
+ step = -1;
+ }
+
+ while (true)
+ {
+ if (_data->missingScanLines <= 0)
+ {
+ throw IEX_NAMESPACE::ArgExc ("Tried to write more scan lines "
+ "than specified by the data window.");
+ }
+
+ //
+ // Wait until the next line buffer is ready to be written
+ //
+
+ LineBuffer *writeBuffer =
+ _data->getLineBuffer (nextWriteBuffer);
+
+ writeBuffer->wait();
+
+ int numLines = writeBuffer->scanLineMax -
+ writeBuffer->scanLineMin + 1;
+
+ _data->missingScanLines -= numLines;
+
+ //
+ // If the line buffer is only partially full, then it is
+ // not complete and we cannot write it to disk yet.
+ //
+
+ if (writeBuffer->partiallyFull)
+ {
+ _data->currentScanLine = _data->currentScanLine +
+ step * numLines;
+ writeBuffer->post();
+
+ return;
+ }
+
+ //
+ // Write the line buffer
+ //
+
+ writePixelData (_data->_streamData, _data, writeBuffer);
+ nextWriteBuffer += step;
+
+ _data->currentScanLine = _data->currentScanLine +
+ step * numLines;
+
+ #ifdef DEBUG
+
+ assert (_data->currentScanLine ==
+ ((_data->lineOrder == INCREASING_Y) ?
+ writeBuffer->scanLineMax + 1:
+ writeBuffer->scanLineMin - 1));
+
+ #endif
+
+ //
+ // Release the lock on the line buffer
+ //
+
+ writeBuffer->post();
+
+ //
+ // If this was the last line buffer in the scanline range
+ //
+
+ if (nextWriteBuffer == stop)
+ break;
+
+ //
+ // If there are no more line buffers to compress,
+ // then only continue to write out remaining lineBuffers
+ //
+
+ if (nextCompressBuffer == stop)
+ continue;
+
+ //
+ // Add nextCompressBuffer as a compression task
+ //
+
+ ThreadPool::addGlobalTask
+ (new LineBufferTask (&taskGroup, _data, nextCompressBuffer,
+ scanLineMin, scanLineMax));
+
+ //
+ // Update the next line buffer we need to compress
+ //
+
+ nextCompressBuffer += step;
+ }
+
+ //
+ // Finish all tasks
+ //
+ }
+
+ //
+ // Exeption handling:
+ //
+ // LineBufferTask::execute() may have encountered exceptions, but
+ // those exceptions occurred in another thread, not in the thread
+ // that is executing this call to OutputFile::writePixels().
+ // LineBufferTask::execute() has caught all exceptions and stored
+ // the exceptions' what() strings in the line buffers.
+ // Now we check if any line buffer contains a stored exception; if
+ // this is the case then we re-throw the exception in this thread.
+ // (It is possible that multiple line buffers contain stored
+ // exceptions. We re-throw the first exception we find and
+ // ignore all others.)
+ //
+
+ const string *exception = 0;
+
+ for (size_t i = 0; i < _data->lineBuffers.size(); ++i)
+ {
+ LineBuffer *lineBuffer = _data->lineBuffers[i];
+
+ if (lineBuffer->hasException && !exception)
+ exception = &lineBuffer->exception;
+
+ lineBuffer->hasException = false;
+ }
+
+ if (exception)
+ throw IEX_NAMESPACE::IoExc (*exception);
+ }
+ catch (IEX_NAMESPACE::BaseExc &e)
+ {
+ REPLACE_EXC (e, "Failed to write pixel data to image "
+ "file \"" << fileName() << "\". " << e.what());
+ throw;
+ }
+}
+
+
+int
+DeepScanLineOutputFile::currentScanLine () const
+{
+ Lock lock (*_data->_streamData);
+ return _data->currentScanLine;
+}
+
+
+void
+DeepScanLineOutputFile::copyPixels (DeepScanLineInputPart &in)
+{
+ copyPixels(*in.file);
+}
+
+void
+DeepScanLineOutputFile::copyPixels (DeepScanLineInputFile &in)
+{
+
+ Lock lock (*_data->_streamData);
+
+ //
+ // Check if this file's and and the InputFile's
+ // headers are compatible.
+ //
+
+ const Header &hdr = _data->header;
+ const Header &inHdr = in.header();
+
+ if(!inHdr.hasType() || inHdr.type()!=DEEPSCANLINE)
+ {
+ THROW (IEX_NAMESPACE::ArgExc, "Cannot copy pixels from image "
+ "file \"" << in.fileName() << "\" to image "
+ "file \"" << fileName() << "\": the input needs to be a deep scanline image");
+ }
+ if (!(hdr.dataWindow() == inHdr.dataWindow()))
+ THROW (IEX_NAMESPACE::ArgExc, "Cannot copy pixels from image "
+ "file \"" << in.fileName() << "\" to image "
+ "file \"" << fileName() << "\". "
+ "The files have different data windows.");
+
+ if (!(hdr.lineOrder() == inHdr.lineOrder()))
+ THROW (IEX_NAMESPACE::ArgExc, "Quick pixel copy from image "
+ "file \"" << in.fileName() << "\" to image "
+ "file \"" << fileName() << "\" failed. "
+ "The files have different line orders.");
+
+ if (!(hdr.compression() == inHdr.compression()))
+ THROW (IEX_NAMESPACE::ArgExc, "Quick pixel copy from image "
+ "file \"" << in.fileName() << "\" to image "
+ "file \"" << fileName() << "\" failed. "
+ "The files use different compression methods.");
+
+ if (!(hdr.channels() == inHdr.channels()))
+ THROW (IEX_NAMESPACE::ArgExc, "Quick pixel copy from image "
+ "file \"" << in.fileName() << "\" to image "
+ "file \"" << fileName() << "\" failed. "
+ "The files have different channel lists.");
+
+ //
+ // Verify that no pixel data have been written to this file yet.
+ //
+
+ const Box2i &dataWindow = hdr.dataWindow();
+
+ if (_data->missingScanLines != dataWindow.max.y - dataWindow.min.y + 1)
+ THROW (IEX_NAMESPACE::LogicExc, "Quick pixel copy from image "
+ "file \"" << in.fileName() << "\" to image "
+ "file \"" << fileName() << "\" failed. "
+ "\"" << fileName() << "\" already contains "
+ "pixel data.");
+
+ //
+ // Copy the pixel data.
+ //
+
+ vector<char> data(4096);
+
+ while (_data->missingScanLines > 0)
+ {
+ Int64 dataSize = (Int64) data.size();
+ in.rawPixelData(_data->currentScanLine, &data[0], dataSize);
+ if(dataSize > data.size())
+ {
+ // block wasn't big enough - go again with enough memory this time
+ data.resize(dataSize);
+ in.rawPixelData(_data->currentScanLine, &data[0], dataSize);
+ }
+
+ // extract header from block to pass to writePixelData
+
+ Int64 packedSampleCountSize = *(Int64 *) (&data[4]);
+ Int64 packedDataSize = *(Int64 *) (&data[12]);
+ Int64 unpackedDataSize = *(Int64 *) (&data[20]);
+ const char * sampleCountTable = &data[0]+28;
+ const char * pixelData = sampleCountTable + packedSampleCountSize;
+
+
+ writePixelData (_data->_streamData, _data, lineBufferMinY (_data->currentScanLine,
+ _data->minY,
+ _data->linesInBuffer),
+ pixelData, packedDataSize, unpackedDataSize,sampleCountTable,packedSampleCountSize);
+
+ _data->currentScanLine += (_data->lineOrder == INCREASING_Y)?
+ _data->linesInBuffer: -_data->linesInBuffer;
+
+ _data->missingScanLines -= _data->linesInBuffer;
+ }
+}
+
+
+void
+DeepScanLineOutputFile::updatePreviewImage (const PreviewRgba newPixels[])
+{
+ Lock lock (*_data->_streamData);
+
+ if (_data->previewPosition <= 0)
+ THROW (IEX_NAMESPACE::LogicExc, "Cannot update preview image pixels. "
+ "File \"" << fileName() << "\" does not "
+ "contain a preview image.");
+
+ //
+ // Store the new pixels in the header's preview image attribute.
+ //
+
+ PreviewImageAttribute &pia =
+ _data->header.typedAttribute <PreviewImageAttribute> ("preview");
+
+ PreviewImage &pi = pia.value();
+ PreviewRgba *pixels = pi.pixels();
+ int numPixels = pi.width() * pi.height();
+
+ for (int i = 0; i < numPixels; ++i)
+ pixels[i] = newPixels[i];
+
+ //
+ // Save the current file position, jump to the position in
+ // the file where the preview image starts, store the new
+ // preview image, and jump back to the saved file position.
+ //
+
+ Int64 savedPosition = _data->_streamData->os->tellp();
+
+ try
+ {
+ _data->_streamData->os->seekp (_data->previewPosition);
+ pia.writeValueTo (*_data->_streamData->os, _data->version);
+ _data->_streamData->os->seekp (savedPosition);
+ }
+ catch (IEX_NAMESPACE::BaseExc &e)
+ {
+ REPLACE_EXC (e, "Cannot update preview image pixels for "
+ "file \"" << fileName() << "\". " << e.what());
+ throw;
+ }
+}
+
+
+OPENEXR_IMF_INTERNAL_NAMESPACE_SOURCE_EXIT
--- /dev/null
+///////////////////////////////////////////////////////////////////////////
+//
+// Copyright (c) 2011, Industrial Light & Magic, a division of Lucas
+// Digital Ltd. LLC
+//
+// All rights reserved.
+//
+// Redistribution and use in source and binary forms, with or without
+// modification, are permitted provided that the following conditions are
+// met:
+// * Redistributions of source code must retain the above copyright
+// notice, this list of conditions and the following disclaimer.
+// * Redistributions in binary form must reproduce the above
+// copyright notice, this list of conditions and the following disclaimer
+// in the documentation and/or other materials provided with the
+// distribution.
+// * Neither the name of Industrial Light & Magic nor the names of
+// its contributors may be used to endorse or promote products derived
+// from this software without specific prior written permission.
+//
+// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+//
+///////////////////////////////////////////////////////////////////////////
+
+
+
+#ifndef INCLUDED_IMF_DEEP_SCAN_LINE_OUTPUT_FILE_H
+#define INCLUDED_IMF_DEEP_SCAN_LINE_OUTPUT_FILE_H
+
+//-----------------------------------------------------------------------------
+//
+// class DeepScanLineOutputFile
+//
+//-----------------------------------------------------------------------------
+
+#include "ImfHeader.h"
+#include "ImfFrameBuffer.h"
+#include "ImfThreading.h"
+#include "ImfGenericOutputFile.h"
+#include "ImfNamespace.h"
+#include "ImfForward.h"
+#include "ImfExport.h"
+
+OPENEXR_IMF_INTERNAL_NAMESPACE_HEADER_ENTER
+
+
+struct PreviewRgba;
+
+class DeepScanLineOutputFile : public GenericOutputFile
+{
+ public:
+
+ //-----------------------------------------------------------
+ // Constructor -- opens the file and writes the file header.
+ // The file header is also copied into the DeepScanLineOutputFile
+ // object, and can later be accessed via the header() method.
+ // Destroying this DeepScanLineOutputFile object automatically closes
+ // the file.
+ //
+ // numThreads determines the number of threads that will be
+ // used to write the file (see ImfThreading.h).
+ //-----------------------------------------------------------
+
+ IMF_EXPORT
+ DeepScanLineOutputFile (const char fileName[], const Header &header,
+ int numThreads = globalThreadCount());
+
+
+ //------------------------------------------------------------
+ // Constructor -- attaches the new DeepScanLineOutputFile object
+ // to a file that has already been opened, and writes the file header.
+ // The file header is also copied into the DeepScanLineOutputFile
+ // object, and can later be accessed via the header() method.
+ // Destroying this DeepScanLineOutputFile object does not automatically
+ // close the file.
+ //
+ // numThreads determines the number of threads that will be
+ // used to write the file (see ImfThreading.h).
+ //------------------------------------------------------------
+
+ IMF_EXPORT
+ DeepScanLineOutputFile (OPENEXR_IMF_INTERNAL_NAMESPACE::OStream &os, const Header &header,
+ int numThreads = globalThreadCount());
+
+
+ //-------------------------------------------------
+ // Destructor
+ //
+ // Destroying the DeepScanLineOutputFile object
+ // before writing all scan lines within the data
+ // window results in an incomplete file.
+ //-------------------------------------------------
+
+ IMF_EXPORT
+ virtual ~DeepScanLineOutputFile ();
+
+
+ //------------------------
+ // Access to the file name
+ //------------------------
+
+ IMF_EXPORT
+ const char * fileName () const;
+
+
+ //--------------------------
+ // Access to the file header
+ //--------------------------
+
+ IMF_EXPORT
+ const Header & header () const;
+
+
+ //-------------------------------------------------------
+ // Set the current frame buffer -- copies the FrameBuffer
+ // object into the OutputFile object.
+ //
+ // The current frame buffer is the source of the pixel
+ // data written to the file. The current frame buffer
+ // must be set at least once before writePixels() is
+ // called. The current frame buffer can be changed
+ // after each call to writePixels.
+ //-------------------------------------------------------
+
+ IMF_EXPORT
+ void setFrameBuffer (const DeepFrameBuffer &frameBuffer);
+
+
+ //-----------------------------------
+ // Access to the current frame buffer
+ //-----------------------------------
+
+ IMF_EXPORT
+ const DeepFrameBuffer & frameBuffer () const;
+
+
+ //-------------------------------------------------------------------
+ // Write pixel data:
+ //
+ // writePixels(n) retrieves the next n scan lines worth of data from
+ // the current frame buffer, starting with the scan line indicated by
+ // currentScanLine(), and stores the data in the output file, and
+ // progressing in the direction indicated by header.lineOrder().
+ //
+ // To produce a complete and correct file, exactly m scan lines must
+ // be written, where m is equal to
+ // header().dataWindow().max.y - header().dataWindow().min.y + 1.
+ //-------------------------------------------------------------------
+
+ IMF_EXPORT
+ void writePixels (int numScanLines = 1);
+
+
+ //------------------------------------------------------------------
+ // Access to the current scan line:
+ //
+ // currentScanLine() returns the y coordinate of the first scan line
+ // that will be read from the current frame buffer during the next
+ // call to writePixels().
+ //
+ // If header.lineOrder() == INCREASING_Y:
+ //
+ // The current scan line before the first call to writePixels()
+ // is header().dataWindow().min.y. After writing each scan line,
+ // the current scan line is incremented by 1.
+ //
+ // If header.lineOrder() == DECREASING_Y:
+ //
+ // The current scan line before the first call to writePixels()
+ // is header().dataWindow().max.y. After writing each scan line,
+ // the current scan line is decremented by 1.
+ //
+ //------------------------------------------------------------------
+
+ IMF_EXPORT
+ int currentScanLine () const;
+
+
+ //--------------------------------------------------------------
+ // Shortcut to copy all pixels from an InputFile into this file,
+ // without uncompressing and then recompressing the pixel data.
+ // This file's header must be compatible with the InputFile's
+ // header: The two header's "dataWindow", "compression",
+ // "lineOrder" and "channels" attributes must be the same.
+ //--------------------------------------------------------------
+
+ IMF_EXPORT
+ void copyPixels (DeepScanLineInputFile &in);
+
+ // --------------------------------------------------------------
+ // Shortcut to copy pixels from a given part of a multipart file
+ // --------------------------------------------------------------
+ IMF_EXPORT
+ void copyPixels (DeepScanLineInputPart &in);
+
+
+ //--------------------------------------------------------------
+ // Updating the preview image:
+ //
+ // updatePreviewImage() supplies a new set of pixels for the
+ // preview image attribute in the file's header. If the header
+ // does not contain a preview image, updatePreviewImage() throws
+ // an IEX_NAMESPACE::LogicExc.
+ //
+ // Note: updatePreviewImage() is necessary because images are
+ // often stored in a file incrementally, a few scan lines at a
+ // time, while the image is being generated. Since the preview
+ // image is an attribute in the file's header, it gets stored in
+ // the file as soon as the file is opened, but we may not know
+ // what the preview image should look like until we have written
+ // the last scan line of the main image.
+ //
+ //--------------------------------------------------------------
+
+ IMF_EXPORT
+ void updatePreviewImage (const PreviewRgba newPixels[]);
+
+
+ struct Data;
+
+ private:
+
+ //------------------------------------------------------------
+ // Constructor -- attaches the OutputStreamMutex to the
+ // given one from MultiPartOutputFile. Set the previewPosition
+ // and lineOffsetsPosition which have been acquired from
+ // the constructor of MultiPartOutputFile as well.
+ //------------------------------------------------------------
+ DeepScanLineOutputFile (const OutputPartData* part);
+
+ DeepScanLineOutputFile (const DeepScanLineOutputFile &); // not implemented
+ DeepScanLineOutputFile & operator = (const DeepScanLineOutputFile &); // not implemented
+
+ void initialize (const Header &header);
+ void initializeLineBuffer();
+
+ Data * _data;
+
+
+
+ friend class MultiPartOutputFile;
+};
+
+OPENEXR_IMF_INTERNAL_NAMESPACE_HEADER_EXIT
+
+#endif
--- /dev/null
+///////////////////////////////////////////////////////////////////////////
+//
+// Copyright (c) 2011, Industrial Light & Magic, a division of Lucas
+// Digital Ltd. LLC
+//
+// All rights reserved.
+//
+// Redistribution and use in source and binary forms, with or without
+// modification, are permitted provided that the following conditions are
+// met:
+// * Redistributions of source code must retain the above copyright
+// notice, this list of conditions and the following disclaimer.
+// * Redistributions in binary form must reproduce the above
+// copyright notice, this list of conditions and the following disclaimer
+// in the documentation and/or other materials provided with the
+// distribution.
+// * Neither the name of Industrial Light & Magic nor the names of
+// its contributors may be used to endorse or promote products derived
+// from this software without specific prior written permission.
+//
+// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+//
+///////////////////////////////////////////////////////////////////////////
+
+#include "ImfDeepScanLineOutputPart.h"
+#include "ImfNamespace.h"
+
+OPENEXR_IMF_INTERNAL_NAMESPACE_SOURCE_ENTER
+
+DeepScanLineOutputPart::DeepScanLineOutputPart(MultiPartOutputFile& multiPartFile, int partNumber)
+{
+ file = multiPartFile.getOutputPart<DeepScanLineOutputFile>(partNumber);
+}
+
+
+const char *
+DeepScanLineOutputPart::fileName () const
+{
+ return file->fileName();
+}
+
+
+const Header &
+DeepScanLineOutputPart::header () const
+{
+ return file->header();
+}
+
+
+void
+DeepScanLineOutputPart::setFrameBuffer (const DeepFrameBuffer &frameBuffer)
+{
+ file->setFrameBuffer(frameBuffer);
+}
+
+
+const DeepFrameBuffer &
+DeepScanLineOutputPart::frameBuffer () const
+{
+ return file->frameBuffer();
+}
+
+
+void
+DeepScanLineOutputPart::writePixels (int numScanLines)
+{
+ file->writePixels(numScanLines);
+}
+
+
+int
+DeepScanLineOutputPart::currentScanLine () const
+{
+ return file->currentScanLine();
+}
+
+
+void
+DeepScanLineOutputPart::copyPixels (DeepScanLineInputFile &in)
+{
+ file->copyPixels(in);
+}
+
+void
+DeepScanLineOutputPart::copyPixels (DeepScanLineInputPart &in)
+{
+ file->copyPixels(in);
+}
+
+void
+DeepScanLineOutputPart::updatePreviewImage (const PreviewRgba newPixels[])
+{
+ file->updatePreviewImage(newPixels);
+}
+
+OPENEXR_IMF_INTERNAL_NAMESPACE_SOURCE_EXIT
+
--- /dev/null
+///////////////////////////////////////////////////////////////////////////
+//
+// Copyright (c) 2011, Industrial Light & Magic, a division of Lucas
+// Digital Ltd. LLC
+//
+// All rights reserved.
+//
+// Redistribution and use in source and binary forms, with or without
+// modification, are permitted provided that the following conditions are
+// met:
+// * Redistributions of source code must retain the above copyright
+// notice, this list of conditions and the following disclaimer.
+// * Redistributions in binary form must reproduce the above
+// copyright notice, this list of conditions and the following disclaimer
+// in the documentation and/or other materials provided with the
+// distribution.
+// * Neither the name of Industrial Light & Magic nor the names of
+// its contributors may be used to endorse or promote products derived
+// from this software without specific prior written permission.
+//
+// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+//
+///////////////////////////////////////////////////////////////////////////
+
+#ifndef IMFDEEPSCANLINEOUTPUTPART_H_
+#define IMFDEEPSCANLINEOUTPUTPART_H_
+
+#include "ImfDeepScanLineOutputFile.h"
+#include "ImfMultiPartOutputFile.h"
+#include "ImfNamespace.h"
+#include "ImfExport.h"
+
+OPENEXR_IMF_INTERNAL_NAMESPACE_HEADER_ENTER
+
+class DeepScanLineOutputPart
+{
+ public:
+
+ IMF_EXPORT
+ DeepScanLineOutputPart(MultiPartOutputFile& multiPartFile, int partNumber);
+
+ //------------------------
+ // Access to the file name
+ //------------------------
+
+ IMF_EXPORT
+ const char * fileName () const;
+
+
+ //--------------------------
+ // Access to the file header
+ //--------------------------
+
+ IMF_EXPORT
+ const Header & header () const;
+
+
+ //-------------------------------------------------------
+ // Set the current frame buffer -- copies the FrameBuffer
+ // object into the OutputFile object.
+ //
+ // The current frame buffer is the source of the pixel
+ // data written to the file. The current frame buffer
+ // must be set at least once before writePixels() is
+ // called. The current frame buffer can be changed
+ // after each call to writePixels.
+ //-------------------------------------------------------
+
+ IMF_EXPORT
+ void setFrameBuffer (const DeepFrameBuffer &frameBuffer);
+
+
+ //-----------------------------------
+ // Access to the current frame buffer
+ //-----------------------------------
+
+ IMF_EXPORT
+ const DeepFrameBuffer & frameBuffer () const;
+
+
+ //-------------------------------------------------------------------
+ // Write pixel data:
+ //
+ // writePixels(n) retrieves the next n scan lines worth of data from
+ // the current frame buffer, starting with the scan line indicated by
+ // currentScanLine(), and stores the data in the output file, and
+ // progressing in the direction indicated by header.lineOrder().
+ //
+ // To produce a complete and correct file, exactly m scan lines must
+ // be written, where m is equal to
+ // header().dataWindow().max.y - header().dataWindow().min.y + 1.
+ //-------------------------------------------------------------------
+
+ IMF_EXPORT
+ void writePixels (int numScanLines = 1);
+
+
+ //------------------------------------------------------------------
+ // Access to the current scan line:
+ //
+ // currentScanLine() returns the y coordinate of the first scan line
+ // that will be read from the current frame buffer during the next
+ // call to writePixels().
+ //
+ // If header.lineOrder() == INCREASING_Y:
+ //
+ // The current scan line before the first call to writePixels()
+ // is header().dataWindow().min.y. After writing each scan line,
+ // the current scan line is incremented by 1.
+ //
+ // If header.lineOrder() == DECREASING_Y:
+ //
+ // The current scan line before the first call to writePixels()
+ // is header().dataWindow().max.y. After writing each scan line,
+ // the current scan line is decremented by 1.
+ //
+ //------------------------------------------------------------------
+
+ IMF_EXPORT
+ int currentScanLine () const;
+
+
+ //--------------------------------------------------------------
+ // Shortcut to copy all pixels from an InputFile into this file,
+ // without uncompressing and then recompressing the pixel data.
+ // This file's header must be compatible with the InputFile's
+ // header: The two header's "dataWindow", "compression",
+ // "lineOrder" and "channels" attributes must be the same.
+ //--------------------------------------------------------------
+
+ IMF_EXPORT
+ void copyPixels (DeepScanLineInputFile &in);
+ IMF_EXPORT
+ void copyPixels (DeepScanLineInputPart &in);
+
+
+ //--------------------------------------------------------------
+ // Updating the preview image:
+ //
+ // updatePreviewImage() supplies a new set of pixels for the
+ // preview image attribute in the file's header. If the header
+ // does not contain a preview image, updatePreviewImage() throws
+ // an IEX_NAMESPACE::LogicExc.
+ //
+ // Note: updatePreviewImage() is necessary because images are
+ // often stored in a file incrementally, a few scan lines at a
+ // time, while the image is being generated. Since the preview
+ // image is an attribute in the file's header, it gets stored in
+ // the file as soon as the file is opened, but we may not know
+ // what the preview image should look like until we have written
+ // the last scan line of the main image.
+ //
+ //--------------------------------------------------------------
+
+ IMF_EXPORT
+ void updatePreviewImage (const PreviewRgba newPixels[]);
+
+ private:
+ DeepScanLineOutputFile* file;
+};
+
+OPENEXR_IMF_INTERNAL_NAMESPACE_HEADER_EXIT
+
+
+
+
+
+#endif /* IMFDEEPSCANLINEOUTPUTPART_H_ */
--- /dev/null
+///////////////////////////////////////////////////////////////////////////
+//
+// Copyright (c) 2011, Industrial Light & Magic, a division of Lucas
+// Digital Ltd. LLC
+//
+// All rights reserved.
+//
+// Redistribution and use in source and binary forms, with or without
+// modification, are permitted provided that the following conditions are
+// met:
+// * Redistributions of source code must retain the above copyright
+// notice, this list of conditions and the following disclaimer.
+// * Redistributions in binary form must reproduce the above
+// copyright notice, this list of conditions and the following disclaimer
+// in the documentation and/or other materials provided with the
+// distribution.
+// * Neither the name of Industrial Light & Magic nor the names of
+// its contributors may be used to endorse or promote products derived
+// from this software without specific prior written permission.
+//
+// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+//
+///////////////////////////////////////////////////////////////////////////
+
+//-----------------------------------------------------------------------------
+//
+// class DeepTiledInputFile
+//
+//-----------------------------------------------------------------------------
+
+#include <ImfDeepTiledInputFile.h>
+#include <ImfTileDescriptionAttribute.h>
+#include <ImfChannelList.h>
+#include <ImfMisc.h>
+#include <ImfTiledMisc.h>
+#include <ImfStdIO.h>
+#include <ImfCompressor.h>
+#include "ImathBox.h"
+#include <ImfXdr.h>
+#include <ImfConvert.h>
+#include <ImfVersion.h>
+#include <ImfTileOffsets.h>
+#include <ImfThreading.h>
+#include <ImfPartType.h>
+#include <ImfMultiPartInputFile.h>
+#include "IlmThreadPool.h"
+#include "IlmThreadSemaphore.h"
+#include "IlmThreadMutex.h"
+#include "ImfInputStreamMutex.h"
+#include "ImfInputPartData.h"
+#include "ImathVec.h"
+#include "Iex.h"
+#include <string>
+#include <vector>
+#include <algorithm>
+#include <assert.h>
+#include <limits>
+
+#include "ImfNamespace.h"
+
+OPENEXR_IMF_INTERNAL_NAMESPACE_SOURCE_ENTER
+
+using IMATH_NAMESPACE::Box2i;
+using IMATH_NAMESPACE::V2i;
+using std::string;
+using std::vector;
+using std::min;
+using std::max;
+using ILMTHREAD_NAMESPACE::Mutex;
+using ILMTHREAD_NAMESPACE::Lock;
+using ILMTHREAD_NAMESPACE::Semaphore;
+using ILMTHREAD_NAMESPACE::Task;
+using ILMTHREAD_NAMESPACE::TaskGroup;
+using ILMTHREAD_NAMESPACE::ThreadPool;
+
+namespace {
+
+struct TInSliceInfo
+{
+ PixelType typeInFrameBuffer;
+ PixelType typeInFile;
+ char* pointerArrayBase;
+ size_t xStride;
+ size_t yStride;
+ ptrdiff_t sampleStride;
+ bool fill;
+ bool skip;
+ double fillValue;
+ int xTileCoords;
+ int yTileCoords;
+
+ TInSliceInfo (PixelType typeInFrameBuffer = HALF,
+ char * base = NULL,
+ PixelType typeInFile = HALF,
+ size_t xStride = 0,
+ size_t yStride = 0,
+ ptrdiff_t sampleStride = 0,
+ bool fill = false,
+ bool skip = false,
+ double fillValue = 0.0,
+ int xTileCoords = 0,
+ int yTileCoords = 0);
+};
+
+
+TInSliceInfo::TInSliceInfo (PixelType tifb,
+ char * b,
+ PixelType tifl,
+ size_t xs, size_t ys,
+ ptrdiff_t spst,
+ bool f, bool s,
+ double fv,
+ int xtc,
+ int ytc)
+:
+ typeInFrameBuffer (tifb),
+ typeInFile (tifl),
+ pointerArrayBase (b),
+ xStride (xs),
+ yStride (ys),
+ sampleStride (spst),
+ fill (f),
+ skip (s),
+ fillValue (fv),
+ xTileCoords (xtc),
+ yTileCoords (ytc)
+{
+ // empty
+}
+
+
+struct TileBuffer
+{
+ Array2D<unsigned int> sampleCount;
+ const char * uncompressedData;
+ char * buffer;
+ Int64 dataSize;
+ Int64 uncompressedDataSize;
+ Compressor * compressor;
+ Compressor::Format format;
+ int dx;
+ int dy;
+ int lx;
+ int ly;
+ bool hasException;
+ string exception;
+
+ TileBuffer ();
+ ~TileBuffer ();
+
+ inline void wait () {_sem.wait();}
+ inline void post () {_sem.post();}
+
+ protected:
+
+ Semaphore _sem;
+};
+
+
+TileBuffer::TileBuffer ():
+ uncompressedData (0),
+ buffer (0),
+ dataSize (0),
+ compressor (0),
+ format (defaultFormat (compressor)),
+ dx (-1),
+ dy (-1),
+ lx (-1),
+ ly (-1),
+ hasException (false),
+ exception (),
+ _sem (1)
+{
+ // empty
+}
+
+
+TileBuffer::~TileBuffer ()
+{
+ delete compressor;
+}
+
+} // namespace
+
+
+class MultiPartInputFile;
+
+
+//
+// struct TiledInputFile::Data stores things that will be
+// needed between calls to readTile()
+//
+
+struct DeepTiledInputFile::Data: public Mutex
+{
+ Header header; // the image header
+ TileDescription tileDesc; // describes the tile layout
+ int version; // file's version
+ DeepFrameBuffer frameBuffer; // framebuffer to write into
+ LineOrder lineOrder; // the file's lineorder
+ int minX; // data window's min x coord
+ int maxX; // data window's max x coord
+ int minY; // data window's min y coord
+ int maxY; // data window's max x coord
+
+ int numXLevels; // number of x levels
+ int numYLevels; // number of y levels
+ int * numXTiles; // number of x tiles at a level
+ int * numYTiles; // number of y tiles at a level
+
+ TileOffsets tileOffsets; // stores offsets in file for
+ // each tile
+
+ bool fileIsComplete; // True if no tiles are missing
+ // in the file
+
+ vector<TInSliceInfo*> slices; // info about channels in file
+
+ // ourselves? or does someone
+ // else do it?
+
+ int partNumber; // part number
+
+ bool multiPartBackwardSupport; // if we are reading a multipart file
+ // using OpenEXR 1.7 API
+
+ int numThreads; // number of threads
+
+ MultiPartInputFile* multiPartFile; // the MultiPartInputFile used to
+ // support backward compatibility
+
+ vector<TileBuffer*> tileBuffers; // each holds a single tile
+
+ bool memoryMapped; // if the stream is memory mapped
+
+ char* sampleCountSliceBase; // pointer to the start of
+ // the sample count array
+ ptrdiff_t sampleCountXStride; // x stride of the sample count array
+ ptrdiff_t sampleCountYStride; // y stride of the sample count array
+
+ int sampleCountXTileCoords; // the value of xTileCoords from the
+ // sample count slice
+ int sampleCountYTileCoords; // the value of yTileCoords from the
+ // sample count slice
+
+ Array<char> sampleCountTableBuffer; // the buffer for sample count table
+
+ Compressor* sampleCountTableComp; // the decompressor for sample count table
+
+ Int64 maxSampleCountTableSize; // the max size in bytes for a pixel
+ // sample count table
+ int combinedSampleSize; // total size of all channels combined to check sampletable size
+
+ InputStreamMutex * _streamData;
+ bool _deleteStream; // should we delete the stream
+ Data (int numThreads);
+ ~Data ();
+
+ inline TileBuffer * getTileBuffer (int number);
+ // hash function from tile indices
+ // into our vector of tile buffers
+
+ int& getSampleCount(int x, int y);
+ // get the number of samples
+ // in each pixel
+};
+
+
+DeepTiledInputFile::Data::Data (int numThreads):
+ numXTiles (0),
+ numYTiles (0),
+ partNumber (-1),
+ multiPartBackwardSupport(false),
+ numThreads(numThreads),
+ memoryMapped(false),
+ _streamData(NULL),
+ _deleteStream(false)
+{
+ //
+ // We need at least one tileBuffer, but if threading is used,
+ // to keep n threads busy we need 2*n tileBuffers
+ //
+
+ tileBuffers.resize (max (1, 2 * numThreads));
+}
+
+
+DeepTiledInputFile::Data::~Data ()
+{
+ delete [] numXTiles;
+ delete [] numYTiles;
+
+ for (size_t i = 0; i < tileBuffers.size(); i++)
+ delete tileBuffers[i];
+
+ if (multiPartBackwardSupport)
+ delete multiPartFile;
+
+ for (size_t i = 0; i < slices.size(); i++)
+ delete slices[i];
+}
+
+
+TileBuffer*
+DeepTiledInputFile::Data::getTileBuffer (int number)
+{
+ return tileBuffers[number % tileBuffers.size()];
+}
+
+
+int&
+DeepTiledInputFile::Data::getSampleCount(int x, int y)
+{
+ return sampleCount(sampleCountSliceBase,
+ sampleCountXStride,
+ sampleCountYStride,
+ x, y);
+}
+
+
+namespace {
+
+void
+readTileData (InputStreamMutex *streamData,
+ DeepTiledInputFile::Data *ifd,
+ int dx, int dy,
+ int lx, int ly,
+ char *&buffer,
+ Int64 &dataSize,
+ Int64 &unpackedDataSize)
+{
+ //
+ // Read a single tile block from the file and into the array pointed
+ // to by buffer. If the file is memory-mapped, then we change where
+ // buffer points instead of writing into the array (hence buffer needs
+ // to be a reference to a char *).
+ //
+
+ //
+ // Look up the location for this tile in the Index and
+ // seek to that position if necessary
+ //
+
+ Int64 tileOffset = ifd->tileOffsets (dx, dy, lx, ly);
+
+ if (tileOffset == 0)
+ {
+ THROW (IEX_NAMESPACE::InputExc, "Tile (" << dx << ", " << dy << ", " <<
+ lx << ", " << ly << ") is missing.");
+ }
+
+ //
+ // In a multi-part file, the next chunk does not need to
+ // belong to the same part, so we have to compare the
+ // offset here.
+ //
+
+ if ( !isMultiPart(ifd->version) )
+ {
+ if (streamData->currentPosition != tileOffset)
+ streamData->is->seekg(tileOffset);
+ }
+ else
+ {
+ //
+ // In a multi-part file, the file pointer may be moved by other
+ // parts, so we have to ask tellg() where we are.
+ //
+ if (streamData->is->tellg() != tileOffset)
+ streamData->is->seekg (tileOffset);
+ }
+
+ //
+ // Read the first few bytes of the tile (the header).
+ // Verify that the tile coordinates and the level number
+ // are correct.
+ //
+
+ int tileXCoord, tileYCoord, levelX, levelY;
+
+ if (isMultiPart(ifd->version))
+ {
+ int partNumber;
+ Xdr::read <StreamIO> (*streamData->is, partNumber);
+ if (partNumber != ifd->partNumber)
+ {
+ THROW (IEX_NAMESPACE::ArgExc, "Unexpected part number " << partNumber
+ << ", should be " << ifd->partNumber << ".");
+ }
+ }
+
+ Xdr::read <StreamIO> (*streamData->is, tileXCoord);
+ Xdr::read <StreamIO> (*streamData->is, tileYCoord);
+ Xdr::read <StreamIO> (*streamData->is, levelX);
+ Xdr::read <StreamIO> (*streamData->is, levelY);
+
+ Int64 tableSize;
+ Xdr::read <StreamIO> (*streamData->is, tableSize);
+
+ Xdr::read <StreamIO> (*streamData->is, dataSize);
+ Xdr::read <StreamIO> (*streamData->is, unpackedDataSize);
+
+
+ //
+ // Skip the pixel sample count table because we have read this data.
+ //
+
+ Xdr::skip <StreamIO> (*streamData->is, tableSize);
+
+
+ if (tileXCoord != dx)
+ throw IEX_NAMESPACE::InputExc ("Unexpected tile x coordinate.");
+
+ if (tileYCoord != dy)
+ throw IEX_NAMESPACE::InputExc ("Unexpected tile y coordinate.");
+
+ if (levelX != lx)
+ throw IEX_NAMESPACE::InputExc ("Unexpected tile x level number coordinate.");
+
+ if (levelY != ly)
+ throw IEX_NAMESPACE::InputExc ("Unexpected tile y level number coordinate.");
+
+ //
+ // Read the pixel data.
+ //
+
+ if (streamData->is->isMemoryMapped ())
+ buffer = streamData->is->readMemoryMapped (dataSize);
+ else
+ {
+ // (TODO) check if the packed data size is too big?
+ // (TODO) better memory management here. Don't delete buffer everytime.
+ if (buffer != 0) delete[] buffer;
+ buffer = new char[dataSize];
+ streamData->is->read (buffer, dataSize);
+ }
+
+ //
+ // Keep track of which tile is the next one in
+ // the file, so that we can avoid redundant seekg()
+ // operations (seekg() can be fairly expensive).
+ //
+
+ streamData->currentPosition = tileOffset + 4 * Xdr::size<int>() +
+ 3 * Xdr::size<Int64>() +
+ tableSize +
+ dataSize;
+}
+
+
+void
+readNextTileData (InputStreamMutex *streamData,
+ DeepTiledInputFile::Data *ifd,
+ int &dx, int &dy,
+ int &lx, int &ly,
+ char * & buffer,
+ Int64 &dataSize,
+ Int64 &unpackedDataSize)
+{
+ //
+ // Read the next tile block from the file
+ //
+
+ //
+ // Read the first few bytes of the tile (the header).
+ //
+
+ Xdr::read <StreamIO> (*streamData->is, dx);
+ Xdr::read <StreamIO> (*streamData->is, dy);
+ Xdr::read <StreamIO> (*streamData->is, lx);
+ Xdr::read <StreamIO> (*streamData->is, ly);
+
+ Int64 tableSize;
+ Xdr::read <StreamIO> (*streamData->is, tableSize);
+
+ Xdr::read <StreamIO> (*streamData->is, dataSize);
+ Xdr::read <StreamIO> (*streamData->is, unpackedDataSize);
+
+ //
+ // Skip the pixel sample count table because we have read this data.
+ //
+
+ Xdr::skip <StreamIO> (*streamData->is, tableSize);
+
+ //
+ // Read the pixel data.
+ //
+
+ streamData->is->read (buffer, dataSize);
+
+ //
+ // Keep track of which tile is the next one in
+ // the file, so that we can avoid redundant seekg()
+ // operations (seekg() can be fairly expensive).
+ //
+
+ streamData->currentPosition += 4 * Xdr::size<int>() +
+ 3 * Xdr::size<Int64>() +
+ tableSize +
+ dataSize;
+}
+
+
+//
+// A TileBufferTask encapsulates the task of uncompressing
+// a single tile and copying it into the frame buffer.
+//
+
+class TileBufferTask : public Task
+{
+ public:
+
+ TileBufferTask (TaskGroup *group,
+ DeepTiledInputFile::Data *ifd,
+ TileBuffer *tileBuffer);
+
+ virtual ~TileBufferTask ();
+
+ virtual void execute ();
+
+ private:
+
+ DeepTiledInputFile::Data * _ifd;
+ TileBuffer * _tileBuffer;
+};
+
+
+TileBufferTask::TileBufferTask
+ (TaskGroup *group,
+ DeepTiledInputFile::Data *ifd,
+ TileBuffer *tileBuffer)
+:
+ Task (group),
+ _ifd (ifd),
+ _tileBuffer (tileBuffer)
+{
+ // empty
+}
+
+
+TileBufferTask::~TileBufferTask ()
+{
+ //
+ // Signal that the tile buffer is now free
+ //
+
+ _tileBuffer->post ();
+}
+
+
+void
+TileBufferTask::execute ()
+{
+ try
+ {
+ //
+ // Calculate information about the tile
+ //
+
+ Box2i tileRange = OPENEXR_IMF_INTERNAL_NAMESPACE::dataWindowForTile (
+ _ifd->tileDesc,
+ _ifd->minX, _ifd->maxX,
+ _ifd->minY, _ifd->maxY,
+ _tileBuffer->dx,
+ _tileBuffer->dy,
+ _tileBuffer->lx,
+ _tileBuffer->ly);
+
+ //
+ // Get the size of the tile.
+ //
+
+ Array<unsigned int> numPixelsPerScanLine;
+ numPixelsPerScanLine.resizeErase(tileRange.max.y - tileRange.min.y + 1);
+
+ int sizeOfTile = 0;
+ int maxBytesPerTileLine = 0;
+
+ for (int y = tileRange.min.y; y <= tileRange.max.y; y++)
+ {
+ numPixelsPerScanLine[y - tileRange.min.y] = 0;
+
+ int bytesPerLine = 0;
+
+ for (int x = tileRange.min.x; x <= tileRange.max.x; x++)
+ {
+ int xOffset = _ifd->sampleCountXTileCoords * tileRange.min.x;
+ int yOffset = _ifd->sampleCountYTileCoords * tileRange.min.y;
+
+ int count = _ifd->getSampleCount(x - xOffset, y - yOffset);
+ for (unsigned int c = 0; c < _ifd->slices.size(); ++c)
+ {
+ sizeOfTile += count * pixelTypeSize(_ifd->slices[c]->typeInFile);
+ bytesPerLine += count * pixelTypeSize(_ifd->slices[c]->typeInFile);
+ }
+ numPixelsPerScanLine[y - tileRange.min.y] += count;
+ }
+
+ if (bytesPerLine > maxBytesPerTileLine)
+ maxBytesPerTileLine = bytesPerLine;
+ }
+
+ // (TODO) don't do this every time.
+ if (_tileBuffer->compressor != 0)
+ delete _tileBuffer->compressor;
+ _tileBuffer->compressor = newTileCompressor
+ (_ifd->header.compression(),
+ maxBytesPerTileLine,
+ _ifd->tileDesc.ySize,
+ _ifd->header);
+
+ //
+ // Uncompress the data, if necessary
+ //
+
+ if (_tileBuffer->compressor && _tileBuffer->dataSize < Int64(sizeOfTile))
+ {
+ _tileBuffer->format = _tileBuffer->compressor->format();
+
+ _tileBuffer->dataSize = _tileBuffer->compressor->uncompressTile
+ (_tileBuffer->buffer, _tileBuffer->dataSize,
+ tileRange, _tileBuffer->uncompressedData);
+ }
+ else
+ {
+ //
+ // If the line is uncompressed, it's in XDR format,
+ // regardless of the compressor's output format.
+ //
+
+ _tileBuffer->format = Compressor::XDR;
+ _tileBuffer->uncompressedData = _tileBuffer->buffer;
+ }
+
+ //
+ // Convert the tile of pixel data back from the machine-independent
+ // representation, and store the result in the frame buffer.
+ //
+
+ const char *readPtr = _tileBuffer->uncompressedData;
+ // points to where we
+ // read from in the
+ // tile block
+
+ //
+ // Iterate over the scan lines in the tile.
+ //
+
+ for (int y = tileRange.min.y; y <= tileRange.max.y; ++y)
+ {
+ //
+ // Iterate over all image channels.
+ //
+
+ for (unsigned int i = 0; i < _ifd->slices.size(); ++i)
+ {
+ TInSliceInfo &slice = *_ifd->slices[i];
+
+ //
+ // These offsets are used to facilitate both
+ // absolute and tile-relative pixel coordinates.
+ //
+
+ int xOffsetForData = (slice.xTileCoords == 0) ? 0 : tileRange.min.x;
+ int yOffsetForData = (slice.yTileCoords == 0) ? 0 : tileRange.min.y;
+ int xOffsetForSampleCount =
+ (_ifd->sampleCountXTileCoords == 0) ? 0 : tileRange.min.x;
+ int yOffsetForSampleCount =
+ (_ifd->sampleCountYTileCoords == 0) ? 0 : tileRange.min.y;
+
+ //
+ // Fill the frame buffer with pixel data.
+ //
+
+ if (slice.skip)
+ {
+ //
+ // The file contains data for this channel, but
+ // the frame buffer contains no slice for this channel.
+ //
+
+ skipChannel (readPtr, slice.typeInFile,
+ numPixelsPerScanLine[y - tileRange.min.y]);
+ }
+ else
+ {
+ //
+ // The frame buffer contains a slice for this channel.
+ //
+
+ copyIntoDeepFrameBuffer (readPtr, slice.pointerArrayBase,
+ _ifd->sampleCountSliceBase,
+ _ifd->sampleCountXStride,
+ _ifd->sampleCountYStride,
+ y,
+ tileRange.min.x,
+ tileRange.max.x,
+ xOffsetForSampleCount, yOffsetForSampleCount,
+ xOffsetForData, yOffsetForData,
+ slice.sampleStride,
+ slice.xStride,
+ slice.yStride,
+ slice.fill,
+ slice.fillValue, _tileBuffer->format,
+ slice.typeInFrameBuffer,
+ slice.typeInFile);
+ }
+ }
+ }
+ }
+ catch (std::exception &e)
+ {
+ if (!_tileBuffer->hasException)
+ {
+ _tileBuffer->exception = e.what ();
+ _tileBuffer->hasException = true;
+ }
+ }
+ catch (...)
+ {
+ if (!_tileBuffer->hasException)
+ {
+ _tileBuffer->exception = "unrecognized exception";
+ _tileBuffer->hasException = true;
+ }
+ }
+}
+
+
+TileBufferTask *
+newTileBufferTask
+ (TaskGroup *group,
+ DeepTiledInputFile::Data *ifd,
+ int number,
+ int dx, int dy,
+ int lx, int ly)
+{
+ //
+ // Wait for a tile buffer to become available,
+ // fill the buffer with raw data from the file,
+ // and create a new TileBufferTask whose execute()
+ // method will uncompress the tile and copy the
+ // tile's pixels into the frame buffer.
+ //
+
+ TileBuffer *tileBuffer = ifd->getTileBuffer (number);
+
+ try
+ {
+ tileBuffer->wait();
+
+ tileBuffer->dx = dx;
+ tileBuffer->dy = dy;
+ tileBuffer->lx = lx;
+ tileBuffer->ly = ly;
+
+ tileBuffer->uncompressedData = 0;
+
+ readTileData (ifd->_streamData, ifd, dx, dy, lx, ly,
+ tileBuffer->buffer,
+ tileBuffer->dataSize,
+ tileBuffer->uncompressedDataSize);
+ }
+ catch (...)
+ {
+ //
+ // Reading from the file caused an exception.
+ // Signal that the tile buffer is free, and
+ // re-throw the exception.
+ //
+
+ tileBuffer->post();
+ throw;
+ }
+
+ return new TileBufferTask (group, ifd, tileBuffer);
+}
+
+
+} // namespace
+
+
+DeepTiledInputFile::DeepTiledInputFile (const char fileName[], int numThreads):
+ _data (new Data (numThreads))
+{
+ _data->_deleteStream=true;
+ //
+ // This constructor is called when a user
+ // explicitly wants to read a tiled file.
+ //
+
+ IStream* is = 0;
+ try
+ {
+ is = new StdIFStream (fileName);
+ readMagicNumberAndVersionField(*is, _data->version);
+
+ //
+ // Compatibility to read multpart file.
+ //
+ if (isMultiPart(_data->version))
+ {
+ compatibilityInitialize(*is);
+ }
+ else
+ {
+ _data->_streamData = new InputStreamMutex();
+ _data->_streamData->is = is;
+ _data->header.readFrom (*_data->_streamData->is, _data->version);
+ initialize();
+ _data->tileOffsets.readFrom (*(_data->_streamData->is), _data->fileIsComplete,false,true);
+ _data->_streamData->currentPosition = _data->_streamData->is->tellg();
+ }
+ }
+ catch (IEX_NAMESPACE::BaseExc &e)
+ {
+ if (is) delete is;
+ if (_data && !_data->multiPartBackwardSupport && _data->_streamData) delete _data->_streamData;
+ if (_data) delete _data;
+
+ REPLACE_EXC (e, "Cannot open image file "
+ "\"" << fileName << "\". " << e.what());
+ throw;
+ }
+ catch (...)
+ {
+ if (is) delete is;
+ if (_data && !_data->multiPartBackwardSupport && _data->_streamData) delete _data->_streamData;
+ if (_data) delete _data;
+
+ throw;
+ }
+}
+
+
+DeepTiledInputFile::DeepTiledInputFile (OPENEXR_IMF_INTERNAL_NAMESPACE::IStream &is, int numThreads):
+ _data (new Data (numThreads))
+{
+ _data->_streamData=0;
+ _data->_deleteStream=false;
+
+ //
+ // This constructor is called when a user
+ // explicitly wants to read a tiled file.
+ //
+
+ try
+ {
+ readMagicNumberAndVersionField(is, _data->version);
+
+ //
+ // Backward compatibility to read multpart file.
+ //
+ if (isMultiPart(_data->version))
+ {
+ compatibilityInitialize(is);
+ }
+ else
+ {
+ _data->_streamData = new InputStreamMutex();
+ _data->_streamData->is = &is;
+ _data->header.readFrom (*_data->_streamData->is, _data->version);
+ initialize();
+ // file is guaranteed not to be multipart, but is deep
+ _data->tileOffsets.readFrom (*(_data->_streamData->is), _data->fileIsComplete, false,true);
+ _data->memoryMapped = _data->_streamData->is->isMemoryMapped();
+ _data->_streamData->currentPosition = _data->_streamData->is->tellg();
+ }
+ }
+ catch (IEX_NAMESPACE::BaseExc &e)
+ {
+ if (_data && !_data->multiPartBackwardSupport && _data->_streamData) delete _data->_streamData;
+ if (_data) delete _data;
+
+ REPLACE_EXC (e, "Cannot open image file "
+ "\"" << is.fileName() << "\". " << e.what());
+ throw;
+ }
+ catch (...)
+ {
+ if (_data && !_data->multiPartBackwardSupport && _data->_streamData) delete _data->_streamData;
+ if (_data) delete _data;
+
+ throw;
+ }
+}
+
+
+DeepTiledInputFile::DeepTiledInputFile (const Header &header,
+ OPENEXR_IMF_INTERNAL_NAMESPACE::IStream *is,
+ int version,
+ int numThreads) :
+ _data (new Data (numThreads))
+
+{
+ _data->_streamData->is = is;
+ _data->_deleteStream=false;
+
+ //
+ // This constructor called by class Imf::InputFile
+ // when a user wants to just read an image file, and
+ // doesn't care or know if the file is tiled.
+ // No need to have backward compatibility here, because
+ // we have the header.
+ //
+
+ _data->header = header;
+ _data->version = version;
+ initialize();
+ _data->tileOffsets.readFrom (*(_data->_streamData->is), _data->fileIsComplete,false,true);
+ _data->memoryMapped = is->isMemoryMapped();
+ _data->_streamData->currentPosition = _data->_streamData->is->tellg();
+}
+
+
+DeepTiledInputFile::DeepTiledInputFile (InputPartData* part) :
+ _data (new Data (part->numThreads))
+{
+ _data->_deleteStream=false;
+ multiPartInitialize(part);
+}
+
+
+void
+DeepTiledInputFile::compatibilityInitialize(OPENEXR_IMF_INTERNAL_NAMESPACE::IStream& is)
+{
+ is.seekg(0);
+ //
+ // Construct a MultiPartInputFile, initialize TiledInputFile
+ // with the part 0 data.
+ // (TODO) maybe change the third parameter of the constructor of MultiPartInputFile later.
+ //
+ _data->multiPartFile = new MultiPartInputFile(is, _data->numThreads);
+ _data->multiPartBackwardSupport = true;
+ InputPartData* part = _data->multiPartFile->getPart(0);
+
+ multiPartInitialize(part);
+}
+
+
+void
+DeepTiledInputFile::multiPartInitialize(InputPartData* part)
+{
+ if (isTiled(part->header.type()) == false)
+ THROW (IEX_NAMESPACE::ArgExc, "Can't build a DeepTiledInputFile from a part of type " << part->header.type());
+
+ _data->_streamData = part->mutex;
+ _data->header = part->header;
+ _data->version = part->version;
+ _data->partNumber = part->partNumber;
+ _data->memoryMapped = _data->_streamData->is->isMemoryMapped();
+ initialize();
+ _data->tileOffsets.readFrom(part->chunkOffsets , _data->fileIsComplete);
+ _data->_streamData->currentPosition = _data->_streamData->is->tellg();
+}
+
+
+void
+DeepTiledInputFile::initialize ()
+{
+ if (_data->partNumber == -1)
+ if (_data->header.type() != DEEPTILE)
+ throw IEX_NAMESPACE::ArgExc ("Expected a deep tiled file but the file is not deep tiled.");
+ if(_data->header.version()!=1)
+ {
+ THROW(IEX_NAMESPACE::ArgExc, "Version " << _data->header.version() << " not supported for deeptiled images in this version of the library");
+ }
+
+ _data->header.sanityCheck (true);
+
+ _data->tileDesc = _data->header.tileDescription();
+ _data->lineOrder = _data->header.lineOrder();
+
+ //
+ // Save the dataWindow information
+ //
+
+ const Box2i &dataWindow = _data->header.dataWindow();
+ _data->minX = dataWindow.min.x;
+ _data->maxX = dataWindow.max.x;
+ _data->minY = dataWindow.min.y;
+ _data->maxY = dataWindow.max.y;
+
+ //
+ // Precompute level and tile information to speed up utility functions
+ //
+
+ precalculateTileInfo (_data->tileDesc,
+ _data->minX, _data->maxX,
+ _data->minY, _data->maxY,
+ _data->numXTiles, _data->numYTiles,
+ _data->numXLevels, _data->numYLevels);
+
+ //
+ // Create all the TileBuffers and allocate their internal buffers
+ //
+
+ _data->tileOffsets = TileOffsets (_data->tileDesc.mode,
+ _data->numXLevels,
+ _data->numYLevels,
+ _data->numXTiles,
+ _data->numYTiles);
+
+ for (size_t i = 0; i < _data->tileBuffers.size(); i++)
+ _data->tileBuffers[i] = new TileBuffer ();
+
+ _data->maxSampleCountTableSize = _data->tileDesc.ySize *
+ _data->tileDesc.xSize *
+ sizeof(int);
+
+ _data->sampleCountTableBuffer.resizeErase(_data->maxSampleCountTableSize);
+
+ _data->sampleCountTableComp = newCompressor(_data->header.compression(),
+ _data->maxSampleCountTableSize,
+ _data->header);
+
+
+ const ChannelList & c=_data->header.channels();
+ _data->combinedSampleSize=0;
+ for(ChannelList::ConstIterator i=c.begin();i!=c.end();i++)
+ {
+ switch( i.channel().type )
+ {
+ case OPENEXR_IMF_INTERNAL_NAMESPACE::HALF :
+ _data->combinedSampleSize+=Xdr::size<half>();
+ break;
+ case OPENEXR_IMF_INTERNAL_NAMESPACE::FLOAT :
+ _data->combinedSampleSize+=Xdr::size<float>();
+ break;
+ case OPENEXR_IMF_INTERNAL_NAMESPACE::UINT :
+ _data->combinedSampleSize+=Xdr::size<unsigned int>();
+ break;
+ default :
+ THROW(IEX_NAMESPACE::ArgExc, "Bad type for channel " << i.name() << " initializing deepscanline reader");
+ }
+ }
+
+}
+
+
+DeepTiledInputFile::~DeepTiledInputFile ()
+{
+ if (!_data->memoryMapped)
+ for (size_t i = 0; i < _data->tileBuffers.size(); i++)
+ if (_data->tileBuffers[i]->buffer != 0)
+ delete [] _data->tileBuffers[i]->buffer;
+
+ if (_data->_deleteStream)
+ delete _data->_streamData->is;
+
+ //
+ // (TODO) we should have a way to tell if the stream data is owned by this file or
+ // by a parent multipart file.
+ //
+
+ if (_data->partNumber == -1)
+ delete _data->_streamData;
+
+ delete _data;
+}
+
+
+const char *
+DeepTiledInputFile::fileName () const
+{
+ return _data->_streamData->is->fileName();
+}
+
+
+const Header &
+DeepTiledInputFile::header () const
+{
+ return _data->header;
+}
+
+
+int
+DeepTiledInputFile::version () const
+{
+ return _data->version;
+}
+
+
+void
+DeepTiledInputFile::setFrameBuffer (const DeepFrameBuffer &frameBuffer)
+{
+ Lock lock (*_data->_streamData);
+
+ //
+ // Set the frame buffer
+ //
+
+ //
+ // Check if the new frame buffer descriptor is
+ // compatible with the image file header.
+ //
+
+ const ChannelList &channels = _data->header.channels();
+
+ for (DeepFrameBuffer::ConstIterator j = frameBuffer.begin();
+ j != frameBuffer.end();
+ ++j)
+ {
+ ChannelList::ConstIterator i = channels.find (j.name());
+
+ if (i == channels.end())
+ continue;
+
+ if (i.channel().xSampling != j.slice().xSampling ||
+ i.channel().ySampling != j.slice().ySampling)
+ THROW (IEX_NAMESPACE::ArgExc, "X and/or y subsampling factors "
+ "of \"" << i.name() << "\" channel "
+ "of input file \"" << fileName() << "\" are "
+ "not compatible with the frame buffer's "
+ "subsampling factors.");
+ }
+
+ //
+ // Store the pixel sample count table.
+ // (TODO) Support for different sampling rates?
+ //
+
+ const Slice& sampleCountSlice = frameBuffer.getSampleCountSlice();
+ if (sampleCountSlice.base == 0)
+ {
+ throw IEX_NAMESPACE::ArgExc ("Invalid base pointer, please set a proper sample count slice.");
+ }
+ else
+ {
+ _data->sampleCountSliceBase = sampleCountSlice.base;
+ _data->sampleCountXStride = sampleCountSlice.xStride;
+ _data->sampleCountYStride = sampleCountSlice.yStride;
+ _data->sampleCountXTileCoords = sampleCountSlice.xTileCoords;
+ _data->sampleCountYTileCoords = sampleCountSlice.yTileCoords;
+ }
+
+ //
+ // Initialize the slice table for readPixels().
+ //
+
+ vector<TInSliceInfo*> slices;
+ ChannelList::ConstIterator i = channels.begin();
+
+ for (DeepFrameBuffer::ConstIterator j = frameBuffer.begin();
+ j != frameBuffer.end();
+ ++j)
+ {
+ while (i != channels.end() && strcmp (i.name(), j.name()) < 0)
+ {
+ //
+ // Channel i is present in the file but not
+ // in the frame buffer; data for channel i
+ // will be skipped during readPixels().
+ //
+
+ slices.push_back (new TInSliceInfo (i.channel().type,
+ NULL,
+ i.channel().type,
+ 0, // xStride
+ 0, // yStride
+ 0, // sampleStride
+ false, // fill
+ true, // skip
+ 0.0)); // fillValue
+ ++i;
+ }
+
+ bool fill = false;
+
+ if (i == channels.end() || strcmp (i.name(), j.name()) > 0)
+ {
+ //
+ // Channel i is present in the frame buffer, but not in the file.
+ // In the frame buffer, slice j will be filled with a default value.
+ //
+
+ fill = true;
+ }
+
+ slices.push_back (new TInSliceInfo (j.slice().type,
+ j.slice().base,
+ fill? j.slice().type: i.channel().type,
+ j.slice().xStride,
+ j.slice().yStride,
+ j.slice().sampleStride,
+ fill,
+ false, // skip
+ j.slice().fillValue,
+ (j.slice().xTileCoords)? 1: 0,
+ (j.slice().yTileCoords)? 1: 0));
+
+
+ if (i != channels.end() && !fill)
+ ++i;
+ }
+
+ // (TODO) inspect the following code. It's additional to the scanline input file.
+ // Is this needed?
+
+ while (i != channels.end())
+ {
+ //
+ // Channel i is present in the file but not
+ // in the frame buffer; data for channel i
+ // will be skipped during readPixels().
+ //
+
+ slices.push_back (new TInSliceInfo (i.channel().type,
+ NULL,
+ i.channel().type,
+ 0, // xStride
+ 0, // yStride
+ 0, // sampleStride
+ false, // fill
+ true, // skip
+ 0.0)); // fillValue
+ ++i;
+ }
+
+ //
+ // Store the new frame buffer.
+ //
+
+ _data->frameBuffer = frameBuffer;
+
+ for (size_t i = 0; i < _data->slices.size(); i++)
+ delete _data->slices[i];
+ _data->slices = slices;
+}
+
+
+const DeepFrameBuffer &
+DeepTiledInputFile::frameBuffer () const
+{
+ Lock lock (*_data->_streamData);
+ return _data->frameBuffer;
+}
+
+
+bool
+DeepTiledInputFile::isComplete () const
+{
+ return _data->fileIsComplete;
+}
+
+
+void
+DeepTiledInputFile::readTiles (int dx1, int dx2, int dy1, int dy2, int lx, int ly)
+{
+ //
+ // Read a range of tiles from the file into the framebuffer
+ //
+
+ try
+ {
+ Lock lock (*_data->_streamData);
+
+ if (_data->slices.size() == 0)
+ throw IEX_NAMESPACE::ArgExc ("No frame buffer specified "
+ "as pixel data destination.");
+
+ if (!isValidLevel (lx, ly))
+ THROW (IEX_NAMESPACE::ArgExc,
+ "Level coordinate "
+ "(" << lx << ", " << ly << ") "
+ "is invalid.");
+
+ //
+ // Determine the first and last tile coordinates in both dimensions.
+ // We always attempt to read the range of tiles in the order that
+ // they are stored in the file.
+ //
+
+ if (dx1 > dx2)
+ std::swap (dx1, dx2);
+
+ if (dy1 > dy2)
+ std::swap (dy1, dy2);
+
+ int dyStart = dy1;
+ int dyStop = dy2 + 1;
+ int dY = 1;
+
+ if (_data->lineOrder == DECREASING_Y)
+ {
+ dyStart = dy2;
+ dyStop = dy1 - 1;
+ dY = -1;
+ }
+
+ //
+ // Create a task group for all tile buffer tasks. When the
+ // task group goes out of scope, the destructor waits until
+ // all tasks are complete.
+ //
+
+ {
+ TaskGroup taskGroup;
+ int tileNumber = 0;
+
+ for (int dy = dyStart; dy != dyStop; dy += dY)
+ {
+ for (int dx = dx1; dx <= dx2; dx++)
+ {
+ if (!isValidTile (dx, dy, lx, ly))
+ THROW (IEX_NAMESPACE::ArgExc,
+ "Tile (" << dx << ", " << dy << ", " <<
+ lx << "," << ly << ") is not a valid tile.");
+
+ ThreadPool::addGlobalTask (newTileBufferTask (&taskGroup,
+ _data,
+ tileNumber++,
+ dx, dy,
+ lx, ly));
+ }
+ }
+
+ //
+ // finish all tasks
+ //
+ }
+
+ //
+ // Exeption handling:
+ //
+ // TileBufferTask::execute() may have encountered exceptions, but
+ // those exceptions occurred in another thread, not in the thread
+ // that is executing this call to TiledInputFile::readTiles().
+ // TileBufferTask::execute() has caught all exceptions and stored
+ // the exceptions' what() strings in the tile buffers.
+ // Now we check if any tile buffer contains a stored exception; if
+ // this is the case then we re-throw the exception in this thread.
+ // (It is possible that multiple tile buffers contain stored
+ // exceptions. We re-throw the first exception we find and
+ // ignore all others.)
+ //
+
+ const string *exception = 0;
+
+ for (size_t i = 0; i < _data->tileBuffers.size(); ++i)
+ {
+ TileBuffer *tileBuffer = _data->tileBuffers[i];
+
+ if (tileBuffer->hasException && !exception)
+ exception = &tileBuffer->exception;
+
+ tileBuffer->hasException = false;
+ }
+
+ if (exception)
+ throw IEX_NAMESPACE::IoExc (*exception);
+ }
+ catch (IEX_NAMESPACE::BaseExc &e)
+ {
+ REPLACE_EXC (e, "Error reading pixel data from image "
+ "file \"" << fileName() << "\". " << e.what());
+ throw;
+ }
+}
+
+
+void
+DeepTiledInputFile::readTiles (int dx1, int dx2, int dy1, int dy2, int l)
+{
+ readTiles (dx1, dx2, dy1, dy2, l, l);
+}
+
+
+void
+DeepTiledInputFile::readTile (int dx, int dy, int lx, int ly)
+{
+ readTiles (dx, dx, dy, dy, lx, ly);
+}
+
+
+void
+DeepTiledInputFile::readTile (int dx, int dy, int l)
+{
+ readTile (dx, dy, l, l);
+}
+
+
+void
+DeepTiledInputFile::rawTileData (int &dx, int &dy,
+ int &lx, int &ly,
+ char * pixelData,
+ Int64 &pixelDataSize) const
+{
+ if (!isValidTile (dx, dy, lx, ly))
+ throw IEX_NAMESPACE::ArgExc ("Tried to read a tile outside "
+ "the image file's data window.");
+
+ Int64 tileOffset = _data->tileOffsets (dx, dy, lx, ly);
+
+ if(tileOffset == 0)
+ {
+ THROW (IEX_NAMESPACE::InputExc, "Tile (" << dx << ", " << dy << ", " <<
+ lx << ", " << ly << ") is missing.");
+ }
+
+ Lock lock(*_data->_streamData);
+
+ if (_data->_streamData->is->tellg() != tileOffset)
+ _data->_streamData->is->seekg (tileOffset);
+
+
+ //
+ // Read the first few bytes of the tile (the header).
+ // Verify that the tile coordinates and the level number
+ // are correct.
+ //
+
+ int tileXCoord, tileYCoord, levelX, levelY;
+
+ if (isMultiPart(_data->version))
+ {
+ int partNumber;
+ Xdr::read <StreamIO> (*_data->_streamData->is, partNumber);
+ if (partNumber != _data->partNumber)
+ {
+ THROW (IEX_NAMESPACE::ArgExc, "Unexpected part number " << partNumber
+ << ", should be " << _data->partNumber << ".");
+ }
+ }
+
+ Xdr::read <StreamIO> (*_data->_streamData->is, tileXCoord);
+ Xdr::read <StreamIO> (*_data->_streamData->is, tileYCoord);
+ Xdr::read <StreamIO> (*_data->_streamData->is, levelX);
+ Xdr::read <StreamIO> (*_data->_streamData->is, levelY);
+
+ Int64 sampleCountTableSize;
+ Int64 packedDataSize;
+ Xdr::read <StreamIO> (*_data->_streamData->is, sampleCountTableSize);
+
+ Xdr::read <StreamIO> (*_data->_streamData->is, packedDataSize);
+
+
+
+ if (tileXCoord != dx)
+ throw IEX_NAMESPACE::InputExc ("Unexpected tile x coordinate.");
+
+ if (tileYCoord != dy)
+ throw IEX_NAMESPACE::InputExc ("Unexpected tile y coordinate.");
+
+ if (levelX != lx)
+ throw IEX_NAMESPACE::InputExc ("Unexpected tile x level number coordinate.");
+
+ if (levelY != ly)
+ throw IEX_NAMESPACE::InputExc ("Unexpected tile y level number coordinate.");
+
+
+ // total requirement for reading all the data
+
+ Int64 totalSizeRequired=40+sampleCountTableSize+packedDataSize;
+
+ bool big_enough = totalSizeRequired<=pixelDataSize;
+
+ pixelDataSize = totalSizeRequired;
+
+ // was the block we were given big enough?
+ if(!big_enough || pixelData==NULL)
+ {
+ // special case: seek stream back to start if we are at the beginning (regular reading pixels assumes it doesn't need to seek
+ // in single part files)
+ if(!isMultiPart(_data->version))
+ {
+ _data->_streamData->is->seekg(_data->_streamData->currentPosition);
+ }
+ // leave lock here - bail before reading more data
+ return;
+ }
+
+ // copy the values we have read into the output block
+ *(int *) (pixelData+0) = dx;
+ *(int *) (pixelData+4) = dy;
+ *(int *) (pixelData+8) = levelX;
+ *(int *) (pixelData+12) = levelY;
+ *(Int64 *) (pixelData+16) =sampleCountTableSize;
+ *(Int64 *) (pixelData+24) = packedDataSize;
+
+ // didn't read the unpackedsize - do that now
+ Xdr::read<StreamIO> (*_data->_streamData->is, *(Int64 *) (pixelData+32));
+
+ // read the actual data
+ _data->_streamData->is->read(pixelData+40, sampleCountTableSize+packedDataSize);
+
+
+ if(!isMultiPart(_data->version))
+ {
+ _data->_streamData->currentPosition+=sampleCountTableSize+packedDataSize+40;
+ }
+
+ // leave lock here
+
+
+}
+
+
+unsigned int
+DeepTiledInputFile::tileXSize () const
+{
+ return _data->tileDesc.xSize;
+}
+
+
+unsigned int
+DeepTiledInputFile::tileYSize () const
+{
+ return _data->tileDesc.ySize;
+}
+
+
+LevelMode
+DeepTiledInputFile::levelMode () const
+{
+ return _data->tileDesc.mode;
+}
+
+
+LevelRoundingMode
+DeepTiledInputFile::levelRoundingMode () const
+{
+ return _data->tileDesc.roundingMode;
+}
+
+
+int
+DeepTiledInputFile::numLevels () const
+{
+ if (levelMode() == RIPMAP_LEVELS)
+ THROW (IEX_NAMESPACE::LogicExc, "Error calling numLevels() on image "
+ "file \"" << fileName() << "\" "
+ "(numLevels() is not defined for files "
+ "with RIPMAP level mode).");
+
+ return _data->numXLevels;
+}
+
+
+int
+DeepTiledInputFile::numXLevels () const
+{
+ return _data->numXLevels;
+}
+
+
+int
+DeepTiledInputFile::numYLevels () const
+{
+ return _data->numYLevels;
+}
+
+
+bool
+DeepTiledInputFile::isValidLevel (int lx, int ly) const
+{
+ if (lx < 0 || ly < 0)
+ return false;
+
+ if (levelMode() == MIPMAP_LEVELS && lx != ly)
+ return false;
+
+ if (lx >= numXLevels() || ly >= numYLevels())
+ return false;
+
+ return true;
+}
+
+
+int
+DeepTiledInputFile::levelWidth (int lx) const
+{
+ try
+ {
+ return levelSize (_data->minX, _data->maxX, lx,
+ _data->tileDesc.roundingMode);
+ }
+ catch (IEX_NAMESPACE::BaseExc &e)
+ {
+ REPLACE_EXC (e, "Error calling levelWidth() on image "
+ "file \"" << fileName() << "\". " << e.what());
+ throw;
+ }
+}
+
+
+int
+DeepTiledInputFile::levelHeight (int ly) const
+{
+ try
+ {
+ return levelSize (_data->minY, _data->maxY, ly,
+ _data->tileDesc.roundingMode);
+ }
+ catch (IEX_NAMESPACE::BaseExc &e)
+ {
+ REPLACE_EXC (e, "Error calling levelHeight() on image "
+ "file \"" << fileName() << "\". " << e.what());
+ throw;
+ }
+}
+
+
+int
+DeepTiledInputFile::numXTiles (int lx) const
+{
+ if (lx < 0 || lx >= _data->numXLevels)
+ {
+ THROW (IEX_NAMESPACE::ArgExc, "Error calling numXTiles() on image "
+ "file \"" << _data->_streamData->is->fileName() << "\" "
+ "(Argument is not in valid range).");
+
+ }
+
+ return _data->numXTiles[lx];
+}
+
+
+int
+DeepTiledInputFile::numYTiles (int ly) const
+{
+ if (ly < 0 || ly >= _data->numYLevels)
+ {
+ THROW (IEX_NAMESPACE::ArgExc, "Error calling numYTiles() on image "
+ "file \"" << _data->_streamData->is->fileName() << "\" "
+ "(Argument is not in valid range).");
+ }
+
+ return _data->numYTiles[ly];
+}
+
+
+Box2i
+DeepTiledInputFile::dataWindowForLevel (int l) const
+{
+ return dataWindowForLevel (l, l);
+}
+
+
+Box2i
+DeepTiledInputFile::dataWindowForLevel (int lx, int ly) const
+{
+ try
+ {
+ return OPENEXR_IMF_INTERNAL_NAMESPACE::dataWindowForLevel (
+ _data->tileDesc,
+ _data->minX, _data->maxX,
+ _data->minY, _data->maxY,
+ lx, ly);
+ }
+ catch (IEX_NAMESPACE::BaseExc &e)
+ {
+ REPLACE_EXC (e, "Error calling dataWindowForLevel() on image "
+ "file \"" << fileName() << "\". " << e.what());
+ throw;
+ }
+}
+
+
+Box2i
+DeepTiledInputFile::dataWindowForTile (int dx, int dy, int l) const
+{
+ return dataWindowForTile (dx, dy, l, l);
+}
+
+
+Box2i
+DeepTiledInputFile::dataWindowForTile (int dx, int dy, int lx, int ly) const
+{
+ try
+ {
+ if (!isValidTile (dx, dy, lx, ly))
+ throw IEX_NAMESPACE::ArgExc ("Arguments not in valid range.");
+
+ return OPENEXR_IMF_INTERNAL_NAMESPACE::dataWindowForTile (
+ _data->tileDesc,
+ _data->minX, _data->maxX,
+ _data->minY, _data->maxY,
+ dx, dy, lx, ly);
+ }
+ catch (IEX_NAMESPACE::BaseExc &e)
+ {
+ REPLACE_EXC (e, "Error calling dataWindowForTile() on image "
+ "file \"" << fileName() << "\". " << e.what());
+ throw;
+ }
+}
+
+
+bool
+DeepTiledInputFile::isValidTile (int dx, int dy, int lx, int ly) const
+{
+ return ((lx < _data->numXLevels && lx >= 0) &&
+ (ly < _data->numYLevels && ly >= 0) &&
+ (dx < _data->numXTiles[lx] && dx >= 0) &&
+ (dy < _data->numYTiles[ly] && dy >= 0));
+}
+
+
+void
+DeepTiledInputFile::readPixelSampleCounts (int dx1, int dx2,
+ int dy1, int dy2,
+ int lx, int ly)
+{
+ Int64 savedFilePos = 0;
+
+ try
+ {
+ Lock lock (*_data->_streamData);
+
+ savedFilePos = _data->_streamData->is->tellg();
+
+
+ if (!isValidLevel (lx, ly))
+ {
+ THROW (IEX_NAMESPACE::ArgExc,
+ "Level coordinate "
+ "(" << lx << ", " << ly << ") "
+ "is invalid.");
+ }
+
+ if (dx1 > dx2)
+ std::swap (dx1, dx2);
+
+ if (dy1 > dy2)
+ std::swap (dy1, dy2);
+
+ int dyStart = dy1;
+ int dyStop = dy2 + 1;
+ int dY = 1;
+
+ if (_data->lineOrder == DECREASING_Y)
+ {
+ dyStart = dy2;
+ dyStop = dy1 - 1;
+ dY = -1;
+ }
+
+ // (TODO) Check if we have read the sample counts for those tiles,
+ // if we have, no need to read again.
+ for (int dy = dyStart; dy != dyStop; dy += dY)
+ {
+ for (int dx = dx1; dx <= dx2; dx++)
+ {
+
+ if (!isValidTile (dx, dy, lx, ly))
+ {
+ THROW (IEX_NAMESPACE::ArgExc,
+ "Tile (" << dx << ", " << dy << ", " <<
+ lx << "," << ly << ") is not a valid tile.");
+ }
+
+ Box2i tileRange = OPENEXR_IMF_INTERNAL_NAMESPACE::dataWindowForTile (
+ _data->tileDesc,
+ _data->minX, _data->maxX,
+ _data->minY, _data->maxY,
+ dx, dy, lx, ly);
+
+ int xOffset = _data->sampleCountXTileCoords * tileRange.min.x;
+ int yOffset = _data->sampleCountYTileCoords * tileRange.min.y;
+
+ //
+ // Skip and check the tile coordinates.
+ //
+
+ _data->_streamData->is->seekg(_data->tileOffsets(dx, dy, lx, ly));
+
+ if (isMultiPart(_data->version))
+ {
+ int partNumber;
+ Xdr::read <StreamIO> (*_data->_streamData->is, partNumber);
+
+ if (partNumber != _data->partNumber)
+ throw IEX_NAMESPACE::InputExc ("Unexpected part number.");
+ }
+
+ int xInFile, yInFile, lxInFile, lyInFile;
+ Xdr::read <StreamIO> (*_data->_streamData->is, xInFile);
+ Xdr::read <StreamIO> (*_data->_streamData->is, yInFile);
+ Xdr::read <StreamIO> (*_data->_streamData->is, lxInFile);
+ Xdr::read <StreamIO> (*_data->_streamData->is, lyInFile);
+
+ if (xInFile != dx)
+ throw IEX_NAMESPACE::InputExc ("Unexpected tile x coordinate.");
+
+ if (yInFile != dy)
+ throw IEX_NAMESPACE::InputExc ("Unexpected tile y coordinate.");
+
+ if (lxInFile != lx)
+ throw IEX_NAMESPACE::InputExc ("Unexpected tile x level number coordinate.");
+
+ if (lyInFile != ly)
+ throw IEX_NAMESPACE::InputExc ("Unexpected tile y level number coordinate.");
+
+ Int64 tableSize, dataSize, unpackedDataSize;
+ Xdr::read <StreamIO> (*_data->_streamData->is, tableSize);
+ Xdr::read <StreamIO> (*_data->_streamData->is, dataSize);
+ Xdr::read <StreamIO> (*_data->_streamData->is, unpackedDataSize);
+
+
+ if(tableSize>_data->maxSampleCountTableSize)
+ {
+ THROW (IEX_NAMESPACE::ArgExc, "Bad sampleCountTableDataSize read from tile "<< dx << ',' << dy << ',' << lx << ',' << ly << ": expected " << _data->maxSampleCountTableSize << " or less, got "<< tableSize);
+ }
+
+
+ //
+ // We make a check on the data size requirements here.
+ // Whilst we wish to store 64bit sizes on disk, not all the compressors
+ // have been made to work with such data sizes and are still limited to
+ // using signed 32 bit (int) for the data size. As such, this version
+ // insists that we validate that the data size does not exceed the data
+ // type max limit.
+ // @TODO refactor the compressor code to ensure full 64-bit support.
+ //
+
+ Int64 compressorMaxDataSize = Int64(std::numeric_limits<int>::max());
+ if (dataSize > compressorMaxDataSize ||
+ unpackedDataSize > compressorMaxDataSize ||
+ tableSize > compressorMaxDataSize)
+ {
+ THROW (IEX_NAMESPACE::ArgExc, "This version of the library does not"
+ << "support the allocation of data with size > "
+ << compressorMaxDataSize
+ << " file table size :" << tableSize
+ << " file unpacked size :" << unpackedDataSize
+ << " file packed size :" << dataSize << ".\n");
+ }
+
+ //
+ // Read and uncompress the pixel sample count table.
+ //
+
+ _data->_streamData->is->read(_data->sampleCountTableBuffer, tableSize);
+
+ const char* readPtr;
+
+ if (tableSize < _data->maxSampleCountTableSize)
+ {
+ if(!_data->sampleCountTableComp)
+ {
+ THROW(IEX_NAMESPACE::ArgExc,"Deep scanline data corrupt at tile " << dx << ',' << dy << ',' << lx << ',' << ly << " (sampleCountTableDataSize error)");
+ }
+ _data->sampleCountTableComp->uncompress(_data->sampleCountTableBuffer,
+ tableSize,
+ tileRange.min.y,
+ readPtr);
+ }
+ else
+ readPtr = _data->sampleCountTableBuffer;
+
+ size_t cumulative_total_samples =0;
+ int lastAccumulatedCount;
+ for (int j = tileRange.min.y; j <= tileRange.max.y; j++)
+ {
+ lastAccumulatedCount = 0;
+ for (int i = tileRange.min.x; i <= tileRange.max.x; i++)
+ {
+ int accumulatedCount;
+ Xdr::read <CharPtrIO> (readPtr, accumulatedCount);
+
+ if (accumulatedCount < lastAccumulatedCount)
+ {
+ THROW(IEX_NAMESPACE::ArgExc,"Deep tile sampleCount data corrupt at tile "
+ << dx << ',' << dy << ',' << lx << ',' << ly << " (negative sample count detected)");
+ }
+
+ int count = accumulatedCount - lastAccumulatedCount;
+ lastAccumulatedCount = accumulatedCount;
+
+ _data->getSampleCount(i - xOffset, j - yOffset) =count;
+ }
+ cumulative_total_samples += lastAccumulatedCount;
+ }
+
+ if(cumulative_total_samples * _data->combinedSampleSize > unpackedDataSize)
+ {
+ THROW(IEX_NAMESPACE::ArgExc,"Deep scanline sampleCount data corrupt at tile "
+ << dx << ',' << dy << ',' << lx << ',' << ly
+ << ": pixel data only contains " << unpackedDataSize
+ << " bytes of data but table references at least "
+ << cumulative_total_samples*_data->combinedSampleSize << " bytes of sample data" );
+ }
+
+ }
+ }
+
+ _data->_streamData->is->seekg(savedFilePos);
+ }
+ catch (IEX_NAMESPACE::BaseExc &e)
+ {
+ REPLACE_EXC (e, "Error reading sample count data from image "
+ "file \"" << fileName() << "\". " << e.what());
+
+ _data->_streamData->is->seekg(savedFilePos);
+
+ throw;
+ }
+}
+
+
+void
+DeepTiledInputFile::readPixelSampleCount (int dx, int dy, int l)
+{
+ readPixelSampleCount (dx, dy, l, l);
+}
+
+
+void
+DeepTiledInputFile::readPixelSampleCount (int dx, int dy, int lx, int ly)
+{
+ readPixelSampleCounts (dx, dx, dy, dy, lx, ly);
+}
+
+
+void
+DeepTiledInputFile::readPixelSampleCounts (int dx1, int dx2,
+ int dy1, int dy2,
+ int l)
+{
+ readPixelSampleCounts (dx1, dx2, dy1, dy2, l, l);
+}
+
+
+size_t
+DeepTiledInputFile::totalTiles() const
+{
+ //
+ // Calculate the total number of tiles in the file
+ //
+
+ int numAllTiles = 0;
+
+ switch (levelMode ())
+ {
+ case ONE_LEVEL:
+ case MIPMAP_LEVELS:
+
+ for (int i_l = 0; i_l < numLevels (); ++i_l)
+ numAllTiles += numXTiles (i_l) * numYTiles (i_l);
+
+ break;
+
+ case RIPMAP_LEVELS:
+
+ for (int i_ly = 0; i_ly < numYLevels (); ++i_ly)
+ for (int i_lx = 0; i_lx < numXLevels (); ++i_lx)
+ numAllTiles += numXTiles (i_lx) * numYTiles (i_ly);
+
+ break;
+
+ default:
+
+ throw IEX_NAMESPACE::ArgExc ("Unknown LevelMode format.");
+ }
+ return numAllTiles;
+}
+
+
+
+
+void
+DeepTiledInputFile::getTileOrder(int dx[],int dy[],int lx[],int ly[]) const
+{
+ return _data->tileOffsets.getTileOrder(dx,dy,lx,ly);
+
+}
+
+OPENEXR_IMF_INTERNAL_NAMESPACE_SOURCE_EXIT
--- /dev/null
+///////////////////////////////////////////////////////////////////////////
+//
+// Copyright (c) 2011, Industrial Light & Magic, a division of Lucas
+// Digital Ltd. LLC
+//
+// All rights reserved.
+//
+// Redistribution and use in source and binary forms, with or without
+// modification, are permitted provided that the following conditions are
+// met:
+// * Redistributions of source code must retain the above copyright
+// notice, this list of conditions and the following disclaimer.
+// * Redistributions in binary form must reproduce the above
+// copyright notice, this list of conditions and the following disclaimer
+// in the documentation and/or other materials provided with the
+// distribution.
+// * Neither the name of Industrial Light & Magic nor the names of
+// its contributors may be used to endorse or promote products derived
+// from this software without specific prior written permission.
+//
+// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+//
+///////////////////////////////////////////////////////////////////////////
+
+
+#ifndef INCLUDED_IMF_DEEP_TILED_INPUT_FILE_H
+#define INCLUDED_IMF_DEEP_TILED_INPUT_FILE_H
+
+//-----------------------------------------------------------------------------
+//
+// class DeepTiledInputFile
+//
+//-----------------------------------------------------------------------------
+
+#include "ImfHeader.h"
+#include "ImfFrameBuffer.h"
+#include "ImathBox.h"
+#include "ImfTileDescription.h"
+#include "ImfThreading.h"
+#include "ImfGenericInputFile.h"
+#include "ImfDeepFrameBuffer.h"
+#include "ImfDeepTiledOutputFile.h"
+#include "ImfForward.h"
+#include "ImfNamespace.h"
+#include "ImfExport.h"
+
+OPENEXR_IMF_INTERNAL_NAMESPACE_HEADER_ENTER
+
+class DeepTiledInputFile : public GenericInputFile
+{
+ public:
+
+ //--------------------------------------------------------------------
+ // A constructor that opens the file with the specified name, and
+ // reads the file header. The constructor throws an IEX_NAMESPACE::ArgExc
+ // exception if the file is not tiled.
+ // The numThreads parameter specifies how many worker threads this
+ // file will try to keep busy when decompressing individual tiles.
+ // Destroying TiledInputFile objects constructed with this constructor
+ // automatically closes the corresponding files.
+ //--------------------------------------------------------------------
+
+ IMF_EXPORT
+ DeepTiledInputFile (const char fileName[],
+ int numThreads = globalThreadCount ());
+
+
+ // ----------------------------------------------------------
+ // A constructor that attaches the new TiledInputFile object
+ // to a file that has already been opened.
+ // Destroying TiledInputFile objects constructed with this
+ // constructor does not automatically close the corresponding
+ // files.
+ // ----------------------------------------------------------
+
+ IMF_EXPORT
+ DeepTiledInputFile (OPENEXR_IMF_INTERNAL_NAMESPACE::IStream &is, int numThreads = globalThreadCount ());
+
+
+ //-----------
+ // Destructor
+ //-----------
+
+ IMF_EXPORT
+ virtual ~DeepTiledInputFile ();
+
+
+ //------------------------
+ // Access to the file name
+ //------------------------
+
+ IMF_EXPORT
+ const char * fileName () const;
+
+
+ //--------------------------
+ // Access to the file header
+ //--------------------------
+
+ IMF_EXPORT
+ const Header & header () const;
+
+
+ //----------------------------------
+ // Access to the file format version
+ //----------------------------------
+
+ IMF_EXPORT
+ int version () const;
+
+
+ //-----------------------------------------------------------
+ // Set the current frame buffer -- copies the FrameBuffer
+ // object into the TiledInputFile object.
+ //
+ // The current frame buffer is the destination for the pixel
+ // data read from the file. The current frame buffer must be
+ // set at least once before readTile() is called.
+ // The current frame buffer can be changed after each call
+ // to readTile().
+ //-----------------------------------------------------------
+
+ IMF_EXPORT
+ void setFrameBuffer (const DeepFrameBuffer &frameBuffer);
+
+
+ //-----------------------------------
+ // Access to the current frame buffer
+ //-----------------------------------
+
+ IMF_EXPORT
+ const DeepFrameBuffer & frameBuffer () const;
+
+
+ //------------------------------------------------------------
+ // Check if the file is complete:
+ //
+ // isComplete() returns true if all pixels in the data window
+ // (in all levels) are present in the input file, or false if
+ // any pixels are missing. (Another program may still be busy
+ // writing the file, or file writing may have been aborted
+ // prematurely.)
+ //------------------------------------------------------------
+
+ IMF_EXPORT
+ bool isComplete () const;
+
+
+ //--------------------------------------------------
+ // Utility functions:
+ //--------------------------------------------------
+
+ //---------------------------------------------------------
+ // Multiresolution mode and tile size:
+ // The following functions return the xSize, ySize and mode
+ // fields of the file header's TileDescriptionAttribute.
+ //---------------------------------------------------------
+
+ IMF_EXPORT
+ unsigned int tileXSize () const;
+ IMF_EXPORT
+ unsigned int tileYSize () const;
+ IMF_EXPORT
+ LevelMode levelMode () const;
+ IMF_EXPORT
+ LevelRoundingMode levelRoundingMode () const;
+
+
+ //--------------------------------------------------------------------
+ // Number of levels:
+ //
+ // numXLevels() returns the file's number of levels in x direction.
+ //
+ // if levelMode() == ONE_LEVEL:
+ // return value is: 1
+ //
+ // if levelMode() == MIPMAP_LEVELS:
+ // return value is: rfunc (log (max (w, h)) / log (2)) + 1
+ //
+ // if levelMode() == RIPMAP_LEVELS:
+ // return value is: rfunc (log (w) / log (2)) + 1
+ //
+ // where
+ // w is the width of the image's data window, max.x - min.x + 1,
+ // y is the height of the image's data window, max.y - min.y + 1,
+ // and rfunc(x) is either floor(x), or ceil(x), depending on
+ // whether levelRoundingMode() returns ROUND_DOWN or ROUND_UP.
+ //
+ // numYLevels() returns the file's number of levels in y direction.
+ //
+ // if levelMode() == ONE_LEVEL or levelMode() == MIPMAP_LEVELS:
+ // return value is the same as for numXLevels()
+ //
+ // if levelMode() == RIPMAP_LEVELS:
+ // return value is: rfunc (log (h) / log (2)) + 1
+ //
+ //
+ // numLevels() is a convenience function for use with
+ // MIPMAP_LEVELS files.
+ //
+ // if levelMode() == ONE_LEVEL or levelMode() == MIPMAP_LEVELS:
+ // return value is the same as for numXLevels()
+ //
+ // if levelMode() == RIPMAP_LEVELS:
+ // an IEX_NAMESPACE::LogicExc exception is thrown
+ //
+ // isValidLevel(lx, ly) returns true if the file contains
+ // a level with level number (lx, ly), false if not.
+ //
+ // totalTiles() returns the total number of tiles in the image
+ //
+ //--------------------------------------------------------------------
+
+ IMF_EXPORT
+ int numLevels () const;
+ IMF_EXPORT
+ int numXLevels () const;
+ IMF_EXPORT
+ int numYLevels () const;
+ IMF_EXPORT
+ bool isValidLevel (int lx, int ly) const;
+ IMF_EXPORT
+ size_t totalTiles() const;
+
+ //----------------------------------------------------------
+ // Dimensions of a level:
+ //
+ // levelWidth(lx) returns the width of a level with level
+ // number (lx, *), where * is any number.
+ //
+ // return value is:
+ // max (1, rfunc (w / pow (2, lx)))
+ //
+ //
+ // levelHeight(ly) returns the height of a level with level
+ // number (*, ly), where * is any number.
+ //
+ // return value is:
+ // max (1, rfunc (h / pow (2, ly)))
+ //
+ //----------------------------------------------------------
+
+ IMF_EXPORT
+ int levelWidth (int lx) const;
+ IMF_EXPORT
+ int levelHeight (int ly) const;
+
+
+ //--------------------------------------------------------------
+ // Number of tiles:
+ //
+ // numXTiles(lx) returns the number of tiles in x direction
+ // that cover a level with level number (lx, *), where * is
+ // any number.
+ //
+ // return value is:
+ // (levelWidth(lx) + tileXSize() - 1) / tileXSize()
+ //
+ //
+ // numYTiles(ly) returns the number of tiles in y direction
+ // that cover a level with level number (*, ly), where * is
+ // any number.
+ //
+ // return value is:
+ // (levelHeight(ly) + tileXSize() - 1) / tileXSize()
+ //
+ //--------------------------------------------------------------
+
+ IMF_EXPORT
+ int numXTiles (int lx = 0) const;
+ IMF_EXPORT
+ int numYTiles (int ly = 0) const;
+
+
+ //---------------------------------------------------------------
+ // Level pixel ranges:
+ //
+ // dataWindowForLevel(lx, ly) returns a 2-dimensional region of
+ // valid pixel coordinates for a level with level number (lx, ly)
+ //
+ // return value is a Box2i with min value:
+ // (dataWindow.min.x, dataWindow.min.y)
+ //
+ // and max value:
+ // (dataWindow.min.x + levelWidth(lx) - 1,
+ // dataWindow.min.y + levelHeight(ly) - 1)
+ //
+ // dataWindowForLevel(level) is a convenience function used
+ // for ONE_LEVEL and MIPMAP_LEVELS files. It returns
+ // dataWindowForLevel(level, level).
+ //
+ //---------------------------------------------------------------
+
+ IMF_EXPORT
+ IMATH_NAMESPACE::Box2i dataWindowForLevel (int l = 0) const;
+ IMF_EXPORT
+ IMATH_NAMESPACE::Box2i dataWindowForLevel (int lx, int ly) const;
+
+
+ //-------------------------------------------------------------------
+ // Tile pixel ranges:
+ //
+ // dataWindowForTile(dx, dy, lx, ly) returns a 2-dimensional
+ // region of valid pixel coordinates for a tile with tile coordinates
+ // (dx,dy) and level number (lx, ly).
+ //
+ // return value is a Box2i with min value:
+ // (dataWindow.min.x + dx * tileXSize(),
+ // dataWindow.min.y + dy * tileYSize())
+ //
+ // and max value:
+ // (dataWindow.min.x + (dx + 1) * tileXSize() - 1,
+ // dataWindow.min.y + (dy + 1) * tileYSize() - 1)
+ //
+ // dataWindowForTile(dx, dy, level) is a convenience function
+ // used for ONE_LEVEL and MIPMAP_LEVELS files. It returns
+ // dataWindowForTile(dx, dy, level, level).
+ //
+ //-------------------------------------------------------------------
+
+ IMF_EXPORT
+ IMATH_NAMESPACE::Box2i dataWindowForTile (int dx, int dy, int l = 0) const;
+
+ IMF_EXPORT
+ IMATH_NAMESPACE::Box2i dataWindowForTile (int dx, int dy,
+ int lx, int ly) const;
+
+ //------------------------------------------------------------
+ // Read pixel data:
+ //
+ // readTile(dx, dy, lx, ly) reads the tile with tile
+ // coordinates (dx, dy), and level number (lx, ly),
+ // and stores it in the current frame buffer.
+ //
+ // dx must lie in the interval [0, numXTiles(lx)-1]
+ // dy must lie in the interval [0, numYTiles(ly)-1]
+ //
+ // lx must lie in the interval [0, numXLevels()-1]
+ // ly must lie in the inverval [0, numYLevels()-1]
+ //
+ // readTile(dx, dy, level) is a convenience function used
+ // for ONE_LEVEL and MIPMAP_LEVELS files. It calls
+ // readTile(dx, dy, level, level).
+ //
+ // The two readTiles(dx1, dx2, dy1, dy2, ...) functions allow
+ // reading multiple tiles at once. If multi-threading is used
+ // the multiple tiles are read concurrently.
+ //
+ // Pixels that are outside the pixel coordinate range for the
+ // tile's level, are never accessed by readTile().
+ //
+ // Attempting to access a tile that is not present in the file
+ // throws an InputExc exception.
+ //
+ //------------------------------------------------------------
+
+ IMF_EXPORT
+ void readTile (int dx, int dy, int l = 0);
+ IMF_EXPORT
+ void readTile (int dx, int dy, int lx, int ly);
+
+ IMF_EXPORT
+ void readTiles (int dx1, int dx2, int dy1, int dy2,
+ int lx, int ly);
+
+ IMF_EXPORT
+ void readTiles (int dx1, int dx2, int dy1, int dy2,
+ int l = 0);
+
+
+ //--------------------------------------------------
+ // Read a tile of raw pixel data from the file,
+ // without uncompressing it (this function is
+ // used to implement TiledOutputFile::copyPixels()).
+ //--------------------------------------------------
+
+ IMF_EXPORT
+ void rawTileData (int &dx, int &dy,
+ int &lx, int &ly,
+ char *pixelData,
+ Int64 &dataSize) const;
+
+ //------------------------------------------------------------------
+ // Read pixel sample counts into a slice in the frame buffer.
+ //
+ // readPixelSampleCount(dx, dy, lx, ly) reads the sample counts
+ // for tile (dx, dy) in level (lx, ly).
+ //
+ // readPixelSampleCount(dx, dy, l) calls
+ // readPixelSampleCount(dx, dy, lx = l, ly = l)
+ //
+ // dx must lie in the interval [0, numXTiles(lx)-1]
+ // dy must lie in the interval [0, numYTiles(ly)-1]
+ //
+ // lx must lie in the interval [0, numXLevels()-1]
+ // ly must lie in the inverval [0, numYLevels()-1]
+ //
+ // readPixelSampleCounts(dx1, dx2, dy1, dy2, lx, ly) reads all
+ // the sample counts for tiles within range
+ // [(min(dx1, dx2), min(dy1, dy2))...(max(dx1, dx2), max(dy1, dy2)],
+ // and on level (lx, ly)
+ //
+ // readPixelSampleCounts(dx1, dx2, dy1, dy2, l) calls
+ // readPixelSampleCounts(dx1, dx2, dy1, dy2, lx = l, ly = l).
+ //------------------------------------------------------------------
+
+ IMF_EXPORT
+ void readPixelSampleCount (int dx, int dy, int l = 0);
+ IMF_EXPORT
+ void readPixelSampleCount (int dx, int dy, int lx, int ly);
+
+ IMF_EXPORT
+ void readPixelSampleCounts (int dx1, int dx2,
+ int dy1, int dy2,
+ int lx, int ly);
+
+ IMF_EXPORT
+ void readPixelSampleCounts (int dx1, int dx2,
+ int dy1, int dy2,
+ int l = 0);
+
+ struct Data;
+
+
+
+ private:
+
+ friend class InputFile;
+ friend class MultiPartInputFile;
+
+ DeepTiledInputFile (InputPartData* part);
+
+ DeepTiledInputFile (const DeepTiledInputFile &); // not implemented
+ DeepTiledInputFile & operator = (const DeepTiledInputFile &); // not implemented
+
+ DeepTiledInputFile (const Header &header, OPENEXR_IMF_INTERNAL_NAMESPACE::IStream *is, int version,
+ int numThreads);
+
+ void initialize ();
+ void multiPartInitialize(InputPartData* part);
+ void compatibilityInitialize(OPENEXR_IMF_INTERNAL_NAMESPACE::IStream& is);
+
+ bool isValidTile (int dx, int dy,
+ int lx, int ly) const;
+
+ size_t bytesPerLineForTile (int dx, int dy,
+ int lx, int ly) const;
+
+
+ void getTileOrder(int dx[],int dy[],int lx[],int ly[]) const;
+
+
+ Data * _data;
+
+
+ // needed for copyPixels
+ friend void DeepTiledOutputFile::copyPixels(DeepTiledInputFile &);
+};
+
+OPENEXR_IMF_INTERNAL_NAMESPACE_HEADER_EXIT
+
+#endif
--- /dev/null
+///////////////////////////////////////////////////////////////////////////
+//
+// Copyright (c) 2011, Industrial Light & Magic, a division of Lucas
+// Digital Ltd. LLC
+//
+// All rights reserved.
+//
+// Redistribution and use in source and binary forms, with or without
+// modification, are permitted provided that the following conditions are
+// met:
+// * Redistributions of source code must retain the above copyright
+// notice, this list of conditions and the following disclaimer.
+// * Redistributions in binary form must reproduce the above
+// copyright notice, this list of conditions and the following disclaimer
+// in the documentation and/or other materials provided with the
+// distribution.
+// * Neither the name of Industrial Light & Magic nor the names of
+// its contributors may be used to endorse or promote products derived
+// from this software without specific prior written permission.
+//
+// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+//
+///////////////////////////////////////////////////////////////////////////
+
+
+#include "ImfDeepTiledInputPart.h"
+#include "ImfMultiPartInputFile.h"
+#include "ImfNamespace.h"
+
+OPENEXR_IMF_INTERNAL_NAMESPACE_SOURCE_ENTER
+
+DeepTiledInputPart::DeepTiledInputPart(MultiPartInputFile& multiPartFile, int partNumber)
+{
+ file = multiPartFile.getInputPart<DeepTiledInputFile>(partNumber);
+}
+
+
+const char *
+DeepTiledInputPart::fileName () const
+{
+ return file->fileName();
+}
+
+
+const Header &
+DeepTiledInputPart::header () const
+{
+ return file->header();
+}
+
+
+int
+DeepTiledInputPart::version () const
+{
+ return file->version();
+}
+
+
+void
+DeepTiledInputPart::setFrameBuffer (const DeepFrameBuffer &frameBuffer)
+{
+ file->setFrameBuffer(frameBuffer);
+}
+
+
+const DeepFrameBuffer &
+DeepTiledInputPart::frameBuffer () const
+{
+ return file->frameBuffer();
+}
+
+
+bool
+DeepTiledInputPart::isComplete () const
+{
+ return file->isComplete();
+}
+
+
+unsigned int
+DeepTiledInputPart::tileXSize () const
+{
+ return file->tileXSize();
+}
+
+
+unsigned int
+DeepTiledInputPart::tileYSize () const
+{
+ return file->tileYSize();
+}
+
+
+LevelMode
+DeepTiledInputPart::levelMode () const
+{
+ return file->levelMode();
+}
+
+
+LevelRoundingMode
+DeepTiledInputPart::levelRoundingMode () const
+{
+ return file->levelRoundingMode();
+}
+
+
+int
+DeepTiledInputPart::numLevels () const
+{
+ return file->numLevels();
+}
+
+
+int
+DeepTiledInputPart::numXLevels () const
+{
+ return file->numXLevels();
+}
+
+
+int
+DeepTiledInputPart::numYLevels () const
+{
+ return file->numYLevels();
+}
+
+
+bool
+DeepTiledInputPart::isValidLevel (int lx, int ly) const
+{
+ return file->isValidLevel(lx, ly);
+}
+
+
+int
+DeepTiledInputPart::levelWidth (int lx) const
+{
+ return file->levelWidth(lx);
+}
+
+
+int
+DeepTiledInputPart::levelHeight (int ly) const
+{
+ return file->levelHeight(ly);
+}
+
+
+int
+DeepTiledInputPart::numXTiles (int lx) const
+{
+ return file->numXTiles(lx);
+}
+
+
+int
+DeepTiledInputPart::numYTiles (int ly) const
+{
+ return file->numYTiles(ly);
+}
+
+
+IMATH_NAMESPACE::Box2i
+DeepTiledInputPart::dataWindowForLevel (int l) const
+{
+ return file->dataWindowForLevel(l);
+}
+
+IMATH_NAMESPACE::Box2i
+DeepTiledInputPart::dataWindowForLevel (int lx, int ly) const
+{
+ return file->dataWindowForLevel(lx, ly);
+}
+
+
+IMATH_NAMESPACE::Box2i
+DeepTiledInputPart::dataWindowForTile (int dx, int dy, int l) const
+{
+ return file->dataWindowForTile(dx, dy, l);
+}
+
+
+IMATH_NAMESPACE::Box2i
+DeepTiledInputPart::dataWindowForTile (int dx, int dy,
+ int lx, int ly) const
+{
+ return file->dataWindowForTile(dx, dy, lx, ly);
+}
+
+
+void
+DeepTiledInputPart::readTile (int dx, int dy, int l)
+{
+ file->readTile(dx, dy, l);
+}
+
+
+void
+DeepTiledInputPart::readTile (int dx, int dy, int lx, int ly)
+{
+ file->readTile(dx, dy, lx, ly);
+}
+
+
+void
+DeepTiledInputPart::readTiles (int dx1, int dx2, int dy1, int dy2,
+ int lx, int ly)
+{
+ file->readTiles(dx1, dx2, dy1, dy2, lx, ly);
+}
+
+
+void
+DeepTiledInputPart::readTiles (int dx1, int dx2, int dy1, int dy2,
+ int l)
+{
+ file->readTiles(dx1, dx2, dy1, dy2, l);
+}
+
+
+void
+DeepTiledInputPart::rawTileData (int &dx, int &dy,
+ int &lx, int &ly,
+ char * pixelData,
+ Int64 & dataSize) const
+{
+ file->rawTileData(dx, dy, lx, ly, pixelData, dataSize );
+}
+
+
+void
+DeepTiledInputPart::readPixelSampleCount (int dx, int dy, int l)
+{
+ file->readPixelSampleCount(dx, dy, l);
+}
+
+
+void
+DeepTiledInputPart::readPixelSampleCount (int dx, int dy, int lx, int ly)
+{
+ file->readPixelSampleCount(dx, dy, lx, ly);
+}
+
+
+void
+DeepTiledInputPart::readPixelSampleCounts (int dx1, int dx2,
+ int dy1, int dy2,
+ int lx, int ly)
+{
+ file->readPixelSampleCounts(dx1, dx2, dy1, dy2, lx, ly);
+}
+
+void
+DeepTiledInputPart::readPixelSampleCounts (int dx1, int dx2,
+ int dy1, int dy2,
+ int l)
+{
+ file->readPixelSampleCounts(dx1, dx2, dy1, dy2, l);
+}
+
+
+OPENEXR_IMF_INTERNAL_NAMESPACE_SOURCE_EXIT
--- /dev/null
+///////////////////////////////////////////////////////////////////////////
+//
+// Copyright (c) 2011, Industrial Light & Magic, a division of Lucas
+// Digital Ltd. LLC
+//
+// All rights reserved.
+//
+// Redistribution and use in source and binary forms, with or without
+// modification, are permitted provided that the following conditions are
+// met:
+// * Redistributions of source code must retain the above copyright
+// notice, this list of conditions and the following disclaimer.
+// * Redistributions in binary form must reproduce the above
+// copyright notice, this list of conditions and the following disclaimer
+// in the documentation and/or other materials provided with the
+// distribution.
+// * Neither the name of Industrial Light & Magic nor the names of
+// its contributors may be used to endorse or promote products derived
+// from this software without specific prior written permission.
+//
+// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+//
+///////////////////////////////////////////////////////////////////////////
+
+
+#ifndef IMFDEEPTILEDINPUTPART_H_
+#define IMFDEEPTILEDINPUTPART_H_
+
+#include "ImfDeepTiledInputFile.h"
+#include "ImfNamespace.h"
+#include "ImfForward.h"
+#include "ImfExport.h"
+
+OPENEXR_IMF_INTERNAL_NAMESPACE_HEADER_ENTER
+
+class DeepTiledInputPart
+{
+ public:
+
+ IMF_EXPORT
+ DeepTiledInputPart(MultiPartInputFile& multiPartFile, int partNumber);
+
+ //------------------------
+ // Access to the file name
+ //------------------------
+
+ IMF_EXPORT
+ const char * fileName () const;
+
+
+ //--------------------------
+ // Access to the file header
+ //--------------------------
+
+ IMF_EXPORT
+ const Header & header () const;
+
+
+ //----------------------------------
+ // Access to the file format version
+ //----------------------------------
+
+ IMF_EXPORT
+ int version () const;
+
+
+ //-----------------------------------------------------------
+ // Set the current frame buffer -- copies the FrameBuffer
+ // object into the TiledInputFile object.
+ //
+ // The current frame buffer is the destination for the pixel
+ // data read from the file. The current frame buffer must be
+ // set at least once before readTile() is called.
+ // The current frame buffer can be changed after each call
+ // to readTile().
+ //-----------------------------------------------------------
+
+ IMF_EXPORT
+ void setFrameBuffer (const DeepFrameBuffer &frameBuffer);
+
+
+ //-----------------------------------
+ // Access to the current frame buffer
+ //-----------------------------------
+
+ IMF_EXPORT
+ const DeepFrameBuffer & frameBuffer () const;
+
+
+ //------------------------------------------------------------
+ // Check if the file is complete:
+ //
+ // isComplete() returns true if all pixels in the data window
+ // (in all levels) are present in the input file, or false if
+ // any pixels are missing. (Another program may still be busy
+ // writing the file, or file writing may have been aborted
+ // prematurely.)
+ //------------------------------------------------------------
+
+ IMF_EXPORT
+ bool isComplete () const;
+
+
+ //--------------------------------------------------
+ // Utility functions:
+ //--------------------------------------------------
+
+ //---------------------------------------------------------
+ // Multiresolution mode and tile size:
+ // The following functions return the xSize, ySize and mode
+ // fields of the file header's TileDescriptionAttribute.
+ //---------------------------------------------------------
+
+ IMF_EXPORT
+ unsigned int tileXSize () const;
+ IMF_EXPORT
+ unsigned int tileYSize () const;
+ IMF_EXPORT
+ LevelMode levelMode () const;
+ IMF_EXPORT
+ LevelRoundingMode levelRoundingMode () const;
+
+
+ //--------------------------------------------------------------------
+ // Number of levels:
+ //
+ // numXLevels() returns the file's number of levels in x direction.
+ //
+ // if levelMode() == ONE_LEVEL:
+ // return value is: 1
+ //
+ // if levelMode() == MIPMAP_LEVELS:
+ // return value is: rfunc (log (max (w, h)) / log (2)) + 1
+ //
+ // if levelMode() == RIPMAP_LEVELS:
+ // return value is: rfunc (log (w) / log (2)) + 1
+ //
+ // where
+ // w is the width of the image's data window, max.x - min.x + 1,
+ // y is the height of the image's data window, max.y - min.y + 1,
+ // and rfunc(x) is either floor(x), or ceil(x), depending on
+ // whether levelRoundingMode() returns ROUND_DOWN or ROUND_UP.
+ //
+ // numYLevels() returns the file's number of levels in y direction.
+ //
+ // if levelMode() == ONE_LEVEL or levelMode() == MIPMAP_LEVELS:
+ // return value is the same as for numXLevels()
+ //
+ // if levelMode() == RIPMAP_LEVELS:
+ // return value is: rfunc (log (h) / log (2)) + 1
+ //
+ //
+ // numLevels() is a convenience function for use with
+ // MIPMAP_LEVELS files.
+ //
+ // if levelMode() == ONE_LEVEL or levelMode() == MIPMAP_LEVELS:
+ // return value is the same as for numXLevels()
+ //
+ // if levelMode() == RIPMAP_LEVELS:
+ // an IEX_NAMESPACE::LogicExc exception is thrown
+ //
+ // isValidLevel(lx, ly) returns true if the file contains
+ // a level with level number (lx, ly), false if not.
+ //
+ //--------------------------------------------------------------------
+
+ IMF_EXPORT
+ int numLevels () const;
+ IMF_EXPORT
+ int numXLevels () const;
+ IMF_EXPORT
+ int numYLevels () const;
+ IMF_EXPORT
+ bool isValidLevel (int lx, int ly) const;
+
+
+ //----------------------------------------------------------
+ // Dimensions of a level:
+ //
+ // levelWidth(lx) returns the width of a level with level
+ // number (lx, *), where * is any number.
+ //
+ // return value is:
+ // max (1, rfunc (w / pow (2, lx)))
+ //
+ //
+ // levelHeight(ly) returns the height of a level with level
+ // number (*, ly), where * is any number.
+ //
+ // return value is:
+ // max (1, rfunc (h / pow (2, ly)))
+ //
+ //----------------------------------------------------------
+
+ IMF_EXPORT
+ int levelWidth (int lx) const;
+ IMF_EXPORT
+ int levelHeight (int ly) const;
+
+
+ //--------------------------------------------------------------
+ // Number of tiles:
+ //
+ // numXTiles(lx) returns the number of tiles in x direction
+ // that cover a level with level number (lx, *), where * is
+ // any number.
+ //
+ // return value is:
+ // (levelWidth(lx) + tileXSize() - 1) / tileXSize()
+ //
+ //
+ // numYTiles(ly) returns the number of tiles in y direction
+ // that cover a level with level number (*, ly), where * is
+ // any number.
+ //
+ // return value is:
+ // (levelHeight(ly) + tileXSize() - 1) / tileXSize()
+ //
+ //--------------------------------------------------------------
+
+ IMF_EXPORT
+ int numXTiles (int lx = 0) const;
+ IMF_EXPORT
+ int numYTiles (int ly = 0) const;
+
+
+ //---------------------------------------------------------------
+ // Level pixel ranges:
+ //
+ // dataWindowForLevel(lx, ly) returns a 2-dimensional region of
+ // valid pixel coordinates for a level with level number (lx, ly)
+ //
+ // return value is a Box2i with min value:
+ // (dataWindow.min.x, dataWindow.min.y)
+ //
+ // and max value:
+ // (dataWindow.min.x + levelWidth(lx) - 1,
+ // dataWindow.min.y + levelHeight(ly) - 1)
+ //
+ // dataWindowForLevel(level) is a convenience function used
+ // for ONE_LEVEL and MIPMAP_LEVELS files. It returns
+ // dataWindowForLevel(level, level).
+ //
+ //---------------------------------------------------------------
+
+ IMF_EXPORT
+ IMATH_NAMESPACE::Box2i dataWindowForLevel (int l = 0) const;
+ IMF_EXPORT
+ IMATH_NAMESPACE::Box2i dataWindowForLevel (int lx, int ly) const;
+
+
+ //-------------------------------------------------------------------
+ // Tile pixel ranges:
+ //
+ // dataWindowForTile(dx, dy, lx, ly) returns a 2-dimensional
+ // region of valid pixel coordinates for a tile with tile coordinates
+ // (dx,dy) and level number (lx, ly).
+ //
+ // return value is a Box2i with min value:
+ // (dataWindow.min.x + dx * tileXSize(),
+ // dataWindow.min.y + dy * tileYSize())
+ //
+ // and max value:
+ // (dataWindow.min.x + (dx + 1) * tileXSize() - 1,
+ // dataWindow.min.y + (dy + 1) * tileYSize() - 1)
+ //
+ // dataWindowForTile(dx, dy, level) is a convenience function
+ // used for ONE_LEVEL and MIPMAP_LEVELS files. It returns
+ // dataWindowForTile(dx, dy, level, level).
+ //
+ //-------------------------------------------------------------------
+
+ IMF_EXPORT
+ IMATH_NAMESPACE::Box2i dataWindowForTile (int dx, int dy, int l = 0) const;
+
+ IMF_EXPORT
+ IMATH_NAMESPACE::Box2i dataWindowForTile (int dx, int dy,
+ int lx, int ly) const;
+
+ //------------------------------------------------------------
+ // Read pixel data:
+ //
+ // readTile(dx, dy, lx, ly) reads the tile with tile
+ // coordinates (dx, dy), and level number (lx, ly),
+ // and stores it in the current frame buffer.
+ //
+ // dx must lie in the interval [0, numXTiles(lx)-1]
+ // dy must lie in the interval [0, numYTiles(ly)-1]
+ //
+ // lx must lie in the interval [0, numXLevels()-1]
+ // ly must lie in the inverval [0, numYLevels()-1]
+ //
+ // readTile(dx, dy, level) is a convenience function used
+ // for ONE_LEVEL and MIPMAP_LEVELS files. It calls
+ // readTile(dx, dy, level, level).
+ //
+ // The two readTiles(dx1, dx2, dy1, dy2, ...) functions allow
+ // reading multiple tiles at once. If multi-threading is used
+ // the multiple tiles are read concurrently.
+ //
+ // Pixels that are outside the pixel coordinate range for the
+ // tile's level, are never accessed by readTile().
+ //
+ // Attempting to access a tile that is not present in the file
+ // throws an InputExc exception.
+ //
+ //------------------------------------------------------------
+
+ IMF_EXPORT
+ void readTile (int dx, int dy, int l = 0);
+ IMF_EXPORT
+ void readTile (int dx, int dy, int lx, int ly);
+
+ IMF_EXPORT
+ void readTiles (int dx1, int dx2, int dy1, int dy2,
+ int lx, int ly);
+
+ IMF_EXPORT
+ void readTiles (int dx1, int dx2, int dy1, int dy2,
+ int l = 0);
+
+
+ //--------------------------------------------------
+ // Read a tile of raw pixel data from the file,
+ // without uncompressing it (this function is
+ // used to implement TiledOutputFile::copyPixels()).
+ //--------------------------------------------------
+
+ IMF_EXPORT
+ void rawTileData (int &dx, int &dy,
+ int &lx, int &ly,
+ char *data,
+ Int64 &dataSize
+ ) const;
+
+ //------------------------------------------------------------------
+ // Read pixel sample counts into a slice in the frame buffer.
+ //
+ // readPixelSampleCount(dx, dy, lx, ly) reads the sample counts
+ // for tile (dx, dy) in level (lx, ly).
+ //
+ // readPixelSampleCount(dx, dy, l) calls
+ // readPixelSampleCount(dx, dy, lx = l, ly = l)
+ //
+ // dx must lie in the interval [0, numXTiles(lx)-1]
+ // dy must lie in the interval [0, numYTiles(ly)-1]
+ //
+ // lx must lie in the interval [0, numXLevels()-1]
+ // ly must lie in the inverval [0, numYLevels()-1]
+ //
+ // readPixelSampleCounts(dx1, dx2, dy1, dy2, lx, ly) reads all
+ // the sample counts for tiles within range
+ // [(min(dx1, dx2), min(dy1, dy2))...(max(dx1, dx2), max(dy1, dy2)],
+ // and on level (lx, ly)
+ //
+ // readPixelSampleCounts(dx1, dx2, dy1, dy2, l) calls
+ // readPixelSampleCounts(dx1, dx2, dy1, dy2, lx = l, ly = l).
+ //------------------------------------------------------------------
+
+ IMF_EXPORT
+ void readPixelSampleCount (int dx, int dy, int l = 0);
+ IMF_EXPORT
+ void readPixelSampleCount (int dx, int dy, int lx, int ly);
+
+ IMF_EXPORT
+ void readPixelSampleCounts (int dx1, int dx2,
+ int dy1, int dy2,
+ int lx, int ly);
+
+ IMF_EXPORT
+ void readPixelSampleCounts (int dx1, int dx2,
+ int dy1, int dy2,
+ int l = 0);
+
+ private:
+ DeepTiledInputFile* file;
+
+ friend void DeepTiledOutputFile::copyPixels(DeepTiledInputPart &);
+};
+
+OPENEXR_IMF_INTERNAL_NAMESPACE_HEADER_EXIT
+
+
+#endif /* IMFDEEPTILEDINPUTPART_H_ */
--- /dev/null
+///////////////////////////////////////////////////////////////////////////
+//
+// Copyright (c) 2011, Industrial Light & Magic, a division of Lucas
+// Digital Ltd. LLC
+//
+// All rights reserved.
+//
+// Redistribution and use in source and binary forms, with or without
+// modification, are permitted provided that the following conditions are
+// met:
+// * Redistributions of source code must retain the above copyright
+// notice, this list of conditions and the following disclaimer.
+// * Redistributions in binary form must reproduce the above
+// copyright notice, this list of conditions and the following disclaimer
+// in the documentation and/or other materials provided with the
+// distribution.
+// * Neither the name of Industrial Light & Magic nor the names of
+// its contributors may be used to endorse or promote products derived
+// from this software without specific prior written permission.
+//
+// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+//
+///////////////////////////////////////////////////////////////////////////
+
+//-----------------------------------------------------------------------------
+//
+// class DeepTiledOutputFile
+//
+//-----------------------------------------------------------------------------
+
+#include "ImfDeepTiledOutputFile.h"
+#include "ImfDeepTiledInputFile.h"
+#include "ImfDeepTiledInputPart.h"
+#include "ImfInputFile.h"
+#include "ImfTileDescriptionAttribute.h"
+#include "ImfPreviewImageAttribute.h"
+#include "ImfChannelList.h"
+#include "ImfMisc.h"
+#include "ImfTiledMisc.h"
+#include "ImfStdIO.h"
+#include "ImfCompressor.h"
+#include "ImfOutputStreamMutex.h"
+#include "ImfOutputPartData.h"
+#include "ImfArray.h"
+#include "ImfXdr.h"
+#include "ImfVersion.h"
+#include "ImfTileOffsets.h"
+#include "ImfThreading.h"
+#include "ImfPartType.h"
+
+#include "ImathBox.h"
+
+#include "IlmThreadPool.h"
+#include "IlmThreadSemaphore.h"
+#include "IlmThreadMutex.h"
+
+#include "Iex.h"
+
+#include <string>
+#include <vector>
+#include <fstream>
+#include <assert.h>
+#include <map>
+#include <algorithm>
+
+#include "ImfNamespace.h"
+
+OPENEXR_IMF_INTERNAL_NAMESPACE_SOURCE_ENTER
+
+using IMATH_NAMESPACE::Box2i;
+using IMATH_NAMESPACE::V2i;
+using std::string;
+using std::vector;
+using std::ofstream;
+using std::map;
+using std::min;
+using std::max;
+using std::swap;
+using ILMTHREAD_NAMESPACE::Mutex;
+using ILMTHREAD_NAMESPACE::Lock;
+using ILMTHREAD_NAMESPACE::Semaphore;
+using ILMTHREAD_NAMESPACE::Task;
+using ILMTHREAD_NAMESPACE::TaskGroup;
+using ILMTHREAD_NAMESPACE::ThreadPool;
+
+namespace {
+
+struct TOutSliceInfo
+{
+ PixelType type;
+ const char * base;
+ size_t sampleStride;
+ size_t xStride;
+ size_t yStride;
+ bool zero;
+ int xTileCoords;
+ int yTileCoords;
+
+ TOutSliceInfo (PixelType type = HALF,
+ size_t sampleStride = 0,
+ size_t xStride = 0,
+ size_t yStride = 0,
+ bool zero = false,
+ int xTileCoords = 0,
+ int yTileCoords = 0);
+};
+
+
+TOutSliceInfo::TOutSliceInfo (PixelType t,
+ size_t spst,
+ size_t xStride,
+ size_t yStride,
+ bool z,
+ int xtc,
+ int ytc)
+:
+ type (t),
+ sampleStride (spst),
+ xStride(xStride),
+ yStride(yStride),
+ zero (z),
+ xTileCoords (xtc),
+ yTileCoords (ytc)
+{
+ // empty
+}
+
+
+struct TileCoord
+{
+ int dx;
+ int dy;
+ int lx;
+ int ly;
+
+
+ TileCoord (int xTile = 0, int yTile = 0,
+ int xLevel = 0, int yLevel = 0)
+ :
+ dx (xTile), dy (yTile),
+ lx (xLevel), ly (yLevel)
+ {
+ // empty
+ }
+
+
+ bool
+ operator < (const TileCoord &other) const
+ {
+ return (ly < other.ly) ||
+ (ly == other.ly && lx < other.lx) ||
+ ((ly == other.ly && lx == other.lx) &&
+ ((dy < other.dy) || (dy == other.dy && dx < other.dx)));
+ }
+
+
+ bool
+ operator == (const TileCoord &other) const
+ {
+ return lx == other.lx &&
+ ly == other.ly &&
+ dx == other.dx &&
+ dy == other.dy;
+ }
+};
+
+
+struct BufferedTile
+{
+ char * pixelData;
+ Int64 pixelDataSize;
+ Int64 unpackedDataSize;
+ char * sampleCountTableData;
+ Int64 sampleCountTableSize;
+
+ BufferedTile (const char *data, int size, int unpackedSize,
+ const char *tableData, int tableSize):
+ pixelData (0),
+ pixelDataSize(size),
+ unpackedDataSize(unpackedSize),
+ sampleCountTableData(0),
+ sampleCountTableSize(tableSize)
+ {
+ pixelData = new char[pixelDataSize];
+ memcpy (pixelData, data, pixelDataSize);
+
+ sampleCountTableData = new char[tableSize];
+ memcpy (sampleCountTableData, tableData, tableSize);
+ }
+
+ ~BufferedTile()
+ {
+ delete [] pixelData;
+ delete [] sampleCountTableData;
+ }
+};
+
+
+typedef map <TileCoord, BufferedTile *> TileMap;
+
+
+struct TileBuffer
+{
+ Array<char> buffer;
+ const char * dataPtr;
+ Int64 dataSize;
+ Int64 uncompressedSize;
+ Compressor * compressor;
+ Array<char> sampleCountTableBuffer;
+ const char * sampleCountTablePtr;
+ Int64 sampleCountTableSize;
+ Compressor* sampleCountTableCompressor;
+ TileCoord tileCoord;
+ bool hasException;
+ string exception;
+
+ TileBuffer ();
+ ~TileBuffer ();
+
+ inline void wait () {_sem.wait();}
+ inline void post () {_sem.post();}
+
+ protected:
+
+ Semaphore _sem;
+};
+
+
+TileBuffer::TileBuffer ():
+ dataPtr (0),
+ dataSize (0),
+ compressor (0),
+ sampleCountTablePtr (0),
+ sampleCountTableCompressor (0),
+ hasException (false),
+ exception (),
+ _sem (1)
+{
+ // empty
+}
+
+
+TileBuffer::~TileBuffer ()
+{
+ if (compressor != 0)
+ delete compressor;
+
+ if (sampleCountTableCompressor != 0)
+ delete sampleCountTableCompressor;
+}
+
+
+} // namespace
+
+
+struct DeepTiledOutputFile::Data
+{
+ Header header; // the image header
+ int version; // file format version
+ bool multipart; // file is multipart
+ TileDescription tileDesc; // describes the tile layout
+ DeepFrameBuffer frameBuffer; // framebuffer to write into
+ Int64 previewPosition;
+ LineOrder lineOrder; // the file's lineorder
+ int minX; // data window's min x coord
+ int maxX; // data window's max x coord
+ int minY; // data window's min y coord
+ int maxY; // data window's max x coord
+
+ int numXLevels; // number of x levels
+ int numYLevels; // number of y levels
+ int * numXTiles; // number of x tiles at a level
+ int * numYTiles; // number of y tiles at a level
+
+ TileOffsets tileOffsets; // stores offsets in file for
+ // each tile
+
+ Compressor::Format format; // compressor's data format
+ vector<TOutSliceInfo*> slices; // info about channels in file
+
+ vector<TileBuffer*> tileBuffers;
+
+ Int64 tileOffsetsPosition; // position of the tile index
+
+ TileMap tileMap; // the map of buffered tiles
+ TileCoord nextTileToWrite;
+
+ int partNumber; // the output part number
+
+ char* sampleCountSliceBase; // the pointer to the number
+ // of samples in each pixel
+ int sampleCountXStride; // the x stride for sampleCountSliceBase
+ int sampleCountYStride; // the y stride for sampleCountSliceBase
+ int sampleCountXTileCoords; // using x coordinates relative to current tile
+ int sampleCountYTileCoords; // using y coordinates relative to current tile
+
+ Int64 maxSampleCountTableSize;// the max size in bytes for a pixel
+ // sample count table
+ OutputStreamMutex* _streamData;
+ bool _deleteStream;
+
+ Data (int numThreads);
+ ~Data ();
+
+ inline TileBuffer * getTileBuffer (int number);
+ // hash function from tile
+ // buffer coords into our
+ // vector of tile buffers
+
+ int& getSampleCount(int x, int y);
+ // get the number of samples
+ // in each pixel
+
+ TileCoord nextTileCoord (const TileCoord &a);
+};
+
+
+DeepTiledOutputFile::Data::Data (int numThreads):
+ numXTiles(0),
+ numYTiles(0),
+ tileOffsetsPosition (0),
+ partNumber(-1),
+ _streamData(NULL),
+ _deleteStream(true)
+{
+ //
+ // We need at least one tileBuffer, but if threading is used,
+ // to keep n threads busy we need 2*n tileBuffers
+ //
+
+ tileBuffers.resize (max (1, 2 * numThreads));
+ for (size_t i = 0; i < tileBuffers.size(); i++)
+ tileBuffers[i] = 0;
+}
+
+
+DeepTiledOutputFile::Data::~Data ()
+{
+ delete [] numXTiles;
+ delete [] numYTiles;
+
+ //
+ // Delete all the tile buffers, if any still happen to exist
+ //
+
+ for (TileMap::iterator i = tileMap.begin(); i != tileMap.end(); ++i)
+ delete i->second;
+
+ for (size_t i = 0; i < tileBuffers.size(); i++)
+ if (tileBuffers[i] != 0)
+ delete tileBuffers[i];
+
+ for (size_t i = 0; i < slices.size(); i++)
+ delete slices[i];
+}
+
+
+int&
+DeepTiledOutputFile::Data::getSampleCount(int x, int y)
+{
+ return sampleCount(sampleCountSliceBase,
+ sampleCountXStride,
+ sampleCountYStride,
+ x, y);
+}
+
+
+TileBuffer*
+DeepTiledOutputFile::Data::getTileBuffer (int number)
+{
+ return tileBuffers[number % tileBuffers.size()];
+}
+
+
+TileCoord
+DeepTiledOutputFile::Data::nextTileCoord (const TileCoord &a)
+{
+ TileCoord b = a;
+
+ if (lineOrder == INCREASING_Y)
+ {
+ b.dx++;
+
+ if (b.dx >= numXTiles[b.lx])
+ {
+ b.dx = 0;
+ b.dy++;
+
+ if (b.dy >= numYTiles[b.ly])
+ {
+ //
+ // the next tile is in the next level
+ //
+
+ b.dy = 0;
+
+ switch (tileDesc.mode)
+ {
+ case ONE_LEVEL:
+ case MIPMAP_LEVELS:
+
+ b.lx++;
+ b.ly++;
+ break;
+
+ case RIPMAP_LEVELS:
+
+ b.lx++;
+
+ if (b.lx >= numXLevels)
+ {
+ b.lx = 0;
+ b.ly++;
+
+ #ifdef DEBUG
+ assert (b.ly <= numYLevels);
+ #endif
+ }
+ break;
+ case NUM_LEVELMODES :
+ throw IEX_NAMESPACE::LogicExc("unknown level mode computing nextTileCoord");
+ }
+ }
+ }
+ }
+ else if (lineOrder == DECREASING_Y)
+ {
+ b.dx++;
+
+ if (b.dx >= numXTiles[b.lx])
+ {
+ b.dx = 0;
+ b.dy--;
+
+ if (b.dy < 0)
+ {
+ //
+ // the next tile is in the next level
+ //
+
+ switch (tileDesc.mode)
+ {
+ case ONE_LEVEL:
+ case MIPMAP_LEVELS:
+
+ b.lx++;
+ b.ly++;
+ break;
+
+ case RIPMAP_LEVELS:
+
+ b.lx++;
+
+ if (b.lx >= numXLevels)
+ {
+ b.lx = 0;
+ b.ly++;
+
+ #ifdef DEBUG
+ assert (b.ly <= numYLevels);
+ #endif
+ }
+ break;
+ case NUM_LEVELMODES :
+ throw IEX_NAMESPACE::LogicExc("unknown level mode computing nextTileCoord");
+ }
+
+ if (b.ly < numYLevels)
+ b.dy = numYTiles[b.ly] - 1;
+ }
+ }
+ }else if(lineOrder==RANDOM_Y)
+ {
+ THROW (IEX_NAMESPACE::ArgExc,
+ "can't compute next tile from randomly ordered image: use getTilesInOrder instead");
+
+ }
+
+ return b;
+}
+
+
+namespace {
+
+void
+writeTileData (DeepTiledOutputFile::Data *ofd,
+ int dx, int dy,
+ int lx, int ly,
+ const char pixelData[],
+ Int64 pixelDataSize,
+ Int64 unpackedDataSize,
+ const char sampleCountTableData[],
+ Int64 sampleCountTableSize)
+{
+
+ //
+ // Store a block of pixel data in the output file, and try
+ // to keep track of the current writing position the file,
+ // without calling tellp() (tellp() can be fairly expensive).
+ //
+
+ Int64 currentPosition = ofd->_streamData->currentPosition;
+ ofd->_streamData->currentPosition = 0;
+
+ if (currentPosition == 0)
+ currentPosition = ofd->_streamData->os->tellp();
+
+ ofd->tileOffsets (dx, dy, lx, ly) = currentPosition;
+
+ #ifdef DEBUG
+ assert (ofd->_streamData->os->tellp() == currentPosition);
+ #endif
+
+ //
+ // Write the tile header.
+ //
+
+ if (ofd->multipart)
+ {
+ Xdr::write <StreamIO> (*ofd->_streamData->os, ofd->partNumber);
+ }
+ Xdr::write <StreamIO> (*ofd->_streamData->os, dx);
+ Xdr::write <StreamIO> (*ofd->_streamData->os, dy);
+ Xdr::write <StreamIO> (*ofd->_streamData->os, lx);
+ Xdr::write <StreamIO> (*ofd->_streamData->os, ly);
+
+ //
+ // Write the packed size of the pixel sample count table (64 bits)
+ //
+
+ Xdr::write <StreamIO> (*ofd->_streamData->os, sampleCountTableSize);
+
+ //
+ // Write the packed and unpacked data size (64 bits each)
+ //
+
+ Xdr::write <StreamIO> (*ofd->_streamData->os, pixelDataSize);
+ Xdr::write <StreamIO> (*ofd->_streamData->os, unpackedDataSize);
+
+ //
+ // Write the compressed pixel sample count table.
+ //
+
+ ofd->_streamData->os->write (sampleCountTableData, sampleCountTableSize);
+
+ //
+ // Write the compressed data.
+ //
+
+ ofd->_streamData->os->write (pixelData, pixelDataSize);
+
+ //
+ // Keep current position in the file so that we can avoid
+ // redundant seekg() operations (seekg() can be fairly expensive).
+ //
+
+ ofd->_streamData->currentPosition = currentPosition +
+ 4 * Xdr::size<int>() + // dx, dy, lx, ly,
+ 3 * Xdr::size<Int64>() + // sampleCountTableSize,
+ // pixelDataSize,
+ // unpackedDataSize
+ sampleCountTableSize +
+ pixelDataSize;
+
+ if (ofd->multipart)
+ {
+ ofd->_streamData->currentPosition += Xdr::size<int>();
+ }
+}
+
+
+
+void
+bufferedTileWrite (
+ DeepTiledOutputFile::Data *ofd,
+ int dx, int dy,
+ int lx, int ly,
+ const char pixelData[],
+ Int64 pixelDataSize,
+ Int64 unpackedDataSize,
+ const char sampleCountTableData[],
+ Int64 sampleCountTableSize)
+{
+ //
+ // Check if a tile with coordinates (dx,dy,lx,ly) has already been written.
+ //
+
+ if (ofd->tileOffsets (dx, dy, lx, ly))
+ {
+ THROW (IEX_NAMESPACE::ArgExc,
+ "Attempt to write tile "
+ "(" << dx << ", " << dy << ", " << lx << ", " << ly << ") "
+ "more than once.");
+ }
+
+ //
+ // If tiles can be written in random order, then don't buffer anything.
+ //
+
+ if (ofd->lineOrder == RANDOM_Y)
+ {
+ writeTileData (ofd, dx, dy, lx, ly,
+ pixelData, pixelDataSize, unpackedDataSize,
+ sampleCountTableData, sampleCountTableSize);
+ return;
+ }
+
+ //
+ // If the tiles cannot be written in random order, then check if a
+ // tile with coordinates (dx,dy,lx,ly) has already been buffered.
+ //
+
+ TileCoord currentTile = TileCoord(dx, dy, lx, ly);
+
+ if (ofd->tileMap.find (currentTile) != ofd->tileMap.end())
+ {
+ THROW (IEX_NAMESPACE::ArgExc,
+ "Attempt to write tile "
+ "(" << dx << ", " << dy << ", " << lx << ", " << ly << ") "
+ "more than once.");
+ }
+
+ //
+ // If all the tiles before this one have already been written to the file,
+ // then write this tile immediately and check if we have buffered tiles
+ // that can be written after this tile.
+ //
+ // Otherwise, buffer the tile so it can be written to file later.
+ //
+
+ if (ofd->nextTileToWrite == currentTile)
+ {
+ writeTileData (ofd, dx, dy, lx, ly,
+ pixelData, pixelDataSize, unpackedDataSize,
+ sampleCountTableData, sampleCountTableSize);
+ ofd->nextTileToWrite = ofd->nextTileCoord (ofd->nextTileToWrite);
+
+ TileMap::iterator i = ofd->tileMap.find (ofd->nextTileToWrite);
+
+ //
+ // Step through the tiles and write all successive buffered tiles after
+ // the current one.
+ //
+
+ while(i != ofd->tileMap.end())
+ {
+ //
+ // Write the tile, and then delete the tile's buffered data
+ //
+
+ writeTileData (ofd,
+ i->first.dx, i->first.dy,
+ i->first.lx, i->first.ly,
+ i->second->pixelData,
+ i->second->pixelDataSize,
+ i->second->unpackedDataSize,
+ i->second->sampleCountTableData,
+ i->second->sampleCountTableSize);
+
+ delete i->second;
+ ofd->tileMap.erase (i);
+
+ //
+ // Proceed to the next tile
+ //
+
+ ofd->nextTileToWrite = ofd->nextTileCoord (ofd->nextTileToWrite);
+ i = ofd->tileMap.find (ofd->nextTileToWrite);
+ }
+ }
+ else
+ {
+ //
+ // Create a new BufferedTile, copy the pixelData into it, and
+ // insert it into the tileMap.
+ //
+
+ ofd->tileMap[currentTile] =
+ new BufferedTile ((const char *)pixelData, pixelDataSize, unpackedDataSize,
+ sampleCountTableData, sampleCountTableSize);
+ }
+}
+
+
+void
+convertToXdr (DeepTiledOutputFile::Data *ofd,
+ Array<char>& tileBuffer,
+ int numScanLines,
+ vector<Int64>& bytesPerLine)
+{
+ //
+ // Convert the contents of a TiledOutputFile's tileBuffer from the
+ // machine's native representation to Xdr format. This function is called
+ // by writeTile(), below, if the compressor wanted its input pixel data
+ // in the machine's native format, but then failed to compress the data
+ // (most compressors will expand rather than compress random input data).
+ //
+ // Note that this routine assumes that the machine's native representation
+ // of the pixel data has the same size as the Xdr representation. This
+ // makes it possible to convert the pixel data in place, without an
+ // intermediate temporary buffer.
+ //
+
+ //
+ // Set these to point to the start of the tile.
+ // We will write to toPtr, and read from fromPtr.
+ //
+
+ char *writePtr = tileBuffer;
+ const char *readPtr = writePtr;
+
+ //
+ // Iterate over all scan lines in the tile.
+ //
+
+ for (int y = 0; y < numScanLines; ++y)
+ {
+ //
+ // Iterate over all slices in the file.
+ //
+
+ for (unsigned int i = 0; i < ofd->slices.size(); ++i)
+ {
+ const TOutSliceInfo &slice = *ofd->slices[i];
+
+ //
+ // Convert the samples in place.
+ //
+
+ Int64 numPixelsPerScanLine = bytesPerLine[y];
+
+ convertInPlace (writePtr, readPtr, slice.type,
+ numPixelsPerScanLine);
+ }
+ }
+
+ #ifdef DEBUG
+
+ assert (writePtr == readPtr);
+
+ #endif
+}
+
+
+//
+// A TileBufferTask encapsulates the task of copying a tile from
+// the user's framebuffer into a LineBuffer and compressing the data
+// if necessary.
+//
+
+class TileBufferTask: public Task
+{
+ public:
+
+ TileBufferTask (TaskGroup *group,
+ DeepTiledOutputFile::Data *ofd,
+ int number,
+ int dx, int dy,
+ int lx, int ly);
+
+ virtual ~TileBufferTask ();
+
+ virtual void execute ();
+
+ private:
+
+ DeepTiledOutputFile::Data * _ofd;
+ TileBuffer * _tileBuffer;
+};
+
+
+TileBufferTask::TileBufferTask
+ (TaskGroup *group,
+ DeepTiledOutputFile::Data *ofd,
+ int number,
+ int dx, int dy,
+ int lx, int ly)
+:
+ Task (group),
+ _ofd (ofd),
+ _tileBuffer (_ofd->getTileBuffer (number))
+{
+ //
+ // Wait for the tileBuffer to become available
+ //
+
+ _tileBuffer->wait ();
+ _tileBuffer->tileCoord = TileCoord (dx, dy, lx, ly);
+}
+
+
+TileBufferTask::~TileBufferTask ()
+{
+ //
+ // Signal that the tile buffer is now free
+ //
+
+ _tileBuffer->post ();
+}
+
+
+void
+TileBufferTask::execute ()
+{
+ try
+ {
+ //
+ // First copy the pixel data from the frame buffer
+ // into the tile buffer
+ //
+ // Convert one tile's worth of pixel data to
+ // a machine-independent representation, and store
+ // the result in _tileBuffer->buffer.
+ //
+
+ Box2i tileRange = OPENEXR_IMF_INTERNAL_NAMESPACE::dataWindowForTile (
+ _ofd->tileDesc,
+ _ofd->minX, _ofd->maxX,
+ _ofd->minY, _ofd->maxY,
+ _tileBuffer->tileCoord.dx,
+ _tileBuffer->tileCoord.dy,
+ _tileBuffer->tileCoord.lx,
+ _tileBuffer->tileCoord.ly);
+
+ int numScanLines = tileRange.max.y - tileRange.min.y + 1;
+// int numPixelsPerScanLine = tileRange.max.x - tileRange.min.x + 1;
+
+ //
+ // Get the bytes for each line.
+ //
+
+ vector<Int64> bytesPerLine(_ofd->tileDesc.ySize);
+ vector<int> xOffsets(_ofd->slices.size());
+ vector<int> yOffsets(_ofd->slices.size());
+ for (size_t i = 0; i < _ofd->slices.size(); i++)
+ {
+ const TOutSliceInfo &slice = *_ofd->slices[i];
+ xOffsets[i] = slice.xTileCoords * tileRange.min.x;
+ yOffsets[i] = slice.yTileCoords * tileRange.min.y;
+ }
+
+ calculateBytesPerLine(_ofd->header,
+ _ofd->sampleCountSliceBase,
+ _ofd->sampleCountXStride,
+ _ofd->sampleCountYStride,
+ tileRange.min.x, tileRange.max.x,
+ tileRange.min.y, tileRange.max.y,
+ xOffsets, yOffsets,
+ bytesPerLine);
+
+ //
+ // Allocate the memory for internal buffer.
+ // (TODO) more efficient memory management?
+ //
+
+ Int64 totalBytes = 0;
+ Int64 maxBytesPerTileLine = 0;
+ for (size_t i = 0; i < bytesPerLine.size(); i++)
+ {
+ totalBytes += bytesPerLine[i];
+ if (bytesPerLine[i] > maxBytesPerTileLine)
+ maxBytesPerTileLine = bytesPerLine[i];
+ }
+ _tileBuffer->buffer.resizeErase(totalBytes);
+
+ char *writePtr = _tileBuffer->buffer;
+
+ //
+ // Iterate over the scan lines in the tile.
+ //
+
+ int xOffsetForSampleCount =
+ (_ofd->sampleCountXTileCoords == 0) ? 0 : tileRange.min.x;
+ int yOffsetForSampleCount =
+ (_ofd->sampleCountYTileCoords == 0) ? 0 : tileRange.min.y;
+
+ for (int y = tileRange.min.y; y <= tileRange.max.y; ++y)
+ {
+ //
+ // Iterate over all image channels.
+ //
+
+ for (unsigned int i = 0; i < _ofd->slices.size(); ++i)
+ {
+ const TOutSliceInfo &slice = *_ofd->slices[i];
+
+
+ //
+ // Fill the tile buffer with pixel data.
+ //
+
+ if (slice.zero)
+ {
+ //
+ // The frame buffer contains no data for this channel.
+ // Store zeroes in _data->tileBuffer.
+ //
+
+ fillChannelWithZeroes (writePtr, _ofd->format, slice.type,
+ bytesPerLine[y - tileRange.min.y]);
+ }
+ else
+ {
+ //
+ // The frame buffer contains data for this channel.
+ //
+
+
+ int xOffsetForData = slice.xTileCoords ? tileRange.min.x : 0;
+ int yOffsetForData = slice.yTileCoords ? tileRange.min.y : 0;
+
+ // (TOOD) treat sample count offsets differently.
+ copyFromDeepFrameBuffer (writePtr,
+ slice.base,
+ _ofd->sampleCountSliceBase,
+ _ofd->sampleCountXStride,
+ _ofd->sampleCountYStride,
+ y,
+ tileRange.min.x,
+ tileRange.max.x,
+ xOffsetForSampleCount,
+ yOffsetForSampleCount,
+ xOffsetForData,
+ yOffsetForData,
+ slice.sampleStride,
+ slice.xStride,
+ slice.yStride,
+ _ofd->format,
+ slice.type);
+#if defined(DEBUG)
+ assert(writePtr-_tileBuffer->buffer<=totalBytes);
+#endif
+ }
+ }
+ }
+
+ //
+ // Compress the pixel sample count table.
+ //
+
+ char* ptr = _tileBuffer->sampleCountTableBuffer;
+ Int64 tableDataSize = 0;
+ for (int i = tileRange.min.y; i <= tileRange.max.y; i++)
+ {
+ int count = 0;
+ for (int j = tileRange.min.x; j <= tileRange.max.x; j++)
+ {
+ count += _ofd->getSampleCount(j - xOffsetForSampleCount,
+ i - yOffsetForSampleCount);
+ Xdr::write <CharPtrIO> (ptr, count);
+ tableDataSize += sizeof (int);
+ }
+ }
+
+ if(_tileBuffer->sampleCountTableCompressor)
+ {
+ _tileBuffer->sampleCountTableSize =
+ _tileBuffer->sampleCountTableCompressor->compress (
+ _tileBuffer->sampleCountTableBuffer,
+ tableDataSize,
+ tileRange.min.y,
+ _tileBuffer->sampleCountTablePtr);
+ }
+
+ //
+ // If we can't make data shrink (or compression was disabled), then just use the raw data.
+ //
+
+ if ( ! _tileBuffer->sampleCountTableCompressor ||
+ _tileBuffer->sampleCountTableSize >= _ofd->maxSampleCountTableSize)
+ {
+ _tileBuffer->sampleCountTableSize = _ofd->maxSampleCountTableSize;
+ _tileBuffer->sampleCountTablePtr = _tileBuffer->sampleCountTableBuffer;
+ }
+
+ //
+ // Compress the contents of the tileBuffer,
+ // and store the compressed data in the output file.
+ //
+
+ _tileBuffer->dataSize = writePtr - _tileBuffer->buffer;
+ _tileBuffer->uncompressedSize = _tileBuffer->dataSize;
+ _tileBuffer->dataPtr = _tileBuffer->buffer;
+
+ // (TODO) don't do this all the time.
+ if (_tileBuffer->compressor != 0)
+ delete _tileBuffer->compressor;
+ _tileBuffer->compressor = newTileCompressor
+ (_ofd->header.compression(),
+ maxBytesPerTileLine,
+ _ofd->tileDesc.ySize,
+ _ofd->header);
+
+ if (_tileBuffer->compressor)
+ {
+ const char *compPtr;
+
+ Int64 compSize = _tileBuffer->compressor->compressTile
+ (_tileBuffer->dataPtr,
+ _tileBuffer->dataSize,
+ tileRange, compPtr);
+
+ if (compSize < _tileBuffer->dataSize)
+ {
+ _tileBuffer->dataSize = compSize;
+ _tileBuffer->dataPtr = compPtr;
+ }
+ else if (_ofd->format == Compressor::NATIVE)
+ {
+ //
+ // The data did not shrink during compression, but
+ // we cannot write to the file using native format,
+ // so we need to convert the lineBuffer to Xdr.
+ //
+
+ convertToXdr (_ofd, _tileBuffer->buffer, numScanLines,
+ bytesPerLine);
+ }
+ }
+ }
+ catch (std::exception &e)
+ {
+ if (!_tileBuffer->hasException)
+ {
+ _tileBuffer->exception = e.what ();
+ _tileBuffer->hasException = true;
+ }
+ }
+ catch (...)
+ {
+ if (!_tileBuffer->hasException)
+ {
+ _tileBuffer->exception = "unrecognized exception";
+ _tileBuffer->hasException = true;
+ }
+ }
+}
+
+} // namespace
+
+
+DeepTiledOutputFile::DeepTiledOutputFile
+ (const char fileName[],
+ const Header &header,
+ int numThreads)
+:
+ _data (new Data (numThreads))
+
+{
+ _data->_streamData=new OutputStreamMutex();
+ _data->_deleteStream =true;
+ try
+ {
+ header.sanityCheck (true);
+ _data->_streamData->os = new StdOFStream (fileName);
+ initialize (header);
+ _data->_streamData->currentPosition = _data->_streamData->os->tellp();
+
+ // Write header and empty offset table to the file.
+ writeMagicNumberAndVersionField(*_data->_streamData->os, _data->header);
+ _data->previewPosition = _data->header.writeTo (*_data->_streamData->os, true);
+ _data->tileOffsetsPosition = _data->tileOffsets.writeTo (*_data->_streamData->os);
+ _data->multipart = false;
+ }
+ catch (IEX_NAMESPACE::BaseExc &e)
+ {
+ if (_data && _data->_streamData && _data->_streamData->os) delete _data->_streamData->os;
+ if (_data && _data->_streamData) delete _data->_streamData;
+ if (_data) delete _data;
+
+ REPLACE_EXC (e, "Cannot open image file "
+ "\"" << fileName << "\". " << e.what());
+ throw;
+ }
+ catch (...)
+ {
+ if (_data && _data->_streamData && _data->_streamData->os) delete _data->_streamData->os;
+ if (_data->_streamData) delete _data->_streamData;
+ if (_data) delete _data;
+
+ throw;
+ }
+}
+
+
+DeepTiledOutputFile::DeepTiledOutputFile
+ (OPENEXR_IMF_INTERNAL_NAMESPACE::OStream &os,
+ const Header &header,
+ int numThreads)
+:
+ _data (new Data (numThreads))
+{
+ _data->_streamData=new OutputStreamMutex();
+ _data->_deleteStream=false;
+
+ try
+ {
+ header.sanityCheck(true);
+ _data->_streamData->os = &os;
+ initialize (header);
+ _data->_streamData->currentPosition = _data->_streamData->os->tellp();
+
+ // Write header and empty offset table to the file.
+ writeMagicNumberAndVersionField(*_data->_streamData->os, _data->header);
+ _data->previewPosition = _data->header.writeTo (*_data->_streamData->os, true);
+ _data->tileOffsetsPosition = _data->tileOffsets.writeTo (*_data->_streamData->os);
+ _data->multipart = false;
+ }
+ catch (IEX_NAMESPACE::BaseExc &e)
+ {
+ if (_data && _data->_streamData) delete _data->_streamData;
+ if (_data) delete _data;
+
+ REPLACE_EXC (e, "Cannot open image file "
+ "\"" << os.fileName() << "\". " << e.what());
+ throw;
+ }
+ catch (...)
+ {
+ if (_data && _data->_streamData) delete _data->_streamData;
+ if (_data) delete _data;
+
+ throw;
+ }
+}
+
+DeepTiledOutputFile::DeepTiledOutputFile(const OutputPartData* part)
+{
+
+ try
+ {
+ if (part->header.type() != DEEPTILE)
+ throw IEX_NAMESPACE::ArgExc("Can't build a DeepTiledOutputFile from "
+ "a type-mismatched part.");
+
+ _data = new Data (part->numThreads);
+ _data->_streamData=part->mutex;
+ _data->_deleteStream=false;
+ initialize(part->header);
+ _data->partNumber = part->partNumber;
+ _data->tileOffsetsPosition = part->chunkOffsetTablePosition;
+ _data->previewPosition = part->previewPosition;
+ _data->multipart = part->multipart;
+ }
+ catch (IEX_NAMESPACE::BaseExc &e)
+ {
+ if (_data) delete _data;
+
+ REPLACE_EXC (e, "Cannot initialize output part "
+ "\"" << part->partNumber << "\". " << e.what());
+ throw;
+ }
+ catch (...)
+ {
+ if (_data) delete _data;
+
+ throw;
+ }
+}
+
+void
+DeepTiledOutputFile::initialize (const Header &header)
+{
+ _data->header = header;
+ _data->header.setType(DEEPTILE);
+ _data->lineOrder = _data->header.lineOrder();
+
+ //
+ // Check that the file is indeed tiled
+ //
+
+ _data->tileDesc = _data->header.tileDescription();
+
+ //
+ // Save the dataWindow information
+ //
+
+ const Box2i &dataWindow = _data->header.dataWindow();
+ _data->minX = dataWindow.min.x;
+ _data->maxX = dataWindow.max.x;
+ _data->minY = dataWindow.min.y;
+ _data->maxY = dataWindow.max.y;
+
+ //
+ // Precompute level and tile information to speed up utility functions
+ //
+
+ precalculateTileInfo (_data->tileDesc,
+ _data->minX, _data->maxX,
+ _data->minY, _data->maxY,
+ _data->numXTiles, _data->numYTiles,
+ _data->numXLevels, _data->numYLevels);
+
+ //
+ // Determine the first tile coordinate that we will be writing
+ // if the file is not RANDOM_Y.
+ //
+
+ _data->nextTileToWrite = (_data->lineOrder == INCREASING_Y)?
+ TileCoord (0, 0, 0, 0):
+ TileCoord (0, _data->numYTiles[0] - 1, 0, 0);
+
+ Compressor* compressor = newTileCompressor
+ (_data->header.compression(),
+ 0,
+ _data->tileDesc.ySize,
+ _data->header);
+
+ _data->format = defaultFormat (compressor);
+
+ if (compressor != 0)
+ delete compressor;
+
+ _data->tileOffsets = TileOffsets (_data->tileDesc.mode,
+ _data->numXLevels,
+ _data->numYLevels,
+ _data->numXTiles,
+ _data->numYTiles);
+
+ //ignore the existing value of chunkCount - correct it if it's wrong
+ _data->header.setChunkCount(getChunkOffsetTableSize(_data->header,true));
+
+ _data->maxSampleCountTableSize = _data->tileDesc.ySize *
+ _data->tileDesc.xSize *
+ sizeof(int);
+
+
+ for (size_t i = 0; i < _data->tileBuffers.size(); i++)
+ {
+ _data->tileBuffers[i] = new TileBuffer ();
+
+ _data->tileBuffers[i]->sampleCountTableBuffer.
+ resizeErase(_data->maxSampleCountTableSize);
+
+ char * p = &(_data->tileBuffers[i]->sampleCountTableBuffer[0]);
+ memset (p, 0, _data->maxSampleCountTableSize);
+
+ _data->tileBuffers[i]->sampleCountTableCompressor =
+ newCompressor (_data->header.compression(),
+ _data->maxSampleCountTableSize,
+ _data->header);
+ }
+}
+
+
+DeepTiledOutputFile::~DeepTiledOutputFile ()
+{
+ if (_data)
+ {
+ {
+ Lock lock(*_data->_streamData);
+ Int64 originalPosition = _data->_streamData->os->tellp();
+
+ if (_data->tileOffsetsPosition > 0)
+ {
+ try
+ {
+ _data->_streamData->os->seekp (_data->tileOffsetsPosition);
+ _data->tileOffsets.writeTo (*_data->_streamData->os);
+
+ //
+ // Restore the original position.
+ //
+ _data->_streamData->os->seekp (originalPosition);
+ }
+ catch (...)
+ {
+ //
+ // We cannot safely throw any exceptions from here.
+ // This destructor may have been called because the
+ // stack is currently being unwound for another
+ // exception.
+ //
+ }
+ }
+ }
+
+ if (_data->_deleteStream && _data->_streamData)
+ delete _data->_streamData->os;
+
+ //
+ // (TODO) we should have a way to tell if the stream data is owned by
+ // this file or by a parent multipart file.
+ //
+
+ if (_data->partNumber == -1 && _data->_streamData)
+ delete _data->_streamData;
+
+ delete _data;
+ }
+}
+
+
+const char *
+DeepTiledOutputFile::fileName () const
+{
+ return _data->_streamData->os->fileName();
+}
+
+
+const Header &
+DeepTiledOutputFile::header () const
+{
+ return _data->header;
+}
+
+
+void
+DeepTiledOutputFile::setFrameBuffer (const DeepFrameBuffer &frameBuffer)
+{
+ Lock lock (*_data->_streamData);
+
+ //
+ // Check if the new frame buffer descriptor
+ // is compatible with the image file header.
+ //
+
+ const ChannelList &channels = _data->header.channels();
+
+ for (ChannelList::ConstIterator i = channels.begin();
+ i != channels.end();
+ ++i)
+ {
+ DeepFrameBuffer::ConstIterator j = frameBuffer.find (i.name());
+
+ if (j == frameBuffer.end())
+ continue;
+
+ if (i.channel().type != j.slice().type)
+ THROW (IEX_NAMESPACE::ArgExc, "Pixel type of \"" << i.name() << "\" channel "
+ "of output file \"" << fileName() << "\" is "
+ "not compatible with the frame buffer's "
+ "pixel type.");
+
+ if (j.slice().xSampling != 1 || j.slice().ySampling != 1)
+ THROW (IEX_NAMESPACE::ArgExc, "All channels in a tiled file must have"
+ "sampling (1,1).");
+ }
+
+ //
+ // Store the pixel sample count table.
+ //
+
+ const Slice& sampleCountSlice = frameBuffer.getSampleCountSlice();
+ if (sampleCountSlice.base == 0)
+ {
+ throw IEX_NAMESPACE::ArgExc ("Invalid base pointer, please set a proper sample count slice.");
+ }
+ else
+ {
+ _data->sampleCountSliceBase = sampleCountSlice.base;
+ _data->sampleCountXStride = sampleCountSlice.xStride;
+ _data->sampleCountYStride = sampleCountSlice.yStride;
+ _data->sampleCountXTileCoords = sampleCountSlice.xTileCoords;
+ _data->sampleCountYTileCoords = sampleCountSlice.yTileCoords;
+ }
+
+ //
+ // Initialize slice table for writePixels().
+ // Pixel sample count slice is not presented in the header,
+ // so it wouldn't be added here.
+ // Store the pixel base pointer table.
+ //
+
+ vector<TOutSliceInfo*> slices;
+
+ for (ChannelList::ConstIterator i = channels.begin();
+ i != channels.end();
+ ++i)
+ {
+ DeepFrameBuffer::ConstIterator j = frameBuffer.find (i.name());
+
+ if (j == frameBuffer.end())
+ {
+ //
+ // Channel i is not present in the frame buffer.
+ // In the file, channel i will contain only zeroes.
+ //
+
+ slices.push_back (new TOutSliceInfo (i.channel().type,
+ 0, // sampleStride,
+ 0, // xStride
+ 0, // yStride
+ true)); // zero
+ }
+ else
+ {
+ //
+ // Channel i is present in the frame buffer.
+ //
+
+ slices.push_back (new TOutSliceInfo (j.slice().type,
+ j.slice().sampleStride,
+ j.slice().xStride,
+ j.slice().yStride,
+ false, // zero
+ (j.slice().xTileCoords)? 1: 0,
+ (j.slice().yTileCoords)? 1: 0));
+
+ TOutSliceInfo* slice = slices.back();
+ slice->base = j.slice().base;
+
+ }
+ }
+
+ //
+ // Store the new frame buffer.
+ //
+
+ _data->frameBuffer = frameBuffer;
+
+ for (size_t i = 0; i < _data->slices.size(); i++)
+ delete _data->slices[i];
+ _data->slices = slices;
+}
+
+
+const DeepFrameBuffer &
+DeepTiledOutputFile::frameBuffer () const
+{
+ Lock lock (*_data->_streamData);
+ return _data->frameBuffer;
+}
+
+
+void
+DeepTiledOutputFile::writeTiles (int dx1, int dx2, int dy1, int dy2,
+ int lx, int ly)
+{
+ try
+ {
+ Lock lock (*_data->_streamData);
+
+ if (_data->slices.size() == 0)
+ throw IEX_NAMESPACE::ArgExc ("No frame buffer specified "
+ "as pixel data source.");
+
+ if (!isValidTile (dx1, dy1, lx, ly) || !isValidTile (dx2, dy2, lx, ly))
+ throw IEX_NAMESPACE::ArgExc ("Tile coordinates are invalid.");
+
+ if (!isValidLevel (lx, ly))
+ THROW (IEX_NAMESPACE::ArgExc,
+ "Level coordinate "
+ "(" << lx << ", " << ly << ") "
+ "is invalid.");
+ //
+ // Determine the first and last tile coordinates in both dimensions
+ // based on the file's lineOrder
+ //
+
+ if (dx1 > dx2)
+ swap (dx1, dx2);
+
+ if (dy1 > dy2)
+ swap (dy1, dy2);
+
+ int dyStart = dy1;
+ int dyStop = dy2 + 1;
+ int dY = 1;
+
+ if (_data->lineOrder == DECREASING_Y)
+ {
+ dyStart = dy2;
+ dyStop = dy1 - 1;
+ dY = -1;
+ }
+
+ int numTiles = (dx2 - dx1 + 1) * (dy2 - dy1 + 1);
+ int numTasks = min ((int)_data->tileBuffers.size(), numTiles);
+
+ //
+ // Create a task group for all tile buffer tasks. When the
+ // task group goes out of scope, the destructor waits until
+ // all tasks are complete.
+ //
+
+ {
+ TaskGroup taskGroup;
+
+ //
+ // Add in the initial compression tasks to the thread pool
+ //
+
+ int nextCompBuffer = 0;
+ int dxComp = dx1;
+ int dyComp = dyStart;
+
+ while (nextCompBuffer < numTasks)
+ {
+ ThreadPool::addGlobalTask (new TileBufferTask (&taskGroup,
+ _data,
+ nextCompBuffer++,
+ dxComp, dyComp,
+ lx, ly));
+ dxComp++;
+
+ if (dxComp > dx2)
+ {
+ dxComp = dx1;
+ dyComp += dY;
+ }
+ }
+
+ //
+ // Write the compressed buffers and add in more compression
+ // tasks until done
+ //
+
+ int nextWriteBuffer = 0;
+ int dxWrite = dx1;
+ int dyWrite = dyStart;
+
+ while (nextWriteBuffer < numTiles)
+ {
+ //
+ // Wait until the nextWriteBuffer is ready to be written
+ //
+
+ TileBuffer* writeBuffer =
+ _data->getTileBuffer (nextWriteBuffer);
+
+ writeBuffer->wait();
+
+ //
+ // Write the tilebuffer
+ //
+
+ bufferedTileWrite ( _data, dxWrite, dyWrite, lx, ly,
+ writeBuffer->dataPtr,
+ writeBuffer->dataSize,
+ writeBuffer->uncompressedSize,
+ writeBuffer->sampleCountTablePtr,
+ writeBuffer->sampleCountTableSize);
+
+ //
+ // Release the lock on nextWriteBuffer
+ //
+
+ writeBuffer->post();
+
+ //
+ // If there are no more tileBuffers to compress, then
+ // only continue to write out remaining tileBuffers,
+ // otherwise keep adding compression tasks.
+ //
+
+ if (nextCompBuffer < numTiles)
+ {
+ //
+ // add nextCompBuffer as a compression Task
+ //
+
+ ThreadPool::addGlobalTask
+ (new TileBufferTask (&taskGroup,
+ _data,
+ nextCompBuffer,
+ dxComp, dyComp,
+ lx, ly));
+ }
+
+ nextWriteBuffer++;
+ dxWrite++;
+
+ if (dxWrite > dx2)
+ {
+ dxWrite = dx1;
+ dyWrite += dY;
+ }
+
+ nextCompBuffer++;
+ dxComp++;
+
+ if (dxComp > dx2)
+ {
+ dxComp = dx1;
+ dyComp += dY;
+ }
+ }
+
+ //
+ // finish all tasks
+ //
+ }
+
+ //
+ // Exeption handling:
+ //
+ // TileBufferTask::execute() may have encountered exceptions, but
+ // those exceptions occurred in another thread, not in the thread
+ // that is executing this call to TiledOutputFile::writeTiles().
+ // TileBufferTask::execute() has caught all exceptions and stored
+ // the exceptions' what() strings in the tile buffers.
+ // Now we check if any tile buffer contains a stored exception; if
+ // this is the case then we re-throw the exception in this thread.
+ // (It is possible that multiple tile buffers contain stored
+ // exceptions. We re-throw the first exception we find and
+ // ignore all others.)
+ //
+
+ const string *exception = 0;
+
+ for (size_t i = 0; i < _data->tileBuffers.size(); ++i)
+ {
+ TileBuffer *tileBuffer = _data->tileBuffers[i];
+
+ if (tileBuffer->hasException && !exception)
+ exception = &tileBuffer->exception;
+
+ tileBuffer->hasException = false;
+ }
+
+ if (exception)
+ throw IEX_NAMESPACE::IoExc (*exception);
+ }
+ catch (IEX_NAMESPACE::BaseExc &e)
+ {
+ REPLACE_EXC (e, "Failed to write pixel data to image "
+ "file \"" << fileName() << "\". " << e.what());
+ throw;
+ }
+}
+
+
+void
+DeepTiledOutputFile::writeTiles (int dx1, int dxMax, int dyMin, int dyMax, int l)
+{
+ writeTiles (dx1, dxMax, dyMin, dyMax, l, l);
+}
+
+
+void
+DeepTiledOutputFile::writeTile (int dx, int dy, int lx, int ly)
+{
+ writeTiles (dx, dx, dy, dy, lx, ly);
+}
+
+
+void
+DeepTiledOutputFile::writeTile (int dx, int dy, int l)
+{
+ writeTile(dx, dy, l, l);
+}
+
+
+void
+DeepTiledOutputFile::copyPixels (DeepTiledInputFile &in)
+{
+
+ //
+ // Check if this file's and and the InputFile's
+ // headers are compatible.
+ //
+
+ const Header &hdr = _data->header;
+ const Header &inHdr = in.header();
+
+
+
+ if (!(hdr.tileDescription() == inHdr.tileDescription()))
+ THROW (IEX_NAMESPACE::ArgExc, "Quick pixel copy from image "
+ "file \"" << in.fileName() << "\" to image "
+ "file \"" << fileName() << "\" failed. "
+ "The files have different tile descriptions.");
+
+ if (!(hdr.dataWindow() == inHdr.dataWindow()))
+ THROW (IEX_NAMESPACE::ArgExc, "Cannot copy pixels from image "
+ "file \"" << in.fileName() << "\" to image "
+ "file \"" << fileName() << "\". The "
+ "files have different data windows.");
+
+ if (!(hdr.lineOrder() == inHdr.lineOrder()))
+ THROW (IEX_NAMESPACE::ArgExc, "Quick pixel copy from image "
+ "file \"" << in.fileName() << "\" to image "
+ "file \"" << fileName() << "\" failed. "
+ "The files have different line orders.");
+
+ if (!(hdr.compression() == inHdr.compression()))
+ THROW (IEX_NAMESPACE::ArgExc, "Quick pixel copy from image "
+ "file \"" << in.fileName() << "\" to image "
+ "file \"" << fileName() << "\" failed. "
+ "The files use different compression methods.");
+
+ if (!(hdr.channels() == inHdr.channels()))
+ THROW (IEX_NAMESPACE::ArgExc, "Quick pixel copy from image "
+ "file \"" << in.fileName() << "\" to image "
+ "file \"" << fileName() << "\" "
+ "failed. The files have different channel "
+ "lists.");
+
+
+ // Verify that no pixel data have been written to this file yet.
+ //
+
+ if (!_data->tileOffsets.isEmpty())
+ THROW (IEX_NAMESPACE::LogicExc, "Quick pixel copy from image "
+ "file \"" << in.fileName() << "\" to image "
+ "file \"" << _data->_streamData->os->fileName() << "\" "
+ "failed. \"" << fileName() << "\" "
+ "already contains pixel data.");
+
+
+ int numAllTiles = in.totalTiles();
+
+ Lock lock (*_data->_streamData);
+
+ //
+ // special handling for random tiles
+ //
+
+ vector<int> dx_list(_data->lineOrder==RANDOM_Y ? numAllTiles : 1);
+ vector<int> dy_list(_data->lineOrder==RANDOM_Y ? numAllTiles : 1);
+ vector<int> lx_list(_data->lineOrder==RANDOM_Y ? numAllTiles : 1);
+ vector<int> ly_list(_data->lineOrder==RANDOM_Y ? numAllTiles : 1);
+
+ if(_data->lineOrder==RANDOM_Y)
+ {
+ in.getTileOrder(&dx_list[0],&dy_list[0],&lx_list[0],&ly_list[0]);
+ _data->nextTileToWrite.dx=dx_list[0];
+ _data->nextTileToWrite.dy=dy_list[0];
+ _data->nextTileToWrite.lx=lx_list[0];
+ _data->nextTileToWrite.ly=ly_list[0];
+ }
+
+
+ vector<char> data(4096);
+ for (int i = 0; i < numAllTiles; ++i)
+ {
+
+ int dx = _data->nextTileToWrite.dx;
+ int dy = _data->nextTileToWrite.dy;
+ int lx = _data->nextTileToWrite.lx;
+ int ly = _data->nextTileToWrite.ly;
+
+ Int64 dataSize = data.size();
+
+ in.rawTileData (dx, dy, lx, ly, &data[0], dataSize);
+ if(dataSize>data.size())
+ {
+ data.resize(dataSize);
+ in.rawTileData (dx, dy, lx, ly, &data[0], dataSize);
+ }
+ Int64 sampleCountTableSize = *(Int64 *)(&data[0] + 16);
+ Int64 pixelDataSize = *(Int64 *)(&data[0] + 24);
+ Int64 unpackedPixelDataSize = *(Int64 *)(&data[0] + 32);
+ char * sampleCountTable = &data[0]+40;
+ char * pixelData = sampleCountTable + sampleCountTableSize;
+
+ writeTileData (_data, dx, dy, lx, ly, pixelData, pixelDataSize,unpackedPixelDataSize,sampleCountTable,sampleCountTableSize);
+
+
+ if(_data->lineOrder==RANDOM_Y)
+ {
+ if(i<numAllTiles-1)
+ {
+ _data->nextTileToWrite.dx=dx_list[i+1];
+ _data->nextTileToWrite.dy=dy_list[i+1];
+ _data->nextTileToWrite.lx=lx_list[i+1];
+ _data->nextTileToWrite.ly=ly_list[i+1];
+ }
+ }else{
+ _data->nextTileToWrite = _data->nextTileCoord (_data->nextTileToWrite);
+ }
+
+ }
+}
+
+
+void
+DeepTiledOutputFile::copyPixels (DeepTiledInputPart &in)
+{
+ copyPixels(*in.file);
+}
+
+
+unsigned int
+DeepTiledOutputFile::tileXSize () const
+{
+ return _data->tileDesc.xSize;
+}
+
+
+unsigned int
+DeepTiledOutputFile::tileYSize () const
+{
+ return _data->tileDesc.ySize;
+}
+
+
+LevelMode
+DeepTiledOutputFile::levelMode () const
+{
+ return _data->tileDesc.mode;
+}
+
+
+LevelRoundingMode
+DeepTiledOutputFile::levelRoundingMode () const
+{
+ return _data->tileDesc.roundingMode;
+}
+
+
+int
+DeepTiledOutputFile::numLevels () const
+{
+ if (levelMode() == RIPMAP_LEVELS)
+ THROW (IEX_NAMESPACE::LogicExc, "Error calling numLevels() on image "
+ "file \"" << fileName() << "\" "
+ "(numLevels() is not defined for RIPMAPs).");
+ return _data->numXLevels;
+}
+
+
+int
+DeepTiledOutputFile::numXLevels () const
+{
+ return _data->numXLevels;
+}
+
+
+int
+DeepTiledOutputFile::numYLevels () const
+{
+ return _data->numYLevels;
+}
+
+
+bool
+DeepTiledOutputFile::isValidLevel (int lx, int ly) const
+{
+ if (lx < 0 || ly < 0)
+ return false;
+
+ if (levelMode() == MIPMAP_LEVELS && lx != ly)
+ return false;
+
+ if (lx >= numXLevels() || ly >= numYLevels())
+ return false;
+
+ return true;
+}
+
+
+int
+DeepTiledOutputFile::levelWidth (int lx) const
+{
+ try
+ {
+ int retVal = levelSize (_data->minX, _data->maxX, lx,
+ _data->tileDesc.roundingMode);
+
+ return retVal;
+ }
+ catch (IEX_NAMESPACE::BaseExc &e)
+ {
+ REPLACE_EXC (e, "Error calling levelWidth() on image "
+ "file \"" << fileName() << "\". " << e.what());
+ throw;
+ }
+}
+
+
+int
+DeepTiledOutputFile::levelHeight (int ly) const
+{
+ try
+ {
+ return levelSize (_data->minY, _data->maxY, ly,
+ _data->tileDesc.roundingMode);
+ }
+ catch (IEX_NAMESPACE::BaseExc &e)
+ {
+ REPLACE_EXC (e, "Error calling levelHeight() on image "
+ "file \"" << fileName() << "\". " << e.what());
+ throw;
+ }
+}
+
+
+int
+DeepTiledOutputFile::numXTiles (int lx) const
+{
+ if (lx < 0 || lx >= _data->numXLevels)
+ THROW (IEX_NAMESPACE::LogicExc, "Error calling numXTiles() on image "
+ "file \"" << _data->_streamData->os->fileName() << "\" "
+ "(Argument is not in valid range).");
+
+ return _data->numXTiles[lx];
+}
+
+
+int
+DeepTiledOutputFile::numYTiles (int ly) const
+{
+ if (ly < 0 || ly >= _data->numYLevels)
+ THROW (IEX_NAMESPACE::LogicExc, "Error calling numXTiles() on image "
+ "file \"" << _data->_streamData->os->fileName() << "\" "
+ "(Argument is not in valid range).");
+
+ return _data->numYTiles[ly];
+}
+
+
+Box2i
+DeepTiledOutputFile::dataWindowForLevel (int l) const
+{
+ return dataWindowForLevel (l, l);
+}
+
+
+Box2i
+DeepTiledOutputFile::dataWindowForLevel (int lx, int ly) const
+{
+ try
+ {
+ return OPENEXR_IMF_INTERNAL_NAMESPACE::dataWindowForLevel (
+ _data->tileDesc,
+ _data->minX, _data->maxX,
+ _data->minY, _data->maxY,
+ lx, ly);
+ }
+ catch (IEX_NAMESPACE::BaseExc &e)
+ {
+ REPLACE_EXC (e, "Error calling dataWindowForLevel() on image "
+ "file \"" << fileName() << "\". " << e.what());
+ throw;
+ }
+}
+
+
+Box2i
+DeepTiledOutputFile::dataWindowForTile (int dx, int dy, int l) const
+{
+ return dataWindowForTile (dx, dy, l, l);
+}
+
+
+Box2i
+DeepTiledOutputFile::dataWindowForTile (int dx, int dy, int lx, int ly) const
+{
+ try
+ {
+ if (!isValidTile (dx, dy, lx, ly))
+ throw IEX_NAMESPACE::ArgExc ("Arguments not in valid range.");
+
+ return OPENEXR_IMF_INTERNAL_NAMESPACE::dataWindowForTile (
+ _data->tileDesc,
+ _data->minX, _data->maxX,
+ _data->minY, _data->maxY,
+ dx, dy,
+ lx, ly);
+ }
+ catch (IEX_NAMESPACE::BaseExc &e)
+ {
+ REPLACE_EXC (e, "Error calling dataWindowForTile() on image "
+ "file \"" << fileName() << "\". " << e.what());
+ throw;
+ }
+}
+
+
+bool
+DeepTiledOutputFile::isValidTile (int dx, int dy, int lx, int ly) const
+{
+ return ((lx < _data->numXLevels && lx >= 0) &&
+ (ly < _data->numYLevels && ly >= 0) &&
+ (dx < _data->numXTiles[lx] && dx >= 0) &&
+ (dy < _data->numYTiles[ly] && dy >= 0));
+}
+
+
+void
+DeepTiledOutputFile::updatePreviewImage (const PreviewRgba newPixels[])
+{
+ Lock lock (*_data->_streamData);
+
+ if (_data->previewPosition <= 0)
+ THROW (IEX_NAMESPACE::LogicExc, "Cannot update preview image pixels. "
+ "File \"" << fileName() << "\" does not "
+ "contain a preview image.");
+
+ //
+ // Store the new pixels in the header's preview image attribute.
+ //
+
+ PreviewImageAttribute &pia =
+ _data->header.typedAttribute <PreviewImageAttribute> ("preview");
+
+ PreviewImage &pi = pia.value();
+ PreviewRgba *pixels = pi.pixels();
+ int numPixels = pi.width() * pi.height();
+
+ for (int i = 0; i < numPixels; ++i)
+ pixels[i] = newPixels[i];
+
+ //
+ // Save the current file position, jump to the position in
+ // the file where the preview image starts, store the new
+ // preview image, and jump back to the saved file position.
+ //
+
+ Int64 savedPosition = _data->_streamData->os->tellp();
+
+ try
+ {
+ _data->_streamData->os->seekp (_data->previewPosition);
+ pia.writeValueTo (*_data->_streamData->os, _data->version);
+ _data->_streamData->os->seekp (savedPosition);
+ }
+ catch (IEX_NAMESPACE::BaseExc &e)
+ {
+ REPLACE_EXC (e, "Cannot update preview image pixels for "
+ "file \"" << fileName() << "\". " << e.what());
+ throw;
+ }
+}
+
+
+void
+DeepTiledOutputFile::breakTile
+ (int dx, int dy,
+ int lx, int ly,
+ int offset,
+ int length,
+ char c)
+{
+ Lock lock (*_data->_streamData);
+
+ Int64 position = _data->tileOffsets (dx, dy, lx, ly);
+
+ if (!position)
+ THROW (IEX_NAMESPACE::ArgExc,
+ "Cannot overwrite tile "
+ "(" << dx << ", " << dy << ", " << lx << "," << ly << "). "
+ "The tile has not yet been stored in "
+ "file \"" << fileName() << "\".");
+
+ _data->_streamData->currentPosition = 0;
+ _data->_streamData->os->seekp (position + offset);
+
+ for (int i = 0; i < length; ++i)
+ _data->_streamData->os->write (&c, 1);
+}
+
+OPENEXR_IMF_INTERNAL_NAMESPACE_SOURCE_EXIT
--- /dev/null
+///////////////////////////////////////////////////////////////////////////
+//
+// Copyright (c) 2011, Industrial Light & Magic, a division of Lucas
+// Digital Ltd. LLC
+//
+// All rights reserved.
+//
+// Redistribution and use in source and binary forms, with or without
+// modification, are permitted provided that the following conditions are
+// met:
+// * Redistributions of source code must retain the above copyright
+// notice, this list of conditions and the following disclaimer.
+// * Redistributions in binary form must reproduce the above
+// copyright notice, this list of conditions and the following disclaimer
+// in the documentation and/or other materials provided with the
+// distribution.
+// * Neither the name of Industrial Light & Magic nor the names of
+// its contributors may be used to endorse or promote products derived
+// from this software without specific prior written permission.
+//
+// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+//
+///////////////////////////////////////////////////////////////////////////
+
+
+#ifndef INCLUDED_IMF_DEEP_TILED_OUTPUT_FILE_H
+#define INCLUDED_IMF_DEEP_TILED_OUTPUT_FILE_H
+
+//-----------------------------------------------------------------------------
+//
+// class DeepTiledOutputFile
+//
+//-----------------------------------------------------------------------------
+
+#include "ImfHeader.h"
+#include "ImfFrameBuffer.h"
+#include "ImathBox.h"
+#include "ImfThreading.h"
+#include "ImfGenericOutputFile.h"
+#include "ImfNamespace.h"
+#include "ImfForward.h"
+#include "ImfExport.h"
+
+OPENEXR_IMF_INTERNAL_NAMESPACE_HEADER_ENTER
+
+
+class DeepTiledOutputFile : public GenericOutputFile
+{
+ public:
+
+ //-------------------------------------------------------------------
+ // A constructor that opens the file with the specified name, and
+ // writes the file header. The file header is also copied into the
+ // TiledOutputFile object, and can later be accessed via the header()
+ // method.
+ //
+ // Destroying TiledOutputFile constructed with this constructor
+ // automatically closes the corresponding files.
+ //
+ // The header must contain a TileDescriptionAttribute called "tiles".
+ //
+ // The x and y subsampling factors for all image channels must be 1;
+ // subsampling is not supported.
+ //
+ // Tiles can be written to the file in arbitrary order. The line
+ // order attribute can be used to cause the tiles to be sorted in
+ // the file. When the file is read later, reading the tiles in the
+ // same order as they are in the file tends to be significantly
+ // faster than reading the tiles in random order (see writeTile,
+ // below).
+ //-------------------------------------------------------------------
+
+ IMF_EXPORT
+ DeepTiledOutputFile (const char fileName[],
+ const Header &header,
+ int numThreads = globalThreadCount ());
+
+
+ // ----------------------------------------------------------------
+ // A constructor that attaches the new TiledOutputFile object to
+ // a file that has already been opened. Destroying TiledOutputFile
+ // objects constructed with this constructor does not automatically
+ // close the corresponding files.
+ // ----------------------------------------------------------------
+
+ IMF_EXPORT
+ DeepTiledOutputFile (OPENEXR_IMF_INTERNAL_NAMESPACE::OStream &os,
+ const Header &header,
+ int numThreads = globalThreadCount ());
+
+
+ //-----------------------------------------------------
+ // Destructor
+ //
+ // Destroying a TiledOutputFile object before all tiles
+ // have been written results in an incomplete file.
+ //-----------------------------------------------------
+
+ IMF_EXPORT
+ virtual ~DeepTiledOutputFile ();
+
+
+ //------------------------
+ // Access to the file name
+ //------------------------
+
+ IMF_EXPORT
+ const char * fileName () const;
+
+
+ //--------------------------
+ // Access to the file header
+ //--------------------------
+
+ IMF_EXPORT
+ const Header & header () const;
+
+
+ //-------------------------------------------------------
+ // Set the current frame buffer -- copies the FrameBuffer
+ // object into the TiledOutputFile object.
+ //
+ // The current frame buffer is the source of the pixel
+ // data written to the file. The current frame buffer
+ // must be set at least once before writeTile() is
+ // called. The current frame buffer can be changed
+ // after each call to writeTile().
+ //-------------------------------------------------------
+
+ IMF_EXPORT
+ void setFrameBuffer (const DeepFrameBuffer &frameBuffer);
+
+
+ //-----------------------------------
+ // Access to the current frame buffer
+ //-----------------------------------
+
+ IMF_EXPORT
+ const DeepFrameBuffer & frameBuffer () const;
+
+
+ //-------------------
+ // Utility functions:
+ //-------------------
+
+ //---------------------------------------------------------
+ // Multiresolution mode and tile size:
+ // The following functions return the xSize, ySize and mode
+ // fields of the file header's TileDescriptionAttribute.
+ //---------------------------------------------------------
+
+ IMF_EXPORT
+ unsigned int tileXSize () const;
+ IMF_EXPORT
+ unsigned int tileYSize () const;
+ IMF_EXPORT
+ LevelMode levelMode () const;
+ IMF_EXPORT
+ LevelRoundingMode levelRoundingMode () const;
+
+
+ //--------------------------------------------------------------------
+ // Number of levels:
+ //
+ // numXLevels() returns the file's number of levels in x direction.
+ //
+ // if levelMode() == ONE_LEVEL:
+ // return value is: 1
+ //
+ // if levelMode() == MIPMAP_LEVELS:
+ // return value is: rfunc (log (max (w, h)) / log (2)) + 1
+ //
+ // if levelMode() == RIPMAP_LEVELS:
+ // return value is: rfunc (log (w) / log (2)) + 1
+ //
+ // where
+ // w is the width of the image's data window, max.x - min.x + 1,
+ // y is the height of the image's data window, max.y - min.y + 1,
+ // and rfunc(x) is either floor(x), or ceil(x), depending on
+ // whether levelRoundingMode() returns ROUND_DOWN or ROUND_UP.
+ //
+ // numYLevels() returns the file's number of levels in y direction.
+ //
+ // if levelMode() == ONE_LEVEL or levelMode() == MIPMAP_LEVELS:
+ // return value is the same as for numXLevels()
+ //
+ // if levelMode() == RIPMAP_LEVELS:
+ // return value is: rfunc (log (h) / log (2)) + 1
+ //
+ //
+ // numLevels() is a convenience function for use with MIPMAP_LEVELS
+ // files.
+ //
+ // if levelMode() == ONE_LEVEL or levelMode() == MIPMAP_LEVELS:
+ // return value is the same as for numXLevels()
+ //
+ // if levelMode() == RIPMAP_LEVELS:
+ // an IEX_NAMESPACE::LogicExc exception is thrown
+ //
+ // isValidLevel(lx, ly) returns true if the file contains
+ // a level with level number (lx, ly), false if not.
+ //
+ //--------------------------------------------------------------------
+
+ IMF_EXPORT
+ int numLevels () const;
+ IMF_EXPORT
+ int numXLevels () const;
+ IMF_EXPORT
+ int numYLevels () const;
+ IMF_EXPORT
+ bool isValidLevel (int lx, int ly) const;
+
+
+ //---------------------------------------------------------
+ // Dimensions of a level:
+ //
+ // levelWidth(lx) returns the width of a level with level
+ // number (lx, *), where * is any number.
+ //
+ // return value is:
+ // max (1, rfunc (w / pow (2, lx)))
+ //
+ //
+ // levelHeight(ly) returns the height of a level with level
+ // number (*, ly), where * is any number.
+ //
+ // return value is:
+ // max (1, rfunc (h / pow (2, ly)))
+ //
+ //---------------------------------------------------------
+
+ IMF_EXPORT
+ int levelWidth (int lx) const;
+ IMF_EXPORT
+ int levelHeight (int ly) const;
+
+
+ //----------------------------------------------------------
+ // Number of tiles:
+ //
+ // numXTiles(lx) returns the number of tiles in x direction
+ // that cover a level with level number (lx, *), where * is
+ // any number.
+ //
+ // return value is:
+ // (levelWidth(lx) + tileXSize() - 1) / tileXSize()
+ //
+ //
+ // numYTiles(ly) returns the number of tiles in y direction
+ // that cover a level with level number (*, ly), where * is
+ // any number.
+ //
+ // return value is:
+ // (levelHeight(ly) + tileXSize() - 1) / tileXSize()
+ //
+ //----------------------------------------------------------
+
+ IMF_EXPORT
+ int numXTiles (int lx = 0) const;
+ IMF_EXPORT
+ int numYTiles (int ly = 0) const;
+
+
+ //---------------------------------------------------------
+ // Level pixel ranges:
+ //
+ // dataWindowForLevel(lx, ly) returns a 2-dimensional
+ // region of valid pixel coordinates for a level with
+ // level number (lx, ly)
+ //
+ // return value is a Box2i with min value:
+ // (dataWindow.min.x, dataWindow.min.y)
+ //
+ // and max value:
+ // (dataWindow.min.x + levelWidth(lx) - 1,
+ // dataWindow.min.y + levelHeight(ly) - 1)
+ //
+ // dataWindowForLevel(level) is a convenience function used
+ // for ONE_LEVEL and MIPMAP_LEVELS files. It returns
+ // dataWindowForLevel(level, level).
+ //
+ //---------------------------------------------------------
+
+ IMF_EXPORT
+ IMATH_NAMESPACE::Box2i dataWindowForLevel (int l = 0) const;
+ IMF_EXPORT
+ IMATH_NAMESPACE::Box2i dataWindowForLevel (int lx, int ly) const;
+
+
+ //-------------------------------------------------------------------
+ // Tile pixel ranges:
+ //
+ // dataWindowForTile(dx, dy, lx, ly) returns a 2-dimensional
+ // region of valid pixel coordinates for a tile with tile coordinates
+ // (dx,dy) and level number (lx, ly).
+ //
+ // return value is a Box2i with min value:
+ // (dataWindow.min.x + dx * tileXSize(),
+ // dataWindow.min.y + dy * tileYSize())
+ //
+ // and max value:
+ // (dataWindow.min.x + (dx + 1) * tileXSize() - 1,
+ // dataWindow.min.y + (dy + 1) * tileYSize() - 1)
+ //
+ // dataWindowForTile(dx, dy, level) is a convenience function
+ // used for ONE_LEVEL and MIPMAP_LEVELS files. It returns
+ // dataWindowForTile(dx, dy, level, level).
+ //
+ //-------------------------------------------------------------------
+
+ IMF_EXPORT
+ IMATH_NAMESPACE::Box2i dataWindowForTile (int dx, int dy,
+ int l = 0) const;
+
+ IMF_EXPORT
+ IMATH_NAMESPACE::Box2i dataWindowForTile (int dx, int dy,
+ int lx, int ly) const;
+
+ //------------------------------------------------------------------
+ // Write pixel data:
+ //
+ // writeTile(dx, dy, lx, ly) writes the tile with tile
+ // coordinates (dx, dy), and level number (lx, ly) to
+ // the file.
+ //
+ // dx must lie in the interval [0, numXTiles(lx) - 1]
+ // dy must lie in the interval [0, numYTiles(ly) - 1]
+ //
+ // lx must lie in the interval [0, numXLevels() - 1]
+ // ly must lie in the inverval [0, numYLevels() - 1]
+ //
+ // writeTile(dx, dy, level) is a convenience function
+ // used for ONE_LEVEL and MIPMAP_LEVEL files. It calls
+ // writeTile(dx, dy, level, level).
+ //
+ // The two writeTiles(dx1, dx2, dy1, dy2, ...) functions allow
+ // writing multiple tiles at once. If multi-threading is used
+ // multiple tiles are written concurrently. The tile coordinates,
+ // dx1, dx2 and dy1, dy2, specify inclusive ranges of tile
+ // coordinates. It is valid for dx1 < dx2 or dy1 < dy2; the
+ // tiles are always written in the order specified by the line
+ // order attribute. Hence, it is not possible to specify an
+ // "invalid" or empty tile range.
+ //
+ // Pixels that are outside the pixel coordinate range for the tile's
+ // level, are never accessed by writeTile().
+ //
+ // Each tile in the file must be written exactly once.
+ //
+ // The file's line order attribute determines the order of the tiles
+ // in the file:
+ //
+ // INCREASING_Y In the file, the tiles for each level are stored
+ // in a contiguous block. The levels are ordered
+ // like this:
+ //
+ // (0, 0) (1, 0) ... (nx-1, 0)
+ // (0, 1) (1, 1) ... (nx-1, 1)
+ // ...
+ // (0,ny-1) (1,ny-1) ... (nx-1,ny-1)
+ //
+ // where nx = numXLevels(), and ny = numYLevels().
+ // In an individual level, (lx, ly), the tiles
+ // are stored in the following order:
+ //
+ // (0, 0) (1, 0) ... (tx-1, 0)
+ // (0, 1) (1, 1) ... (tx-1, 1)
+ // ...
+ // (0,ty-1) (1,ty-1) ... (tx-1,ty-1)
+ //
+ // where tx = numXTiles(lx),
+ // and ty = numYTiles(ly).
+ //
+ // DECREASING_Y As for INCREASING_Y, the tiles for each level
+ // are stored in a contiguous block. The levels
+ // are ordered the same way as for INCREASING_Y,
+ // but within an individual level, the tiles
+ // are stored in this order:
+ //
+ // (0,ty-1) (1,ty-1) ... (tx-1,ty-1)
+ // ...
+ // (0, 1) (1, 1) ... (tx-1, 1)
+ // (0, 0) (1, 0) ... (tx-1, 0)
+ //
+ //
+ // RANDOM_Y The order of the calls to writeTile() determines
+ // the order of the tiles in the file.
+ //
+ //------------------------------------------------------------------
+
+ IMF_EXPORT
+ void writeTile (int dx, int dy, int l = 0);
+ IMF_EXPORT
+ void writeTile (int dx, int dy, int lx, int ly);
+
+ IMF_EXPORT
+ void writeTiles (int dx1, int dx2, int dy1, int dy2,
+ int lx, int ly);
+
+ IMF_EXPORT
+ void writeTiles (int dx1, int dx2, int dy1, int dy2,
+ int l = 0);
+
+
+ //------------------------------------------------------------------
+ // Shortcut to copy all pixels from a TiledInputFile into this file,
+ // without uncompressing and then recompressing the pixel data.
+ // This file's header must be compatible with the TiledInputFile's
+ // header: The two header's "dataWindow", "compression",
+ // "lineOrder", "channels", and "tiles" attributes must be the same.
+ //------------------------------------------------------------------
+
+ IMF_EXPORT
+ void copyPixels (DeepTiledInputFile &in);
+ IMF_EXPORT
+ void copyPixels (DeepTiledInputPart &in);
+
+
+
+ //--------------------------------------------------------------
+ // Updating the preview image:
+ //
+ // updatePreviewImage() supplies a new set of pixels for the
+ // preview image attribute in the file's header. If the header
+ // does not contain a preview image, updatePreviewImage() throws
+ // an IEX_NAMESPACE::LogicExc.
+ //
+ // Note: updatePreviewImage() is necessary because images are
+ // often stored in a file incrementally, a few tiles at a time,
+ // while the image is being generated. Since the preview image
+ // is an attribute in the file's header, it gets stored in the
+ // file as soon as the file is opened, but we may not know what
+ // the preview image should look like until we have written the
+ // last tile of the main image.
+ //
+ //--------------------------------------------------------------
+
+ IMF_EXPORT
+ void updatePreviewImage (const PreviewRgba newPixels[]);
+
+
+ //-------------------------------------------------------------
+ // Break a tile -- for testing and debugging only:
+ //
+ // breakTile(dx,dy,lx,ly,p,n,c) introduces an error into the
+ // output file by writing n copies of character c, starting
+ // p bytes from the beginning of the tile with tile coordinates
+ // (dx, dy) and level number (lx, ly).
+ //
+ // Warning: Calling this function usually results in a broken
+ // image file. The file or parts of it may not be readable,
+ // or the file may contain bad data.
+ //
+ //-------------------------------------------------------------
+
+ IMF_EXPORT
+ void breakTile (int dx, int dy,
+ int lx, int ly,
+ int offset,
+ int length,
+ char c);
+ struct Data;
+
+ private:
+
+ // ----------------------------------------------------------------
+ // A constructor attaches the OutputStreamMutex to the
+ // given one from MultiPartOutputFile. Set the previewPosition
+ // and lineOffsetsPosition which have been acquired from
+ // the constructor of MultiPartOutputFile as well.
+ // ----------------------------------------------------------------
+ DeepTiledOutputFile (const OutputPartData* part);
+
+ DeepTiledOutputFile (const DeepTiledOutputFile &); // not implemented
+ DeepTiledOutputFile & operator = (const DeepTiledOutputFile &); // not implemented
+
+ void initialize (const Header &header);
+
+ bool isValidTile (int dx, int dy,
+ int lx, int ly) const;
+
+ size_t bytesPerLineForTile (int dx, int dy,
+ int lx, int ly) const;
+
+ Data * _data;
+
+
+ friend class MultiPartOutputFile;
+
+};
+
+
+OPENEXR_IMF_INTERNAL_NAMESPACE_HEADER_EXIT
+
+#endif
--- /dev/null
+///////////////////////////////////////////////////////////////////////////
+//
+// Copyright (c) 2011, Industrial Light & Magic, a division of Lucas
+// Digital Ltd. LLC
+//
+// All rights reserved.
+//
+// Redistribution and use in source and binary forms, with or without
+// modification, are permitted provided that the following conditions are
+// met:
+// * Redistributions of source code must retain the above copyright
+// notice, this list of conditions and the following disclaimer.
+// * Redistributions in binary form must reproduce the above
+// copyright notice, this list of conditions and the following disclaimer
+// in the documentation and/or other materials provided with the
+// distribution.
+// * Neither the name of Industrial Light & Magic nor the names of
+// its contributors may be used to endorse or promote products derived
+// from this software without specific prior written permission.
+//
+// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+//
+///////////////////////////////////////////////////////////////////////////
+
+#include "ImfDeepTiledOutputPart.h"
+#include "ImfMultiPartOutputFile.h"
+#include "ImfNamespace.h"
+
+OPENEXR_IMF_INTERNAL_NAMESPACE_SOURCE_ENTER
+
+DeepTiledOutputPart::DeepTiledOutputPart(MultiPartOutputFile& multiPartFile, int partNumber)
+{
+ file = multiPartFile.getOutputPart<DeepTiledOutputFile>(partNumber);
+}
+
+const char *
+DeepTiledOutputPart::fileName () const
+{
+ return file->fileName();
+}
+
+
+const Header &
+DeepTiledOutputPart::header () const
+{
+ return file->header();
+}
+
+
+void
+DeepTiledOutputPart::setFrameBuffer (const DeepFrameBuffer &frameBuffer)
+{
+ file->setFrameBuffer(frameBuffer);
+}
+
+
+const DeepFrameBuffer &
+DeepTiledOutputPart::frameBuffer () const
+{
+ return file->frameBuffer();
+}
+
+
+unsigned int
+DeepTiledOutputPart::tileXSize () const
+{
+ return file->tileXSize();
+}
+
+
+unsigned int
+DeepTiledOutputPart::tileYSize () const
+{
+ return file->tileYSize();
+}
+
+
+LevelMode
+DeepTiledOutputPart::levelMode () const
+{
+ return file->levelMode();
+}
+
+
+LevelRoundingMode
+DeepTiledOutputPart::levelRoundingMode () const
+{
+ return file->levelRoundingMode();
+}
+
+
+int
+DeepTiledOutputPart::numLevels () const
+{
+ return file->numLevels();
+}
+
+
+int
+DeepTiledOutputPart::numXLevels () const
+{
+ return file->numXLevels();
+}
+
+
+int
+DeepTiledOutputPart::numYLevels () const
+{
+ return file->numYLevels();
+}
+
+
+bool
+DeepTiledOutputPart::isValidLevel (int lx, int ly) const
+{
+ return file->isValidLevel(lx, ly);
+}
+
+
+int
+DeepTiledOutputPart::levelWidth (int lx) const
+{
+ return file->levelWidth(lx);
+}
+
+
+int
+DeepTiledOutputPart::levelHeight (int ly) const
+{
+ return file->levelHeight(ly);
+}
+
+
+int
+DeepTiledOutputPart::numXTiles (int lx) const
+{
+ return file->numXTiles(lx);
+}
+
+
+int
+DeepTiledOutputPart::numYTiles (int ly) const
+{
+ return file->numYTiles(ly);
+}
+
+
+
+IMATH_NAMESPACE::Box2i
+DeepTiledOutputPart::dataWindowForLevel (int l) const
+{
+ return file->dataWindowForLevel(l);
+}
+
+
+IMATH_NAMESPACE::Box2i
+DeepTiledOutputPart::dataWindowForLevel (int lx, int ly) const
+{
+ return file->dataWindowForLevel(lx, ly);
+}
+
+
+IMATH_NAMESPACE::Box2i
+DeepTiledOutputPart::dataWindowForTile (int dx, int dy,
+ int l) const
+{
+ return file->dataWindowForTile(dx, dy, l);
+}
+
+
+IMATH_NAMESPACE::Box2i
+DeepTiledOutputPart::dataWindowForTile (int dx, int dy,
+ int lx, int ly) const
+{
+ return file->dataWindowForTile(dx, dy, lx, ly);
+}
+
+
+void
+DeepTiledOutputPart::writeTile (int dx, int dy, int l)
+{
+ file->writeTile(dx, dy, l);
+}
+
+
+void
+DeepTiledOutputPart::writeTile (int dx, int dy, int lx, int ly)
+{
+ file->writeTile(dx, dy, lx, ly);
+}
+
+
+void
+DeepTiledOutputPart::writeTiles (int dx1, int dx2, int dy1, int dy2,
+ int lx, int ly)
+{
+ file->writeTiles(dx1, dx2, dy1, dy2, lx, ly);
+}
+
+
+void
+DeepTiledOutputPart::writeTiles (int dx1, int dx2, int dy1, int dy2,
+ int l)
+{
+ file->writeTiles(dx1, dx2, dy1, dy2, l);
+}
+
+
+void
+DeepTiledOutputPart::copyPixels (DeepTiledInputFile &in)
+{
+ file->copyPixels(in);
+}
+
+
+void
+DeepTiledOutputPart::copyPixels (DeepTiledInputPart &in)
+{
+ file->copyPixels(in);
+}
+
+
+void
+DeepTiledOutputPart::updatePreviewImage (const PreviewRgba newPixels[])
+{
+ file->updatePreviewImage(newPixels);
+}
+
+
+void
+DeepTiledOutputPart::breakTile (int dx, int dy,
+ int lx, int ly,
+ int offset,
+ int length,
+ char c)
+{
+ file->breakTile(dx, dy, lx, ly, offset, length, c);
+}
+
+OPENEXR_IMF_INTERNAL_NAMESPACE_SOURCE_EXIT
--- /dev/null
+///////////////////////////////////////////////////////////////////////////
+//
+// Copyright (c) 2011, Industrial Light & Magic, a division of Lucas
+// Digital Ltd. LLC
+//
+// All rights reserved.
+//
+// Redistribution and use in source and binary forms, with or without
+// modification, are permitted provided that the following conditions are
+// met:
+// * Redistributions of source code must retain the above copyright
+// notice, this list of conditions and the following disclaimer.
+// * Redistributions in binary form must reproduce the above
+// copyright notice, this list of conditions and the following disclaimer
+// in the documentation and/or other materials provided with the
+// distribution.
+// * Neither the name of Industrial Light & Magic nor the names of
+// its contributors may be used to endorse or promote products derived
+// from this software without specific prior written permission.
+//
+// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+//
+///////////////////////////////////////////////////////////////////////////
+
+#ifndef IMFDEEPTILEDOUTPUTPART_H_
+#define IMFDEEPTILEDOUTPUTPART_H_
+
+#include "ImfForward.h"
+#include "ImfDeepTiledInputFile.h"
+#include "ImfNamespace.h"
+#include "ImfExport.h"
+
+
+OPENEXR_IMF_INTERNAL_NAMESPACE_HEADER_ENTER
+
+
+class DeepTiledOutputPart
+{
+ public:
+
+ IMF_EXPORT
+ DeepTiledOutputPart(MultiPartOutputFile& multiPartFile, int partNumber);
+
+ //------------------------
+ // Access to the file name
+ //------------------------
+
+ IMF_EXPORT
+ const char * fileName () const;
+
+
+ //--------------------------
+ // Access to the file header
+ //--------------------------
+
+ IMF_EXPORT
+ const Header & header () const;
+
+
+ //-------------------------------------------------------
+ // Set the current frame buffer -- copies the FrameBuffer
+ // object into the TiledOutputFile object.
+ //
+ // The current frame buffer is the source of the pixel
+ // data written to the file. The current frame buffer
+ // must be set at least once before writeTile() is
+ // called. The current frame buffer can be changed
+ // after each call to writeTile().
+ //-------------------------------------------------------
+
+ IMF_EXPORT
+ void setFrameBuffer (const DeepFrameBuffer &frameBuffer);
+
+
+ //-----------------------------------
+ // Access to the current frame buffer
+ //-----------------------------------
+
+ IMF_EXPORT
+ const DeepFrameBuffer & frameBuffer () const;
+
+
+ //-------------------
+ // Utility functions:
+ //-------------------
+
+ //---------------------------------------------------------
+ // Multiresolution mode and tile size:
+ // The following functions return the xSize, ySize and mode
+ // fields of the file header's TileDescriptionAttribute.
+ //---------------------------------------------------------
+
+ IMF_EXPORT
+ unsigned int tileXSize () const;
+ IMF_EXPORT
+ unsigned int tileYSize () const;
+ IMF_EXPORT
+ LevelMode levelMode () const;
+ IMF_EXPORT
+ LevelRoundingMode levelRoundingMode () const;
+
+
+ //--------------------------------------------------------------------
+ // Number of levels:
+ //
+ // numXLevels() returns the file's number of levels in x direction.
+ //
+ // if levelMode() == ONE_LEVEL:
+ // return value is: 1
+ //
+ // if levelMode() == MIPMAP_LEVELS:
+ // return value is: rfunc (log (max (w, h)) / log (2)) + 1
+ //
+ // if levelMode() == RIPMAP_LEVELS:
+ // return value is: rfunc (log (w) / log (2)) + 1
+ //
+ // where
+ // w is the width of the image's data window, max.x - min.x + 1,
+ // y is the height of the image's data window, max.y - min.y + 1,
+ // and rfunc(x) is either floor(x), or ceil(x), depending on
+ // whether levelRoundingMode() returns ROUND_DOWN or ROUND_UP.
+ //
+ // numYLevels() returns the file's number of levels in y direction.
+ //
+ // if levelMode() == ONE_LEVEL or levelMode() == MIPMAP_LEVELS:
+ // return value is the same as for numXLevels()
+ //
+ // if levelMode() == RIPMAP_LEVELS:
+ // return value is: rfunc (log (h) / log (2)) + 1
+ //
+ //
+ // numLevels() is a convenience function for use with MIPMAP_LEVELS
+ // files.
+ //
+ // if levelMode() == ONE_LEVEL or levelMode() == MIPMAP_LEVELS:
+ // return value is the same as for numXLevels()
+ //
+ // if levelMode() == RIPMAP_LEVELS:
+ // an IEX_NAMESPACE::LogicExc exception is thrown
+ //
+ // isValidLevel(lx, ly) returns true if the file contains
+ // a level with level number (lx, ly), false if not.
+ //
+ //--------------------------------------------------------------------
+
+ IMF_EXPORT
+ int numLevels () const;
+ IMF_EXPORT
+ int numXLevels () const;
+ IMF_EXPORT
+ int numYLevels () const;
+ IMF_EXPORT
+ bool isValidLevel (int lx, int ly) const;
+
+
+ //---------------------------------------------------------
+ // Dimensions of a level:
+ //
+ // levelWidth(lx) returns the width of a level with level
+ // number (lx, *), where * is any number.
+ //
+ // return value is:
+ // max (1, rfunc (w / pow (2, lx)))
+ //
+ //
+ // levelHeight(ly) returns the height of a level with level
+ // number (*, ly), where * is any number.
+ //
+ // return value is:
+ // max (1, rfunc (h / pow (2, ly)))
+ //
+ //---------------------------------------------------------
+
+ IMF_EXPORT
+ int levelWidth (int lx) const;
+ IMF_EXPORT
+ int levelHeight (int ly) const;
+
+
+ //----------------------------------------------------------
+ // Number of tiles:
+ //
+ // numXTiles(lx) returns the number of tiles in x direction
+ // that cover a level with level number (lx, *), where * is
+ // any number.
+ //
+ // return value is:
+ // (levelWidth(lx) + tileXSize() - 1) / tileXSize()
+ //
+ //
+ // numYTiles(ly) returns the number of tiles in y direction
+ // that cover a level with level number (*, ly), where * is
+ // any number.
+ //
+ // return value is:
+ // (levelHeight(ly) + tileXSize() - 1) / tileXSize()
+ //
+ //----------------------------------------------------------
+
+ IMF_EXPORT
+ int numXTiles (int lx = 0) const;
+ IMF_EXPORT
+ int numYTiles (int ly = 0) const;
+
+
+ //---------------------------------------------------------
+ // Level pixel ranges:
+ //
+ // dataWindowForLevel(lx, ly) returns a 2-dimensional
+ // region of valid pixel coordinates for a level with
+ // level number (lx, ly)
+ //
+ // return value is a Box2i with min value:
+ // (dataWindow.min.x, dataWindow.min.y)
+ //
+ // and max value:
+ // (dataWindow.min.x + levelWidth(lx) - 1,
+ // dataWindow.min.y + levelHeight(ly) - 1)
+ //
+ // dataWindowForLevel(level) is a convenience function used
+ // for ONE_LEVEL and MIPMAP_LEVELS files. It returns
+ // dataWindowForLevel(level, level).
+ //
+ //---------------------------------------------------------
+
+ IMF_EXPORT
+ IMATH_NAMESPACE::Box2i dataWindowForLevel (int l = 0) const;
+ IMF_EXPORT
+ IMATH_NAMESPACE::Box2i dataWindowForLevel (int lx, int ly) const;
+
+
+ //-------------------------------------------------------------------
+ // Tile pixel ranges:
+ //
+ // dataWindowForTile(dx, dy, lx, ly) returns a 2-dimensional
+ // region of valid pixel coordinates for a tile with tile coordinates
+ // (dx,dy) and level number (lx, ly).
+ //
+ // return value is a Box2i with min value:
+ // (dataWindow.min.x + dx * tileXSize(),
+ // dataWindow.min.y + dy * tileYSize())
+ //
+ // and max value:
+ // (dataWindow.min.x + (dx + 1) * tileXSize() - 1,
+ // dataWindow.min.y + (dy + 1) * tileYSize() - 1)
+ //
+ // dataWindowForTile(dx, dy, level) is a convenience function
+ // used for ONE_LEVEL and MIPMAP_LEVELS files. It returns
+ // dataWindowForTile(dx, dy, level, level).
+ //
+ //-------------------------------------------------------------------
+
+ IMF_EXPORT
+ IMATH_NAMESPACE::Box2i dataWindowForTile (int dx, int dy,
+ int l = 0) const;
+
+ IMF_EXPORT
+ IMATH_NAMESPACE::Box2i dataWindowForTile (int dx, int dy,
+ int lx, int ly) const;
+
+ //------------------------------------------------------------------
+ // Write pixel data:
+ //
+ // writeTile(dx, dy, lx, ly) writes the tile with tile
+ // coordinates (dx, dy), and level number (lx, ly) to
+ // the file.
+ //
+ // dx must lie in the interval [0, numXTiles(lx) - 1]
+ // dy must lie in the interval [0, numYTiles(ly) - 1]
+ //
+ // lx must lie in the interval [0, numXLevels() - 1]
+ // ly must lie in the inverval [0, numYLevels() - 1]
+ //
+ // writeTile(dx, dy, level) is a convenience function
+ // used for ONE_LEVEL and MIPMAP_LEVEL files. It calls
+ // writeTile(dx, dy, level, level).
+ //
+ // The two writeTiles(dx1, dx2, dy1, dy2, ...) functions allow
+ // writing multiple tiles at once. If multi-threading is used
+ // multiple tiles are written concurrently. The tile coordinates,
+ // dx1, dx2 and dy1, dy2, specify inclusive ranges of tile
+ // coordinates. It is valid for dx1 < dx2 or dy1 < dy2; the
+ // tiles are always written in the order specified by the line
+ // order attribute. Hence, it is not possible to specify an
+ // "invalid" or empty tile range.
+ //
+ // Pixels that are outside the pixel coordinate range for the tile's
+ // level, are never accessed by writeTile().
+ //
+ // Each tile in the file must be written exactly once.
+ //
+ // The file's line order attribute determines the order of the tiles
+ // in the file:
+ //
+ // INCREASING_Y In the file, the tiles for each level are stored
+ // in a contiguous block. The levels are ordered
+ // like this:
+ //
+ // (0, 0) (1, 0) ... (nx-1, 0)
+ // (0, 1) (1, 1) ... (nx-1, 1)
+ // ...
+ // (0,ny-1) (1,ny-1) ... (nx-1,ny-1)
+ //
+ // where nx = numXLevels(), and ny = numYLevels().
+ // In an individual level, (lx, ly), the tiles
+ // are stored in the following order:
+ //
+ // (0, 0) (1, 0) ... (tx-1, 0)
+ // (0, 1) (1, 1) ... (tx-1, 1)
+ // ...
+ // (0,ty-1) (1,ty-1) ... (tx-1,ty-1)
+ //
+ // where tx = numXTiles(lx),
+ // and ty = numYTiles(ly).
+ //
+ // DECREASING_Y As for INCREASING_Y, the tiles for each level
+ // are stored in a contiguous block. The levels
+ // are ordered the same way as for INCREASING_Y,
+ // but within an individual level, the tiles
+ // are stored in this order:
+ //
+ // (0,ty-1) (1,ty-1) ... (tx-1,ty-1)
+ // ...
+ // (0, 1) (1, 1) ... (tx-1, 1)
+ // (0, 0) (1, 0) ... (tx-1, 0)
+ //
+ //
+ // RANDOM_Y The order of the calls to writeTile() determines
+ // the order of the tiles in the file.
+ //
+ //------------------------------------------------------------------
+
+ IMF_EXPORT
+ void writeTile (int dx, int dy, int l = 0);
+ IMF_EXPORT
+ void writeTile (int dx, int dy, int lx, int ly);
+
+ IMF_EXPORT
+ void writeTiles (int dx1, int dx2, int dy1, int dy2,
+ int lx, int ly);
+
+ IMF_EXPORT
+ void writeTiles (int dx1, int dx2, int dy1, int dy2,
+ int l = 0);
+
+
+ //------------------------------------------------------------------
+ // Shortcut to copy all pixels from a TiledInputFile into this file,
+ // without uncompressing and then recompressing the pixel data.
+ // This file's header must be compatible with the TiledInputFile's
+ // header: The two header's "dataWindow", "compression",
+ // "lineOrder", "channels", and "tiles" attributes must be the same.
+ //------------------------------------------------------------------
+
+ IMF_EXPORT
+ void copyPixels (DeepTiledInputFile &in);
+ IMF_EXPORT
+ void copyPixels (DeepTiledInputPart &in);
+
+
+
+
+ //--------------------------------------------------------------
+ // Updating the preview image:
+ //
+ // updatePreviewImage() supplies a new set of pixels for the
+ // preview image attribute in the file's header. If the header
+ // does not contain a preview image, updatePreviewImage() throws
+ // an IEX_NAMESPACE::LogicExc.
+ //
+ // Note: updatePreviewImage() is necessary because images are
+ // often stored in a file incrementally, a few tiles at a time,
+ // while the image is being generated. Since the preview image
+ // is an attribute in the file's header, it gets stored in the
+ // file as soon as the file is opened, but we may not know what
+ // the preview image should look like until we have written the
+ // last tile of the main image.
+ //
+ //--------------------------------------------------------------
+
+ IMF_EXPORT
+ void updatePreviewImage (const PreviewRgba newPixels[]);
+
+
+ //-------------------------------------------------------------
+ // Break a tile -- for testing and debugging only:
+ //
+ // breakTile(dx,dy,lx,ly,p,n,c) introduces an error into the
+ // output file by writing n copies of character c, starting
+ // p bytes from the beginning of the tile with tile coordinates
+ // (dx, dy) and level number (lx, ly).
+ //
+ // Warning: Calling this function usually results in a broken
+ // image file. The file or parts of it may not be readable,
+ // or the file may contain bad data.
+ //
+ //-------------------------------------------------------------
+
+ IMF_EXPORT
+ void breakTile (int dx, int dy,
+ int lx, int ly,
+ int offset,
+ int length,
+ char c);
+
+ private:
+ DeepTiledOutputFile* file;
+
+};
+
+OPENEXR_IMF_INTERNAL_NAMESPACE_HEADER_EXIT
+
+#endif /* IMFDEEPTILEDOUTPUTPART_H_ */
//
// Copyright (c) 2002, Industrial Light & Magic, a division of Lucas
// Digital Ltd. LLC
-//
+//
// All rights reserved.
-//
+//
// Redistribution and use in source and binary forms, with or without
// modification, are permitted provided that the following conditions are
// met:
// distribution.
// * Neither the name of Industrial Light & Magic nor the names of
// its contributors may be used to endorse or promote products derived
-// from this software without specific prior written permission.
-//
+// from this software without specific prior written permission.
+//
// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
#include <ImfDoubleAttribute.h>
-namespace Imf {
+OPENEXR_IMF_INTERNAL_NAMESPACE_SOURCE_ENTER
template <>
}
-} // namespace Imf
+OPENEXR_IMF_INTERNAL_NAMESPACE_SOURCE_EXIT
//
// Copyright (c) 2002, Industrial Light & Magic, a division of Lucas
// Digital Ltd. LLC
-//
+//
// All rights reserved.
-//
+//
// Redistribution and use in source and binary forms, with or without
// modification, are permitted provided that the following conditions are
// met:
// distribution.
// * Neither the name of Industrial Light & Magic nor the names of
// its contributors may be used to endorse or promote products derived
-// from this software without specific prior written permission.
-//
+// from this software without specific prior written permission.
+//
// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
//
//-----------------------------------------------------------------------------
-#include <ImfAttribute.h>
+#include "ImfAttribute.h"
+#include "ImfExport.h"
-
-namespace Imf {
+OPENEXR_IMF_INTERNAL_NAMESPACE_HEADER_ENTER
typedef TypedAttribute<double> DoubleAttribute;
-template <> const char *DoubleAttribute::staticTypeName ();
+template <> IMF_EXPORT const char *DoubleAttribute::staticTypeName ();
-} // namespace Imf
+OPENEXR_IMF_INTERNAL_NAMESPACE_HEADER_EXIT
-// Metrowerks compiler wants the .cpp file inlined, too
-#ifdef __MWERKS__
-#include <ImfDoubleAttribute.cpp>
-#endif
#endif
--- /dev/null
+///////////////////////////////////////////////////////////////////////////
+//
+// Copyright (c) 2009-2014 DreamWorks Animation LLC.
+//
+// All rights reserved.
+//
+// Redistribution and use in source and binary forms, with or without
+// modification, are permitted provided that the following conditions are
+// met:
+// * Redistributions of source code must retain the above copyright
+// notice, this list of conditions and the following disclaimer.
+// * Redistributions in binary form must reproduce the above
+// copyright notice, this list of conditions and the following disclaimer
+// in the documentation and/or other materials provided with the
+// distribution.
+// * Neither the name of DreamWorks Animation nor the names of
+// its contributors may be used to endorse or promote products derived
+// from this software without specific prior written permission.
+//
+// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+//
+///////////////////////////////////////////////////////////////////////////
+
+//---------------------------------------------------
+//
+// class DwaCompressor -- Store lossy RGB data by quantizing
+// DCT components.
+//
+// First, we try and figure out what compression strategy to take
+// based in channel name. For RGB channels, we want a lossy method
+// described below. But, if we have alpha, we should do something
+// different (and probably using RLE). If we have depth, or velocity,
+// or something else, just fall back to ZIP. The rules for deciding
+// which strategy to use are setup in initializeDefaultChannelRules().
+// When writing a file, the relevant rules needed to decode are written
+// into the start of the data block, making a self-contained file.
+// If initializeDefaultChannelRules() doesn't quite suite your naming
+// conventions, you can adjust the rules without breaking decoder
+// compatability.
+//
+// If we're going to lossy compress R, G, or B channels, it's easier
+// to toss bits in a more perceptual uniform space. One could argue
+// at length as to what constitutes perceptually uniform, expecially
+// when storing either scene/input/focal plane referred and output referred
+// data.
+//
+// We'll compromise. For values <= 1, we use a traditional power function
+// (without any of that straight-line business at the bottom). For values > 1,
+// we want something more like a log function, since power functions blow
+// up. At 1, we want a smooth blend between the functions. So, we use a
+// piecewise function that does just that - see dwaLookups.cpp for
+// a little more detail.
+//
+// Also, if we find that we have R, G, and B channels from the same layer,
+// we can get a bit more compression efficiency by transforming to a Y'CbCr
+// space. We use the 709 transform, but with Cb,Cr = 0 for an input of
+// (0, 0, 0), instead of the traditional Cb,Cr = .5. Shifting the zero point
+// makes no sense with large range data. Transforms are done to from
+// the perceptual space data, not the linear-light space data (R'G'B' ->
+// (Y'CbCr, not RGB -> YCbCr).
+//
+// Next, we forward DCT the data. This is done with a floating
+// point DCT, as we don't really have control over the src range. The
+// resulting values are dropped to half-float precision.
+//
+// Now, we need to quantize. Quantization departs from the usual way
+// of dividing and rounding. Instead, we start with some floating
+// point "base-error" value. From this, we can derive quantization
+// error for each DCT component. Take the standard JPEG quantization
+// tables and normalize them by the smallest value. Then, multiply
+// the normalized quant tables by our base-error value. This gives
+// a range of errors for each DCT component.
+//
+// For each DCT component, we want to find a quantized value that
+// is within +- the per-component error. Pick the quantized value
+// that has the fewest bits set in its' binary representation.
+// Brute-forcing the search would make for extremly inefficient
+// compression. Fortunatly, we can precompute a table to assist
+// with this search.
+//
+// For each 16-bit float value, there are at most 15 other values with
+// fewer bits set. We can precompute these values in a compact form, since
+// many source values have far fewer that 15 possible quantized values.
+// Now, instead of searching the entire range +- the component error,
+// we can just search at most 15 quantization candidates. The search can
+// be accelerated a bit more by sorting the candidates by the
+// number of bits set, in increasing order. Then, the search can stop
+// once a candidate is found w/i the per-component quantization
+// error range.
+//
+// The quantization strategy has the side-benefit that there is no
+// de-quantization step upon decode, so we don't bother recording
+// the quantization table.
+//
+// Ok. So we now have quantized values. Time for entropy coding. We
+// can use either static Huffman or zlib/DEFLATE. The static Huffman
+// is more efficient at compacting data, but can have a greater
+// overhead, especially for smaller tile/strip sizes.
+//
+// There is some additional fun, like ZIP compressing the DC components
+// instead of Huffman/zlib, which helps make things slightly smaller.
+//
+// Compression level is controlled by setting an int/float/double attribute
+// on the header named "dwaCompressionLevel". This is a thinly veiled name for
+// the "base-error" value mentioned above. The "base-error" is just
+// dwaCompressionLevel / 100000. The default value of 45.0 is generally
+// pretty good at generating "visually lossless" values at reasonable
+// data rates. Setting dwaCompressionLevel to 0 should result in no additional
+// quantization at the quantization stage (though there may be
+// quantization in practice at the CSC/DCT steps). But if you really
+// want lossless compression, there are pleanty of other choices
+// of compressors ;)
+//
+// When dealing with FLOAT source buffers, we first quantize the source
+// to HALF and continue down as we would for HALF source.
+//
+//---------------------------------------------------
+
+
+#include "ImfDwaCompressor.h"
+#include "ImfDwaCompressorSimd.h"
+
+#include "ImfChannelList.h"
+#include "ImfStandardAttributes.h"
+#include "ImfHeader.h"
+#include "ImfHuf.h"
+#include "ImfInt64.h"
+#include "ImfIntAttribute.h"
+#include "ImfIO.h"
+#include "ImfMisc.h"
+#include "ImfNamespace.h"
+#include "ImfRle.h"
+#include "ImfSimd.h"
+#include "ImfSystemSpecific.h"
+#include "ImfXdr.h"
+#include "ImfZip.h"
+
+#include "ImathFun.h"
+#include "ImathBox.h"
+#include "ImathVec.h"
+#include "half.h"
+#include "halfLimits.h"
+
+#include "dwaLookups.h"
+
+#include <vector>
+#include <string>
+#include <cctype>
+#include <cassert>
+#include <algorithm>
+
+// Windows specific addition to prevent the indirect import of the redefined min/max macros
+#if defined _WIN32 || defined _WIN64
+ #ifdef NOMINMAX
+ #undef NOMINMAX
+ #endif
+ #define NOMINMAX
+#endif
+#include <zlib.h>
+
+
+OPENEXR_IMF_INTERNAL_NAMESPACE_SOURCE_ENTER
+
+
+namespace {
+
+ //
+ // Function pointer to dispatch to an approprate
+ // convertFloatToHalf64_* impl, based on runtime cpu checking.
+ // Should be initialized in DwaCompressor::initializeFuncs()
+ //
+
+ void (*convertFloatToHalf64)(unsigned short*, float*) =
+ convertFloatToHalf64_scalar;
+
+ //
+ // Function pointer for dispatching a fromHalfZigZag_ impl
+ //
+
+ void (*fromHalfZigZag)(unsigned short*, float*) =
+ fromHalfZigZag_scalar;
+
+ //
+ // Dispatch the inverse DCT on an 8x8 block, where the last
+ // n rows can be all zeros. The n=0 case converts the full block.
+ //
+ void (*dctInverse8x8_0)(float*) = dctInverse8x8_scalar<0>;
+ void (*dctInverse8x8_1)(float*) = dctInverse8x8_scalar<1>;
+ void (*dctInverse8x8_2)(float*) = dctInverse8x8_scalar<2>;
+ void (*dctInverse8x8_3)(float*) = dctInverse8x8_scalar<3>;
+ void (*dctInverse8x8_4)(float*) = dctInverse8x8_scalar<4>;
+ void (*dctInverse8x8_5)(float*) = dctInverse8x8_scalar<5>;
+ void (*dctInverse8x8_6)(float*) = dctInverse8x8_scalar<6>;
+ void (*dctInverse8x8_7)(float*) = dctInverse8x8_scalar<7>;
+
+} // namespace
+
+
+struct DwaCompressor::ChannelData
+{
+ std::string name;
+ CompressorScheme compression;
+ int xSampling;
+ int ySampling;
+ PixelType type;
+ bool pLinear;
+
+ int width;
+ int height;
+
+ //
+ // Incoming and outgoing data is scanline interleaved, and it's much
+ // easier to operate on contiguous data. Assuming the planare unc
+ // buffer is to hold RLE data, we need to rearrange to make bytes
+ // adjacent.
+ //
+
+ char *planarUncBuffer;
+ char *planarUncBufferEnd;
+
+ char *planarUncRle[4];
+ char *planarUncRleEnd[4];
+
+ PixelType planarUncType;
+ int planarUncSize;
+};
+
+
+struct DwaCompressor::CscChannelSet
+{
+ int idx[3];
+};
+
+
+struct DwaCompressor::Classifier
+{
+ Classifier (std::string suffix,
+ CompressorScheme scheme,
+ PixelType type,
+ int cscIdx,
+ bool caseInsensitive):
+ _suffix(suffix),
+ _scheme(scheme),
+ _type(type),
+ _cscIdx(cscIdx),
+ _caseInsensitive(caseInsensitive)
+ {
+ if (caseInsensitive)
+ std::transform(_suffix.begin(), _suffix.end(), _suffix.begin(), tolower);
+ }
+
+ Classifier (const char *&ptr, int size)
+ {
+ if (size <= 0)
+ throw IEX_NAMESPACE::InputExc("Error uncompressing DWA data"
+ " (truncated rule).");
+
+ {
+ char suffix[Name::SIZE];
+ memset (suffix, 0, Name::SIZE);
+ Xdr::read<CharPtrIO> (ptr, std::min(size, Name::SIZE-1), suffix);
+ _suffix = std::string(suffix);
+ }
+
+ if (size < _suffix.length() + 1 + 2*Xdr::size<char>())
+ throw IEX_NAMESPACE::InputExc("Error uncompressing DWA data"
+ " (truncated rule).");
+
+ char value;
+ Xdr::read<CharPtrIO> (ptr, value);
+
+ _cscIdx = (int)(value >> 4) - 1;
+ if (_cscIdx < -1 || _cscIdx >= 3)
+ throw IEX_NAMESPACE::InputExc("Error uncompressing DWA data"
+ " (corrupt cscIdx rule).");
+
+ _scheme = (CompressorScheme)((value >> 2) & 3);
+ if (_scheme < 0 || _scheme >= NUM_COMPRESSOR_SCHEMES)
+ throw IEX_NAMESPACE::InputExc("Error uncompressing DWA data"
+ " (corrupt scheme rule).");
+
+ _caseInsensitive = (value & 1 ? true : false);
+
+ Xdr::read<CharPtrIO> (ptr, value);
+ if (value < 0 || value >= NUM_PIXELTYPES)
+ throw IEX_NAMESPACE::InputExc("Error uncompressing DWA data"
+ " (corrupt rule).");
+ _type = (PixelType)value;
+ }
+
+ bool match (const std::string &suffix, const PixelType type) const
+ {
+ if (_type != type) return false;
+
+ if (_caseInsensitive)
+ {
+ std::string tmp(suffix);
+ std::transform(tmp.begin(), tmp.end(), tmp.begin(), tolower);
+ return tmp == _suffix;
+ }
+
+ return suffix == _suffix;
+ }
+
+ size_t size () const
+ {
+ // string length + \0
+ size_t sizeBytes = _suffix.length() + 1;
+
+ // 1 byte for scheme / cscIdx / caseInsensitive, and 1 byte for type
+ sizeBytes += 2 * Xdr::size<char>();
+
+ return sizeBytes;
+ }
+
+ void write (char *&ptr) const
+ {
+ Xdr::write<CharPtrIO> (ptr, _suffix.c_str());
+
+ // Encode _cscIdx (-1-3) in the upper 4 bits,
+ // _scheme (0-2) in the next 2 bits
+ // _caseInsen in the bottom bit
+ unsigned char value = 0;
+ value |= ((unsigned char)(_cscIdx+1) & 15) << 4;
+ value |= ((unsigned char)_scheme & 3) << 2;
+ value |= (unsigned char)_caseInsensitive & 1;
+
+ Xdr::write<CharPtrIO> (ptr, value);
+ Xdr::write<CharPtrIO> (ptr, (unsigned char)_type);
+ }
+
+ std::string _suffix;
+ CompressorScheme _scheme;
+ PixelType _type;
+ int _cscIdx;
+ bool _caseInsensitive;
+};
+
+
+//
+// Base class for the LOSSY_DCT decoder classes
+//
+
+class DwaCompressor::LossyDctDecoderBase
+{
+ public:
+
+ LossyDctDecoderBase
+ (char *packedAc,
+ char *packedDc,
+ const unsigned short *toLinear,
+ int width,
+ int height);
+
+ virtual ~LossyDctDecoderBase ();
+
+ void execute();
+
+ //
+ // These return number of items, not bytes. Each item
+ // is an unsigned short
+ //
+
+ int numAcValuesEncoded() const { return _packedAcCount; }
+ int numDcValuesEncoded() const { return _packedDcCount; }
+
+ protected:
+
+ //
+ // Un-RLE the packed AC components into
+ // a half buffer. The half block should
+ // be the full 8x8 block (in zig-zag order
+ // still), not the first AC component.
+ //
+ // currAcComp is advanced as bytes are decoded.
+ //
+ // This returns the index of the last non-zero
+ // value in the buffer - with the index into zig zag
+ // order data. If we return 0, we have DC only data.
+ //
+
+ int unRleAc (unsigned short *&currAcComp,
+ unsigned short *halfZigBlock);
+
+
+ //
+ // if NATIVE and XDR are really the same values, we can
+ // skip some processing and speed things along
+ //
+
+ bool _isNativeXdr;
+
+
+ //
+ // Counts of how many items have been packed into the
+ // AC and DC buffers
+ //
+
+ int _packedAcCount;
+ int _packedDcCount;
+
+
+ //
+ // AC and DC buffers to pack
+ //
+
+ char *_packedAc;
+ char *_packedDc;
+
+
+ //
+ // half -> half LUT to transform from nonlinear to linear
+ //
+
+ const unsigned short *_toLinear;
+
+
+ //
+ // image dimensions
+ //
+
+ int _width;
+ int _height;
+
+
+ //
+ // Pointers to the start of each scanlines, to be filled on decode
+ // Generally, these will be filled by the subclasses.
+ //
+
+ std::vector< std::vector<char *> > _rowPtrs;
+
+
+ //
+ // The type of each data that _rowPtrs[i] is referring. Layout
+ // is in the same order as _rowPtrs[].
+ //
+
+ std::vector<PixelType> _type;
+ std::vector<SimdAlignedBuffer64f> _dctData;
+};
+
+
+//
+// Used to decode a single channel of LOSSY_DCT data.
+//
+
+class DwaCompressor::LossyDctDecoder: public LossyDctDecoderBase
+{
+ public:
+
+ //
+ // toLinear is a half-float LUT to convert the encoded values
+ // back to linear light. If you want to skip this step, pass
+ // in NULL here.
+ //
+
+ LossyDctDecoder
+ (std::vector<char *> &rowPtrs,
+ char *packedAc,
+ char *packedDc,
+ const unsigned short *toLinear,
+ int width,
+ int height,
+ PixelType type)
+ :
+ LossyDctDecoderBase(packedAc, packedDc, toLinear, width, height)
+ {
+ _rowPtrs.push_back(rowPtrs);
+ _type.push_back(type);
+ }
+
+ virtual ~LossyDctDecoder () {}
+};
+
+
+//
+// Used to decode 3 channels of LOSSY_DCT data that
+// are grouped together and color space converted.
+//
+
+class DwaCompressor::LossyDctDecoderCsc: public LossyDctDecoderBase
+{
+ public:
+
+ //
+ // toLinear is a half-float LUT to convert the encoded values
+ // back to linear light. If you want to skip this step, pass
+ // in NULL here.
+ //
+
+ LossyDctDecoderCsc
+ (std::vector<char *> &rowPtrsR,
+ std::vector<char *> &rowPtrsG,
+ std::vector<char *> &rowPtrsB,
+ char *packedAc,
+ char *packedDc,
+ const unsigned short *toLinear,
+ int width,
+ int height,
+ PixelType typeR,
+ PixelType typeG,
+ PixelType typeB)
+ :
+ LossyDctDecoderBase(packedAc, packedDc, toLinear, width, height)
+ {
+ _rowPtrs.push_back(rowPtrsR);
+ _rowPtrs.push_back(rowPtrsG);
+ _rowPtrs.push_back(rowPtrsB);
+ _type.push_back(typeR);
+ _type.push_back(typeG);
+ _type.push_back(typeB);
+ }
+
+ virtual ~LossyDctDecoderCsc () {}
+};
+
+
+//
+// Base class for encoding using the lossy DCT scheme
+//
+
+class DwaCompressor::LossyDctEncoderBase
+{
+ public:
+
+ LossyDctEncoderBase
+ (float quantBaseError,
+ char *packedAc,
+ char *packedDc,
+ const unsigned short *toNonlinear,
+ int width,
+ int height);
+
+ virtual ~LossyDctEncoderBase ();
+
+ void execute ();
+
+ //
+ // These return number of items, not bytes. Each item
+ // is an unsigned short
+ //
+
+ int numAcValuesEncoded () const {return _numAcComp;}
+ int numDcValuesEncoded () const {return _numDcComp;}
+
+ protected:
+
+ void toZigZag (half *dst, half *src);
+ int countSetBits (unsigned short src);
+ half quantize (half src, float errorTolerance);
+ void rleAc (half *block, unsigned short *&acPtr);
+
+ float _quantBaseError;
+
+ int _width,
+ _height;
+ const unsigned short *_toNonlinear;
+
+ int _numAcComp,
+ _numDcComp;
+
+ std::vector< std::vector<const char *> > _rowPtrs;
+ std::vector<PixelType> _type;
+ std::vector<SimdAlignedBuffer64f> _dctData;
+
+
+ //
+ // Pointers to the buffers where AC and DC
+ // DCT components should be packed for
+ // lossless compression downstream
+ //
+
+ char *_packedAc;
+ char *_packedDc;
+
+
+ //
+ // Our "quantization tables" - the example JPEG tables,
+ // normalized so that the smallest value in each is 1.0.
+ // This gives us a relationship between error in DCT
+ // components
+ //
+
+ float _quantTableY[64];
+ float _quantTableCbCr[64];
+};
+
+
+
+//
+// Single channel lossy DCT encoder
+//
+
+class DwaCompressor::LossyDctEncoder: public LossyDctEncoderBase
+{
+ public:
+
+ LossyDctEncoder
+ (float quantBaseError,
+ std::vector<const char *> &rowPtrs,
+ char *packedAc,
+ char *packedDc,
+ const unsigned short *toNonlinear,
+ int width,
+ int height,
+ PixelType type)
+ :
+ LossyDctEncoderBase
+ (quantBaseError, packedAc, packedDc, toNonlinear, width, height)
+ {
+ _rowPtrs.push_back(rowPtrs);
+ _type.push_back(type);
+ }
+
+ virtual ~LossyDctEncoder () {}
+};
+
+
+//
+// RGB channel lossy DCT encoder
+//
+
+class DwaCompressor::LossyDctEncoderCsc: public LossyDctEncoderBase
+{
+ public:
+
+ LossyDctEncoderCsc
+ (float quantBaseError,
+ std::vector<const char *> &rowPtrsR,
+ std::vector<const char *> &rowPtrsG,
+ std::vector<const char *> &rowPtrsB,
+ char *packedAc,
+ char *packedDc,
+ const unsigned short *toNonlinear,
+ int width,
+ int height,
+ PixelType typeR,
+ PixelType typeG,
+ PixelType typeB)
+ :
+ LossyDctEncoderBase
+ (quantBaseError, packedAc, packedDc, toNonlinear, width, height)
+ {
+ _type.push_back(typeR);
+ _type.push_back(typeG);
+ _type.push_back(typeB);
+
+ _rowPtrs.push_back(rowPtrsR);
+ _rowPtrs.push_back(rowPtrsG);
+ _rowPtrs.push_back(rowPtrsB);
+ }
+
+ virtual ~LossyDctEncoderCsc () {}
+};
+
+
+// ==============================================================
+//
+// LossyDctDecoderBase
+//
+// --------------------------------------------------------------
+
+DwaCompressor::LossyDctDecoderBase::LossyDctDecoderBase
+ (char *packedAc,
+ char *packedDc,
+ const unsigned short *toLinear,
+ int width,
+ int height)
+:
+ _isNativeXdr(false),
+ _packedAcCount(0),
+ _packedDcCount(0),
+ _packedAc(packedAc),
+ _packedDc(packedDc),
+ _toLinear(toLinear),
+ _width(width),
+ _height(height)
+{
+ if (_toLinear == 0)
+ _toLinear = get_dwaCompressorNoOp();
+
+ _isNativeXdr = GLOBAL_SYSTEM_LITTLE_ENDIAN;
+}
+
+
+DwaCompressor::LossyDctDecoderBase::~LossyDctDecoderBase () {}
+
+
+void
+DwaCompressor::LossyDctDecoderBase::execute ()
+{
+ int numComp = _rowPtrs.size();
+ int lastNonZero = 0;
+ int numBlocksX = (int) ceil ((float)_width / 8.0f);
+ int numBlocksY = (int) ceil ((float)_height / 8.0f);
+ int leftoverX = _width - (numBlocksX-1) * 8;
+ int leftoverY = _height - (numBlocksY-1) * 8;
+
+ int numFullBlocksX = (int)floor ((float)_width / 8.0f);
+
+ unsigned short tmpShortNative = 0;
+ unsigned short tmpShortXdr = 0;
+ const char *tmpConstCharPtr = 0;
+
+ unsigned short *currAcComp = (unsigned short *)_packedAc;
+ std::vector<unsigned short *> currDcComp (_rowPtrs.size());
+ std::vector<SimdAlignedBuffer64us> halfZigBlock (_rowPtrs.size());
+
+ if (_type.size() != _rowPtrs.size())
+ throw IEX_NAMESPACE::BaseExc ("Row pointers and types mismatch in count");
+
+ if ((_rowPtrs.size() != 3) && (_rowPtrs.size() != 1))
+ throw IEX_NAMESPACE::NoImplExc ("Only 1 and 3 channel encoding is supported");
+
+ _dctData.resize(numComp);
+
+ //
+ // Allocate a temp aligned buffer to hold a rows worth of full
+ // 8x8 half-float blocks
+ //
+
+ unsigned char *rowBlockHandle = new unsigned char
+ [numComp * numBlocksX * 64 * sizeof(unsigned short) + _SSE_ALIGNMENT];
+
+ unsigned short *rowBlock[3];
+
+ rowBlock[0] = (unsigned short*)rowBlockHandle;
+
+ for (int i = 0; i < _SSE_ALIGNMENT; ++i)
+ {
+ if (((size_t)(rowBlockHandle + i) & _SSE_ALIGNMENT_MASK) == 0)
+ rowBlock[0] = (unsigned short *)(rowBlockHandle + i);
+ }
+
+ for (int comp = 1; comp < numComp; ++comp)
+ rowBlock[comp] = rowBlock[comp - 1] + numBlocksX * 64;
+
+ //
+ // Pack DC components together by common plane, so we can get
+ // a little more out of differencing them. We'll always have
+ // one component per block, so we can computed offsets.
+ //
+
+ currDcComp[0] = (unsigned short *)_packedDc;
+
+ for (unsigned int comp = 1; comp < numComp; ++comp)
+ currDcComp[comp] = currDcComp[comp - 1] + numBlocksX * numBlocksY;
+
+ for (int blocky = 0; blocky < numBlocksY; ++blocky)
+ {
+ int maxY = 8;
+
+ if (blocky == numBlocksY-1)
+ maxY = leftoverY;
+
+ int maxX = 8;
+
+ for (int blockx = 0; blockx < numBlocksX; ++blockx)
+ {
+ if (blockx == numBlocksX-1)
+ maxX = leftoverX;
+
+ //
+ // If we can detect that the block is constant values
+ // (all components only have DC values, and all AC is 0),
+ // we can do everything only on 1 value, instead of all
+ // 64.
+ //
+ // This won't really help for regular images, but it is
+ // meant more for layers with large swaths of black
+ //
+
+ bool blockIsConstant = true;
+
+ for (unsigned int comp = 0; comp < numComp; ++comp)
+ {
+
+ //
+ // DC component is stored separately
+ //
+
+ #ifdef IMF_HAVE_SSE2
+ {
+ __m128i *dst = (__m128i*)halfZigBlock[comp]._buffer;
+
+ dst[7] = _mm_setzero_si128();
+ dst[6] = _mm_setzero_si128();
+ dst[5] = _mm_setzero_si128();
+ dst[4] = _mm_setzero_si128();
+ dst[3] = _mm_setzero_si128();
+ dst[2] = _mm_setzero_si128();
+ dst[1] = _mm_setzero_si128();
+ dst[0] = _mm_insert_epi16
+ (_mm_setzero_si128(), *currDcComp[comp]++, 0);
+ }
+ #else /* IMF_HAVE_SSE2 */
+
+ memset (halfZigBlock[comp]._buffer, 0, 64 * 2);
+ halfZigBlock[comp]._buffer[0] = *currDcComp[comp]++;
+
+ #endif /* IMF_HAVE_SSE2 */
+
+ _packedDcCount++;
+
+ //
+ // UnRLE the AC. This will modify currAcComp
+ //
+
+ lastNonZero = unRleAc (currAcComp, halfZigBlock[comp]._buffer);
+
+ //
+ // Convert from XDR to NATIVE
+ //
+
+ if (!_isNativeXdr)
+ {
+ for (int i = 0; i < 64; ++i)
+ {
+ tmpShortXdr = halfZigBlock[comp]._buffer[i];
+ tmpConstCharPtr = (const char *)&tmpShortXdr;
+
+ Xdr::read<CharPtrIO> (tmpConstCharPtr, tmpShortNative);
+
+ halfZigBlock[comp]._buffer[i] = tmpShortNative;
+ }
+ }
+
+ if (lastNonZero == 0)
+ {
+ //
+ // DC only case - AC components are all 0
+ //
+
+ half h;
+
+ h.setBits (halfZigBlock[comp]._buffer[0]);
+ _dctData[comp]._buffer[0] = (float)h;
+
+ dctInverse8x8DcOnly (_dctData[comp]._buffer);
+ }
+ else
+ {
+ //
+ // We have some AC components that are non-zero.
+ // Can't use the 'constant block' optimization
+ //
+
+ blockIsConstant = false;
+
+ //
+ // Un-Zig zag
+ //
+
+ (*fromHalfZigZag)
+ (halfZigBlock[comp]._buffer, _dctData[comp]._buffer);
+
+ //
+ // Zig-Zag indices in normal layout are as follows:
+ //
+ // 0 1 5 6 14 15 27 28
+ // 2 4 7 13 16 26 29 42
+ // 3 8 12 17 25 30 41 43
+ // 9 11 18 24 31 40 44 53
+ // 10 19 23 32 39 45 52 54
+ // 20 22 33 38 46 51 55 60
+ // 21 34 37 47 50 56 59 61
+ // 35 36 48 49 57 58 62 63
+ //
+ // If lastNonZero is less than the first item on
+ // each row, we know that the whole row is zero and
+ // can be skipped in the row-oriented part of the
+ // iDCT.
+ //
+ // The unrolled logic here is:
+ //
+ // if lastNonZero < rowStartIdx[i],
+ // zeroedRows = rowsEmpty[i]
+ //
+ // where:
+ //
+ // const int rowStartIdx[] = {2, 3, 9, 10, 20, 21, 35};
+ // const int rowsEmpty[] = {7, 6, 5, 4, 3, 2, 1};
+ //
+
+ if (lastNonZero < 2)
+ dctInverse8x8_7(_dctData[comp]._buffer);
+ else if (lastNonZero < 3)
+ dctInverse8x8_6(_dctData[comp]._buffer);
+ else if (lastNonZero < 9)
+ dctInverse8x8_5(_dctData[comp]._buffer);
+ else if (lastNonZero < 10)
+ dctInverse8x8_4(_dctData[comp]._buffer);
+ else if (lastNonZero < 20)
+ dctInverse8x8_3(_dctData[comp]._buffer);
+ else if (lastNonZero < 21)
+ dctInverse8x8_2(_dctData[comp]._buffer);
+ else if (lastNonZero < 35)
+ dctInverse8x8_1(_dctData[comp]._buffer);
+ else
+ dctInverse8x8_0(_dctData[comp]._buffer);
+ }
+ }
+
+ //
+ // Perform the CSC
+ //
+
+ if (numComp == 3)
+ {
+ if (!blockIsConstant)
+ {
+ csc709Inverse64 (_dctData[0]._buffer,
+ _dctData[1]._buffer,
+ _dctData[2]._buffer);
+
+ }
+ else
+ {
+ csc709Inverse (_dctData[0]._buffer[0],
+ _dctData[1]._buffer[0],
+ _dctData[2]._buffer[0]);
+ }
+ }
+
+ //
+ // Float -> Half conversion.
+ //
+ // If the block has a constant value, just convert the first pixel.
+ //
+
+ for (unsigned int comp = 0; comp < numComp; ++comp)
+ {
+ if (!blockIsConstant)
+ {
+ (*convertFloatToHalf64)
+ (&rowBlock[comp][blockx*64], _dctData[comp]._buffer);
+ }
+ else
+ {
+ #ifdef IMF_HAVE_SSE2
+
+ __m128i *dst = (__m128i*)&rowBlock[comp][blockx*64];
+
+ dst[0] = _mm_set1_epi16
+ (((half)_dctData[comp]._buffer[0]).bits());
+
+ dst[1] = dst[0];
+ dst[2] = dst[0];
+ dst[3] = dst[0];
+ dst[4] = dst[0];
+ dst[5] = dst[0];
+ dst[6] = dst[0];
+ dst[7] = dst[0];
+
+ #else /* IMF_HAVE_SSE2 */
+
+ unsigned short *dst = &rowBlock[comp][blockx*64];
+
+ dst[0] = ((half)_dctData[comp]._buffer[0]).bits();
+
+ for (int i = 1; i < 64; ++i)
+ {
+ dst[i] = dst[0];
+ }
+
+ #endif /* IMF_HAVE_SSE2 */
+ } // blockIsConstant
+ } // comp
+ } // blockx
+
+ //
+ // At this point, we have half-float nonlinear value blocked
+ // in rowBlock[][]. We need to unblock the data, transfer
+ // back to linear, and write the results in the _rowPtrs[].
+ //
+ // There is a fast-path for aligned rows, which helps
+ // things a little. Since this fast path is only valid
+ // for full 8-element wide blocks, the partial x blocks
+ // are broken into a separate loop below.
+ //
+ // At the moment, the fast path requires:
+ // * sse support
+ // * aligned row pointers
+ // * full 8-element wide blocks
+ //
+
+ for (int comp = 0; comp < numComp; ++comp)
+ {
+ //
+ // Test if we can use the fast path
+ //
+
+ #ifdef IMF_HAVE_SSE2
+
+ bool fastPath = true;
+
+ for (int y = 8 * blocky; y < 8 * blocky + maxY; ++y)
+ {
+ if ((size_t)_rowPtrs[comp][y] & _SSE_ALIGNMENT_MASK)
+ fastPath = false;
+ }
+
+ if (fastPath)
+ {
+ //
+ // Handle all the full X blocks, in a fast path with sse2 and
+ // aligned row pointers
+ //
+
+ for (int y=8*blocky; y<8*blocky+maxY; ++y)
+ {
+ __m128i *dst = (__m128i *)_rowPtrs[comp][y];
+ __m128i *src = (__m128i *)&rowBlock[comp][(y & 0x7) * 8];
+
+
+ for (int blockx = 0; blockx < numFullBlocksX; ++blockx)
+ {
+ //
+ // These may need some twiddling.
+ // Run with multiples of 8
+ //
+
+ _mm_prefetch ((char *)(src + 16), _MM_HINT_NTA);
+
+ unsigned short i0 = _mm_extract_epi16 (*src, 0);
+ unsigned short i1 = _mm_extract_epi16 (*src, 1);
+ unsigned short i2 = _mm_extract_epi16 (*src, 2);
+ unsigned short i3 = _mm_extract_epi16 (*src, 3);
+
+ unsigned short i4 = _mm_extract_epi16 (*src, 4);
+ unsigned short i5 = _mm_extract_epi16 (*src, 5);
+ unsigned short i6 = _mm_extract_epi16 (*src, 6);
+ unsigned short i7 = _mm_extract_epi16 (*src, 7);
+
+ i0 = _toLinear[i0];
+ i1 = _toLinear[i1];
+ i2 = _toLinear[i2];
+ i3 = _toLinear[i3];
+
+ i4 = _toLinear[i4];
+ i5 = _toLinear[i5];
+ i6 = _toLinear[i6];
+ i7 = _toLinear[i7];
+
+ *dst = _mm_insert_epi16 (_mm_setzero_si128(), i0, 0);
+ *dst = _mm_insert_epi16 (*dst, i1, 1);
+ *dst = _mm_insert_epi16 (*dst, i2, 2);
+ *dst = _mm_insert_epi16 (*dst, i3, 3);
+
+ *dst = _mm_insert_epi16 (*dst, i4, 4);
+ *dst = _mm_insert_epi16 (*dst, i5, 5);
+ *dst = _mm_insert_epi16 (*dst, i6, 6);
+ *dst = _mm_insert_epi16 (*dst, i7, 7);
+
+ src += 8;
+ dst++;
+ }
+ }
+ }
+ else
+ {
+
+ #endif /* IMF_HAVE_SSE2 */
+
+ //
+ // Basic scalar kinda slow path for handling the full X blocks
+ //
+
+ for (int y = 8 * blocky; y < 8 * blocky + maxY; ++y)
+ {
+ unsigned short *dst = (unsigned short *)_rowPtrs[comp][y];
+
+ for (int blockx = 0; blockx < numFullBlocksX; ++blockx)
+ {
+ unsigned short *src =
+ &rowBlock[comp][blockx * 64 + ((y & 0x7) * 8)];
+
+ dst[0] = _toLinear[src[0]];
+ dst[1] = _toLinear[src[1]];
+ dst[2] = _toLinear[src[2]];
+ dst[3] = _toLinear[src[3]];
+
+ dst[4] = _toLinear[src[4]];
+ dst[5] = _toLinear[src[5]];
+ dst[6] = _toLinear[src[6]];
+ dst[7] = _toLinear[src[7]];
+
+ dst += 8;
+ }
+ }
+
+ #ifdef IMF_HAVE_SSE2
+
+ }
+
+ #endif /* IMF_HAVE_SSE2 */
+
+ //
+ // If we have partial X blocks, deal with all those now
+ // Since this should be minimal work, there currently
+ // is only one path that should work for everyone.
+ //
+
+ if (numFullBlocksX != numBlocksX)
+ {
+ for (int y = 8 * blocky; y < 8 * blocky + maxY; ++y)
+ {
+ unsigned short *src = (unsigned short *)
+ &rowBlock[comp][numFullBlocksX * 64 + ((y & 0x7) * 8)];
+
+ unsigned short *dst = (unsigned short *)_rowPtrs[comp][y];
+
+ dst += 8 * numFullBlocksX;
+
+ for (int x = 0; x < maxX; ++x)
+ {
+ *dst++ = _toLinear[*src++];
+ }
+ }
+ }
+ } // comp
+ } // blocky
+
+ //
+ // Walk over all the channels that are of type FLOAT.
+ // Convert from HALF XDR back to FLOAT XDR.
+ //
+
+ for (unsigned int chan = 0; chan < numComp; ++chan)
+ {
+
+ if (_type[chan] != FLOAT)
+ continue;
+
+ std::vector<unsigned short> halfXdr (_width);
+
+ for (int y=0; y<_height; ++y)
+ {
+ char *floatXdrPtr = _rowPtrs[chan][y];
+
+ memcpy(&halfXdr[0], floatXdrPtr, _width*sizeof(unsigned short));
+
+ const char *halfXdrPtr = (const char *)(&halfXdr[0]);
+
+ for (int x=0; x<_width; ++x)
+ {
+ half tmpHalf;
+
+ Xdr::read<CharPtrIO> (halfXdrPtr, tmpHalf);
+ Xdr::write<CharPtrIO> (floatXdrPtr, (float)tmpHalf);
+
+ //
+ // Xdr::write and Xdr::read will advance the ptrs
+ //
+ }
+ }
+ }
+
+ delete[] rowBlockHandle;
+}
+
+
+//
+// Un-RLE the packed AC components into
+// a half buffer. The half block should
+// be the full 8x8 block (in zig-zag order
+// still), not the first AC component.
+//
+// currAcComp is advanced as bytes are decoded.
+//
+// This returns the index of the last non-zero
+// value in the buffer - with the index into zig zag
+// order data. If we return 0, we have DC only data.
+//
+// This is assuminging that halfZigBlock is zero'ed
+// prior to calling
+//
+
+int
+DwaCompressor::LossyDctDecoderBase::unRleAc
+ (unsigned short *&currAcComp,
+ unsigned short *halfZigBlock)
+{
+ //
+ // Un-RLE the RLE'd blocks. If we find an item whose
+ // high byte is 0xff, then insert the number of 0's
+ // as indicated by the low byte.
+ //
+ // Otherwise, just copy the number verbaitm.
+ //
+
+ int lastNonZero = 0;
+ int dctComp = 1;
+
+ //
+ // Start with a zero'ed block, so we don't have to
+ // write when we hit a run symbol
+ //
+
+ while (dctComp < 64)
+ {
+ if (*currAcComp == 0xff00)
+ {
+ //
+ // End of block
+ //
+
+ dctComp = 64;
+
+ }
+ else if ((*currAcComp) >> 8 == 0xff)
+ {
+ //
+ // Run detected! Insert 0's.
+ //
+ // Since the block has been zeroed, just advance the ptr
+ //
+
+ dctComp += (*currAcComp) & 0xff;
+ }
+ else
+ {
+ //
+ // Not a run, just copy over the value
+ //
+
+ lastNonZero = dctComp;
+ halfZigBlock[dctComp] = *currAcComp;
+
+ dctComp++;
+ }
+
+ _packedAcCount++;
+ currAcComp++;
+ }
+
+ return lastNonZero;
+}
+
+
+// ==============================================================
+//
+// LossyDctEncoderBase
+//
+// --------------------------------------------------------------
+
+DwaCompressor::LossyDctEncoderBase::LossyDctEncoderBase
+ (float quantBaseError,
+ char *packedAc,
+ char *packedDc,
+ const unsigned short *toNonlinear,
+ int width,
+ int height)
+:
+ _quantBaseError(quantBaseError),
+ _width(width),
+ _height(height),
+ _toNonlinear(toNonlinear),
+ _numAcComp(0),
+ _numDcComp(0),
+ _packedAc(packedAc),
+ _packedDc(packedDc)
+{
+ //
+ // Here, we take the generic JPEG quantization tables and
+ // normalize them by the smallest component in each table.
+ // This gives us a relationship amongst the DCT components,
+ // in terms of how sensitive each component is to
+ // error.
+ //
+ // A higher normalized value means we can quantize more,
+ // and a small normalized value means we can quantize less.
+ //
+ // Eventually, we will want an acceptable quantization
+ // error range for each component. We find this by
+ // multiplying some user-specified level (_quantBaseError)
+ // by the normalized table (_quantTableY, _quantTableCbCr) to
+ // find the acceptable quantization error range.
+ //
+ // The quantization table is not needed for decoding, and
+ // is not transmitted. So, if you want to get really fancy,
+ // you could derive some content-dependent quantization
+ // table, and the decoder would not need to be changed. But,
+ // for now, we'll just use statice quantization tables.
+ //
+
+ int jpegQuantTableY[] =
+ {
+ 16, 11, 10, 16, 24, 40, 51, 61,
+ 12, 12, 14, 19, 26, 58, 60, 55,
+ 14, 13, 16, 24, 40, 57, 69, 56,
+ 14, 17, 22, 29, 51, 87, 80, 62,
+ 18, 22, 37, 56, 68, 109, 103, 77,
+ 24, 35, 55, 64, 81, 104, 113, 92,
+ 49, 64, 78, 87, 103, 121, 120, 101,
+ 72, 92, 95, 98, 112, 100, 103, 99
+ };
+
+ int jpegQuantTableYMin = 10;
+
+ int jpegQuantTableCbCr[] =
+ {
+ 17, 18, 24, 47, 99, 99, 99, 99,
+ 18, 21, 26, 66, 99, 99, 99, 99,
+ 24, 26, 56, 99, 99, 99, 99, 99,
+ 47, 66, 99, 99, 99, 99, 99, 99,
+ 99, 99, 99, 99, 99, 99, 99, 99,
+ 99, 99, 99, 99, 99, 99, 99, 99,
+ 99, 99, 99, 99, 99, 99, 99, 99,
+ 99, 99, 99, 99, 99, 99, 99, 99
+ };
+
+ int jpegQuantTableCbCrMin = 17;
+
+ for (int idx = 0; idx < 64; ++idx)
+ {
+ _quantTableY[idx] = static_cast<float> (jpegQuantTableY[idx]) /
+ static_cast<float> (jpegQuantTableYMin);
+
+ _quantTableCbCr[idx] = static_cast<float> (jpegQuantTableCbCr[idx]) /
+ static_cast<float> (jpegQuantTableCbCrMin);
+ }
+
+ if (_quantBaseError < 0)
+ quantBaseError = 0;
+}
+
+
+DwaCompressor::LossyDctEncoderBase::~LossyDctEncoderBase ()
+{
+}
+
+
+//
+// Given three channels of source data, encoding by first applying
+// a color space conversion to a YCbCr space. Otherwise, if we only
+// have one channel, just encode it as is.
+//
+// Other numbers of channels are somewhat unexpected at this point,
+// and will throw an exception.
+//
+
+void
+DwaCompressor::LossyDctEncoderBase::execute ()
+{
+ int numBlocksX = (int)ceil ((float)_width / 8.0f);
+ int numBlocksY = (int)ceil ((float)_height/ 8.0f);
+
+ half halfZigCoef[64];
+ half halfCoef[64];
+
+ std::vector<unsigned short *> currDcComp (_rowPtrs.size());
+ unsigned short *currAcComp = (unsigned short *)_packedAc;
+
+ _dctData.resize (_rowPtrs.size());
+ _numAcComp = 0;
+ _numDcComp = 0;
+
+ assert (_type.size() == _rowPtrs.size());
+ assert ((_rowPtrs.size() == 3) || (_rowPtrs.size() == 1));
+
+ //
+ // Allocate a temp half buffer to quantize into for
+ // any FLOAT source channels.
+ //
+
+ int tmpHalfBufferElements = 0;
+
+ for (unsigned int chan = 0; chan < _rowPtrs.size(); ++chan)
+ if (_type[chan] == FLOAT)
+ tmpHalfBufferElements += _width * _height;
+
+ std::vector<unsigned short> tmpHalfBuffer (tmpHalfBufferElements);
+
+ char *tmpHalfBufferPtr = 0;
+
+ if (tmpHalfBufferElements)
+ tmpHalfBufferPtr = (char *)&tmpHalfBuffer[0];
+
+ //
+ // Run over all the float scanlines, quantizing,
+ // and re-assigning _rowPtr[y]. We need to translate
+ // FLOAT XDR to HALF XDR.
+ //
+
+ for (unsigned int chan = 0; chan < _rowPtrs.size(); ++chan)
+ {
+ if (_type[chan] != FLOAT)
+ continue;
+
+ for (int y = 0; y < _height; ++y)
+ {
+ float src = 0;
+ const char *srcXdr = _rowPtrs[chan][y];
+ char *dstXdr = tmpHalfBufferPtr;
+
+ for (int x = 0; x < _width; ++x)
+ {
+
+ Xdr::read<CharPtrIO> (srcXdr, src);
+
+ //
+ // Clamp to half ranges, instead of just casting. This
+ // avoids introducing Infs which end up getting zeroed later
+ //
+ src = std::max (
+ std::min ((float) std::numeric_limits<half>::max(), src),
+ (float)-std::numeric_limits<half>::max());
+
+ Xdr::write<CharPtrIO> (dstXdr, ((half)src).bits());
+
+ //
+ // Xdr::read and Xdr::write will advance the ptr
+ //
+ }
+
+ _rowPtrs[chan][y] = (const char *)tmpHalfBufferPtr;
+ tmpHalfBufferPtr += _width * sizeof (unsigned short);
+ }
+ }
+
+ //
+ // Pack DC components together by common plane, so we can get
+ // a little more out of differencing them. We'll always have
+ // one component per block, so we can computed offsets.
+ //
+
+ currDcComp[0] = (unsigned short *)_packedDc;
+
+ for (unsigned int chan = 1; chan < _rowPtrs.size(); ++chan)
+ currDcComp[chan] = currDcComp[chan-1] + numBlocksX * numBlocksY;
+
+ for (int blocky = 0; blocky < numBlocksY; ++blocky)
+ {
+ for (int blockx = 0; blockx < numBlocksX; ++blockx)
+ {
+ half h;
+ unsigned short tmpShortXdr, tmpShortNative;
+ char *tmpCharPtr;
+
+ for (unsigned int chan = 0; chan < _rowPtrs.size(); ++chan)
+ {
+ //
+ // Break the source into 8x8 blocks. If we don't
+ // fit at the edges, mirror.
+ //
+ // Also, convert from linear to nonlinear representation.
+ // Our source is assumed to be XDR, and we need to convert
+ // to NATIVE prior to converting to float.
+ //
+ // If we're converting linear -> nonlinear, assume that the
+ // XDR -> NATIVE conversion is built into the lookup. Otherwise,
+ // we'll need to explicitly do it.
+ //
+
+ for (int y = 0; y < 8; ++y)
+ {
+ for (int x = 0; x < 8; ++x)
+ {
+ int vx = 8 * blockx + x;
+ int vy = 8 * blocky + y;
+
+ if (vx >= _width)
+ vx = _width - (vx - (_width - 1));
+
+ if (vx < 0) vx = _width-1;
+
+ if (vy >=_height)
+ vy = _height - (vy - (_height - 1));
+
+ if (vy < 0) vy = _height-1;
+
+ tmpShortXdr =
+ ((const unsigned short *)(_rowPtrs[chan])[vy])[vx];
+
+ if (_toNonlinear)
+ {
+ h.setBits (_toNonlinear[tmpShortXdr]);
+ }
+ else
+ {
+ const char *tmpConstCharPtr =
+ (const char *)(&tmpShortXdr);
+
+ Xdr::read<CharPtrIO>
+ (tmpConstCharPtr, tmpShortNative);
+
+ h.setBits(tmpShortNative);
+ }
+
+ _dctData[chan]._buffer[y * 8 + x] = (float)h;
+ } // x
+ } // y
+ } // chan
+
+ //
+ // Color space conversion
+ //
+
+ if (_rowPtrs.size() == 3)
+ {
+ csc709Forward64 (_dctData[0]._buffer,
+ _dctData[1]._buffer,
+ _dctData[2]._buffer);
+ }
+
+ for (unsigned int chan = 0; chan < _rowPtrs.size(); ++chan)
+ {
+ //
+ // Forward DCT
+ //
+
+ dctForward8x8(_dctData[chan]._buffer);
+
+ //
+ // Quantize to half, and zigzag
+ //
+
+ if (chan == 0)
+ {
+ for (int i = 0; i < 64; ++i)
+ {
+ halfCoef[i] =
+ quantize ((half)_dctData[chan]._buffer[i],
+ _quantBaseError*_quantTableY[i]);
+ }
+ }
+ else
+ {
+ for (int i = 0; i < 64; ++i)
+ {
+ halfCoef[i] =
+ quantize ((half)_dctData[chan]._buffer[i],
+ _quantBaseError*_quantTableCbCr[i]);
+ }
+ }
+
+ toZigZag (halfZigCoef, halfCoef);
+
+ //
+ // Convert from NATIVE back to XDR, before we write out
+ //
+
+ for (int i = 0; i < 64; ++i)
+ {
+ tmpCharPtr = (char *)&tmpShortXdr;
+ Xdr::write<CharPtrIO>(tmpCharPtr, halfZigCoef[i].bits());
+ halfZigCoef[i].setBits(tmpShortXdr);
+ }
+
+ //
+ // Save the DC component separately, to be compressed on
+ // its own.
+ //
+
+ *currDcComp[chan]++ = halfZigCoef[0].bits();
+ _numDcComp++;
+
+ //
+ // Then RLE the AC components (which will record the count
+ // of the resulting number of items)
+ //
+
+ rleAc (halfZigCoef, currAcComp);
+ } // chan
+ } // blockx
+ } // blocky
+}
+
+
+//
+// Reorder from zig-zag order to normal ordering
+//
+
+void
+DwaCompressor::LossyDctEncoderBase::toZigZag (half *dst, half *src)
+{
+ const int remap[] =
+ {
+ 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
+ };
+
+ for (int i=0; i<64; ++i)
+ dst[i] = src[remap[i]];
+}
+
+
+//
+// Precomputing the bit count runs faster than using
+// the builtin instruction, at least in one case..
+//
+// Precomputing 8-bits is no slower than 16-bits,
+// and saves a fair bit of overhead..
+//
+
+int
+DwaCompressor::LossyDctEncoderBase::countSetBits (unsigned short src)
+{
+ static const unsigned short numBitsSet[256] =
+ {
+ 0, 1, 1, 2, 1, 2, 2, 3, 1, 2, 2, 3, 2, 3, 3, 4,
+ 1, 2, 2, 3, 2, 3, 3, 4, 2, 3, 3, 4, 3, 4, 4, 5,
+ 1, 2, 2, 3, 2, 3, 3, 4, 2, 3, 3, 4, 3, 4, 4, 5,
+ 2, 3, 3, 4, 3, 4, 4, 5, 3, 4, 4, 5, 4, 5, 5, 6,
+ 1, 2, 2, 3, 2, 3, 3, 4, 2, 3, 3, 4, 3, 4, 4, 5,
+ 2, 3, 3, 4, 3, 4, 4, 5, 3, 4, 4, 5, 4, 5, 5, 6,
+ 2, 3, 3, 4, 3, 4, 4, 5, 3, 4, 4, 5, 4, 5, 5, 6,
+ 3, 4, 4, 5, 4, 5, 5, 6, 4, 5, 5, 6, 5, 6, 6, 7,
+ 1, 2, 2, 3, 2, 3, 3, 4, 2, 3, 3, 4, 3, 4, 4, 5,
+ 2, 3, 3, 4, 3, 4, 4, 5, 3, 4, 4, 5, 4, 5, 5, 6,
+ 2, 3, 3, 4, 3, 4, 4, 5, 3, 4, 4, 5, 4, 5, 5, 6,
+ 3, 4, 4, 5, 4, 5, 5, 6, 4, 5, 5, 6, 5, 6, 6, 7,
+ 2, 3, 3, 4, 3, 4, 4, 5, 3, 4, 4, 5, 4, 5, 5, 6,
+ 3, 4, 4, 5, 4, 5, 5, 6, 4, 5, 5, 6, 5, 6, 6, 7,
+ 3, 4, 4, 5, 4, 5, 5, 6, 4, 5, 5, 6, 5, 6, 6, 7,
+ 4, 5, 5, 6, 5, 6, 6, 7, 5, 6, 6, 7, 6, 7, 7, 8
+ };
+
+ return numBitsSet[src & 0xff] + numBitsSet[src >> 8];
+}
+
+
+//
+// Take a DCT coefficient, as well as an acceptable error. Search
+// nearby values within the error tolerance, that have fewer
+// bits set.
+//
+// The list of candidates has been pre-computed and sorted
+// in order of increasing numbers of bits set. This way, we
+// can stop searching as soon as we find a candidate that
+// is within the error tolerance.
+//
+
+half
+DwaCompressor::LossyDctEncoderBase::quantize (half src, float errorTolerance)
+{
+ half tmp;
+ float srcFloat = (float)src;
+ int numSetBits = countSetBits(src.bits());
+ const unsigned short *closest = get_dwaClosest(src.bits());
+
+ for (int targetNumSetBits = numSetBits - 1;
+ targetNumSetBits >= 0;
+ --targetNumSetBits)
+ {
+ tmp.setBits (*closest);
+
+ if (fabs ((float)tmp - srcFloat) < errorTolerance)
+ return tmp;
+
+ closest++;
+ }
+
+ return src;
+}
+
+
+//
+// RLE the zig-zag of the AC components + copy over
+// into another tmp buffer
+//
+// Try to do a simple RLE scheme to reduce run's of 0's. This
+// differs from the jpeg EOB case, since EOB just indicates that
+// the rest of the block is zero. In our case, we have lots of
+// NaN symbols, which shouldn't be allowed to occur in DCT
+// coefficents - so we'll use them for encoding runs.
+//
+// If the high byte is 0xff, then we have a run of 0's, of length
+// given by the low byte. For example, 0xff03 would be a run
+// of 3 0's, starting at the current location.
+//
+// block is our block of 64 coefficients
+// acPtr a pointer to back the RLE'd values into.
+//
+// This will advance the counter, _numAcComp.
+//
+
+void
+DwaCompressor::LossyDctEncoderBase::rleAc
+ (half *block,
+ unsigned short *&acPtr)
+{
+ int dctComp = 1;
+ unsigned short rleSymbol = 0x0;
+
+ while (dctComp < 64)
+ {
+ int runLen = 1;
+
+ //
+ // If we don't have a 0, output verbatim
+ //
+
+ if (block[dctComp].bits() != rleSymbol)
+ {
+ *acPtr++ = block[dctComp].bits();
+ _numAcComp++;
+
+ dctComp += runLen;
+ continue;
+ }
+
+ //
+ // We're sitting on a 0, so see how big the run is.
+ //
+
+ while ((dctComp+runLen < 64) &&
+ (block[dctComp+runLen].bits() == rleSymbol))
+ {
+ runLen++;
+ }
+
+ //
+ // If the run len is too small, just output verbatim
+ // otherwise output our run token
+ //
+ // Originally, we wouldn't have a separate symbol for
+ // "end of block". But in some experimentation, it looks
+ // like using 0xff00 for "end of block" can save a bit
+ // of space.
+ //
+
+ if (runLen == 1)
+ {
+ runLen = 1;
+ *acPtr++ = block[dctComp].bits();
+ _numAcComp++;
+
+ //
+ // Using 0xff00 for "end of block"
+ //
+ }
+ else if (runLen + dctComp == 64)
+ {
+ //
+ // Signal EOB
+ //
+
+ *acPtr++ = 0xff00;
+ _numAcComp++;
+ }
+ else
+ {
+ //
+ // Signal normal run
+ //
+
+ *acPtr++ = 0xff00 | runLen;
+ _numAcComp++;
+ }
+
+ //
+ // Advance by runLen
+ //
+
+ dctComp += runLen;
+ }
+}
+
+
+// ==============================================================
+//
+// DwaCompressor
+//
+// --------------------------------------------------------------
+
+//
+// DwaCompressor()
+//
+
+DwaCompressor::DwaCompressor
+ (const Header &hdr,
+ int maxScanLineSize,
+ int numScanLines,
+ AcCompression acCompression)
+:
+ Compressor(hdr),
+ _acCompression(acCompression),
+ _maxScanLineSize(maxScanLineSize),
+ _numScanLines(numScanLines),
+ _channels(hdr.channels()),
+ _packedAcBuffer(0),
+ _packedAcBufferSize(0),
+ _packedDcBuffer(0),
+ _packedDcBufferSize(0),
+ _rleBuffer(0),
+ _rleBufferSize(0),
+ _outBuffer(0),
+ _outBufferSize(0),
+ _zip(0),
+ _dwaCompressionLevel(45.0)
+{
+ _min[0] = hdr.dataWindow().min.x;
+ _min[1] = hdr.dataWindow().min.y;
+ _max[0] = hdr.dataWindow().max.x;
+ _max[1] = hdr.dataWindow().max.y;
+
+ for (int i=0; i < NUM_COMPRESSOR_SCHEMES; ++i)
+ {
+ _planarUncBuffer[i] = 0;
+ _planarUncBufferSize[i] = 0;
+ }
+
+ //
+ // Check the header for a quality attribute
+ //
+
+ if (hasDwaCompressionLevel (hdr))
+ _dwaCompressionLevel = dwaCompressionLevel (hdr);
+}
+
+
+DwaCompressor::~DwaCompressor()
+{
+ delete[] _packedAcBuffer;
+ delete[] _packedDcBuffer;
+ delete[] _rleBuffer;
+ delete[] _outBuffer;
+ delete _zip;
+
+ for (int i=0; i<NUM_COMPRESSOR_SCHEMES; ++i)
+ delete[] _planarUncBuffer[i];
+}
+
+
+int
+DwaCompressor::numScanLines() const
+{
+ return _numScanLines;
+}
+
+
+OPENEXR_IMF_NAMESPACE::Compressor::Format
+DwaCompressor::format() const
+{
+ if (GLOBAL_SYSTEM_LITTLE_ENDIAN)
+ return NATIVE;
+ else
+ return XDR;
+}
+
+
+int
+DwaCompressor::compress
+ (const char *inPtr,
+ int inSize,
+ int minY,
+ const char *&outPtr)
+{
+ return compress
+ (inPtr,
+ inSize,
+ IMATH_NAMESPACE::Box2i (IMATH_NAMESPACE::V2i (_min[0], minY),
+ IMATH_NAMESPACE::V2i (_max[0], minY + numScanLines() - 1)),
+ outPtr);
+}
+
+
+int
+DwaCompressor::compressTile
+ (const char *inPtr,
+ int inSize,
+ IMATH_NAMESPACE::Box2i range,
+ const char *&outPtr)
+{
+ return compress (inPtr, inSize, range, outPtr);
+}
+
+
+int
+DwaCompressor::compress
+ (const char *inPtr,
+ int inSize,
+ IMATH_NAMESPACE::Box2i range,
+ const char *&outPtr)
+{
+ const char *inDataPtr = inPtr;
+ char *packedAcEnd = 0;
+ char *packedDcEnd = 0;
+ int fileVersion = 2; // Starting with 2, we write the channel
+ // classification rules into the file
+
+ if (fileVersion < 2)
+ initializeLegacyChannelRules();
+ else
+ initializeDefaultChannelRules();
+
+ size_t outBufferSize = 0;
+ initializeBuffers(outBufferSize);
+
+ unsigned short channelRuleSize = 0;
+ std::vector<Classifier> channelRules;
+ if (fileVersion >= 2)
+ {
+ relevantChannelRules(channelRules);
+
+ channelRuleSize = Xdr::size<unsigned short>();
+ for (size_t i = 0; i < channelRules.size(); ++i)
+ channelRuleSize += channelRules[i].size();
+ }
+
+ //
+ // Remember to allocate _outBuffer, if we haven't done so already.
+ //
+
+ outBufferSize += channelRuleSize;
+ if (outBufferSize > _outBufferSize)
+ {
+ _outBufferSize = outBufferSize;
+ if (_outBuffer != 0)
+ delete[] _outBuffer;
+ _outBuffer = new char[outBufferSize];
+ }
+
+ char *outDataPtr = &_outBuffer[NUM_SIZES_SINGLE * sizeof(OPENEXR_IMF_NAMESPACE::Int64) +
+ channelRuleSize];
+
+ //
+ // We might not be dealing with any color data, in which
+ // case the AC buffer size will be 0, and deferencing
+ // a vector will not be a good thing to do.
+ //
+
+ if (_packedAcBuffer)
+ packedAcEnd = _packedAcBuffer;
+
+ if (_packedDcBuffer)
+ packedDcEnd = _packedDcBuffer;
+
+ #define OBIDX(x) (Int64 *)&_outBuffer[x * sizeof (Int64)]
+
+ Int64 *version = OBIDX (VERSION);
+ Int64 *unknownUncompressedSize = OBIDX (UNKNOWN_UNCOMPRESSED_SIZE);
+ Int64 *unknownCompressedSize = OBIDX (UNKNOWN_COMPRESSED_SIZE);
+ Int64 *acCompressedSize = OBIDX (AC_COMPRESSED_SIZE);
+ Int64 *dcCompressedSize = OBIDX (DC_COMPRESSED_SIZE);
+ Int64 *rleCompressedSize = OBIDX (RLE_COMPRESSED_SIZE);
+ Int64 *rleUncompressedSize = OBIDX (RLE_UNCOMPRESSED_SIZE);
+ Int64 *rleRawSize = OBIDX (RLE_RAW_SIZE);
+
+ Int64 *totalAcUncompressedCount = OBIDX (AC_UNCOMPRESSED_COUNT);
+ Int64 *totalDcUncompressedCount = OBIDX (DC_UNCOMPRESSED_COUNT);
+
+ Int64 *acCompression = OBIDX (AC_COMPRESSION);
+
+ int minX = range.min.x;
+ int maxX = std::min(range.max.x, _max[0]);
+ int minY = range.min.y;
+ int maxY = std::min(range.max.y, _max[1]);
+
+ //
+ // Zero all the numbers in the chunk header
+ //
+
+ memset (_outBuffer, 0, NUM_SIZES_SINGLE * sizeof (Int64));
+
+ //
+ // Setup the AC compression strategy and the version in the data block,
+ // then write the relevant channel classification rules if needed
+ //
+ *version = fileVersion;
+ *acCompression = _acCompression;
+
+ setupChannelData (minX, minY, maxX, maxY);
+
+ if (fileVersion >= 2)
+ {
+ char *writePtr = &_outBuffer[NUM_SIZES_SINGLE * sizeof(OPENEXR_IMF_NAMESPACE::Int64)];
+ Xdr::write<CharPtrIO> (writePtr, channelRuleSize);
+
+ for (size_t i = 0; i < channelRules.size(); ++i)
+ channelRules[i].write(writePtr);
+ }
+
+ //
+ // Determine the start of each row in the input buffer
+ // Channels are interleaved by scanline
+ //
+
+ std::vector<bool> encodedChannels (_channelData.size());
+ std::vector< std::vector<const char *> > rowPtrs (_channelData.size());
+
+ for (unsigned int chan = 0; chan < _channelData.size(); ++chan)
+ encodedChannels[chan] = false;
+
+ inDataPtr = inPtr;
+
+ for (int y = minY; y <= maxY; ++y)
+ {
+ for (unsigned int chan = 0; chan < _channelData.size(); ++chan)
+ {
+
+ ChannelData *cd = &_channelData[chan];
+
+ if (IMATH_NAMESPACE::modp(y, cd->ySampling) != 0)
+ continue;
+
+ rowPtrs[chan].push_back(inDataPtr);
+ inDataPtr += cd->width * OPENEXR_IMF_NAMESPACE::pixelTypeSize(cd->type);
+ }
+ }
+
+ inDataPtr = inPtr;
+
+ //
+ // Make a pass over all our CSC sets and try to encode them first
+ //
+
+ for (unsigned int csc = 0; csc < _cscSets.size(); ++csc)
+ {
+
+ LossyDctEncoderCsc encoder
+ (_dwaCompressionLevel / 100000.f,
+ rowPtrs[_cscSets[csc].idx[0]],
+ rowPtrs[_cscSets[csc].idx[1]],
+ rowPtrs[_cscSets[csc].idx[2]],
+ packedAcEnd,
+ packedDcEnd,
+ get_dwaCompressorToNonlinear(),
+ _channelData[_cscSets[csc].idx[0]].width,
+ _channelData[_cscSets[csc].idx[0]].height,
+ _channelData[_cscSets[csc].idx[0]].type,
+ _channelData[_cscSets[csc].idx[1]].type,
+ _channelData[_cscSets[csc].idx[2]].type);
+
+ encoder.execute();
+
+ *totalAcUncompressedCount += encoder.numAcValuesEncoded();
+ *totalDcUncompressedCount += encoder.numDcValuesEncoded();
+
+ packedAcEnd += encoder.numAcValuesEncoded() * sizeof(unsigned short);
+ packedDcEnd += encoder.numDcValuesEncoded() * sizeof(unsigned short);
+
+ encodedChannels[_cscSets[csc].idx[0]] = true;
+ encodedChannels[_cscSets[csc].idx[1]] = true;
+ encodedChannels[_cscSets[csc].idx[2]] = true;
+ }
+
+ for (unsigned int chan = 0; chan < _channelData.size(); ++chan)
+ {
+ ChannelData *cd = &_channelData[chan];
+
+ if (encodedChannels[chan])
+ continue;
+
+ switch (cd->compression)
+ {
+ case LOSSY_DCT:
+
+ //
+ // For LOSSY_DCT, treat this just like the CSC'd case,
+ // but only operate on one channel
+ //
+
+ {
+ const unsigned short *nonlinearLut = 0;
+
+ if (!cd->pLinear)
+ nonlinearLut = get_dwaCompressorToNonlinear();
+
+ LossyDctEncoder encoder
+ (_dwaCompressionLevel / 100000.f,
+ rowPtrs[chan],
+ packedAcEnd,
+ packedDcEnd,
+ nonlinearLut,
+ cd->width,
+ cd->height,
+ cd->type);
+
+ encoder.execute();
+
+ *totalAcUncompressedCount += encoder.numAcValuesEncoded();
+ *totalDcUncompressedCount += encoder.numDcValuesEncoded();
+
+ packedAcEnd +=
+ encoder.numAcValuesEncoded() * sizeof (unsigned short);
+
+ packedDcEnd +=
+ encoder.numDcValuesEncoded() * sizeof (unsigned short);
+ }
+
+ break;
+
+ case RLE:
+
+ //
+ // For RLE, bash the bytes up so that the first bytes of each
+ // pixel are contingous, as are the second bytes, and so on.
+ //
+
+ for (unsigned int y = 0; y < rowPtrs[chan].size(); ++y)
+ {
+ const char *row = rowPtrs[chan][y];
+
+ for (int x = 0; x < cd->width; ++x)
+ {
+ for (int byte = 0;
+ byte < OPENEXR_IMF_NAMESPACE::pixelTypeSize (cd->type);
+ ++byte)
+ {
+
+ *cd->planarUncRleEnd[byte]++ = *row++;
+ }
+ }
+
+ *rleRawSize += cd->width * OPENEXR_IMF_NAMESPACE::pixelTypeSize(cd->type);
+ }
+
+ break;
+
+ case UNKNOWN:
+
+ //
+ // Otherwise, just copy data over verbatim
+ //
+
+ {
+ int scanlineSize = cd->width * OPENEXR_IMF_NAMESPACE::pixelTypeSize(cd->type);
+
+ for (unsigned int y = 0; y < rowPtrs[chan].size(); ++y)
+ {
+ memcpy (cd->planarUncBufferEnd,
+ rowPtrs[chan][y],
+ scanlineSize);
+
+ cd->planarUncBufferEnd += scanlineSize;
+ }
+
+ *unknownUncompressedSize += cd->planarUncSize;
+ }
+
+ break;
+
+ default:
+
+ assert (false);
+ }
+
+ encodedChannels[chan] = true;
+ }
+
+ //
+ // Pack the Unknown data into the output buffer first. Instead of
+ // just copying it uncompressed, try zlib compression at least.
+ //
+
+ if (*unknownUncompressedSize > 0)
+ {
+ uLongf inSize = (uLongf)(*unknownUncompressedSize);
+ uLongf outSize = compressBound (inSize);
+
+ if (Z_OK != ::compress2 ((Bytef *)outDataPtr,
+ &outSize,
+ (const Bytef *)_planarUncBuffer[UNKNOWN],
+ inSize,
+ 9))
+ {
+ throw IEX_NAMESPACE::BaseExc ("Data compression (zlib) failed.");
+ }
+
+ outDataPtr += outSize;
+ *unknownCompressedSize = outSize;
+ }
+
+ //
+ // Now, pack all the Lossy DCT coefficients into our output
+ // buffer, with Huffman encoding.
+ //
+ // Also, record the compressed size and the number of
+ // uncompressed componentns we have.
+ //
+
+ if (*totalAcUncompressedCount > 0)
+ {
+ switch (_acCompression)
+ {
+ case STATIC_HUFFMAN:
+
+ *acCompressedSize = (int)
+ hufCompress((unsigned short *)_packedAcBuffer,
+ (int)*totalAcUncompressedCount,
+ outDataPtr);
+ break;
+
+ case DEFLATE:
+
+ {
+ uLongf destLen = compressBound (
+ (*totalAcUncompressedCount) * sizeof (unsigned short));
+
+ if (Z_OK != ::compress2
+ ((Bytef *)outDataPtr,
+ &destLen,
+ (Bytef *)_packedAcBuffer,
+ (uLong)(*totalAcUncompressedCount
+ * sizeof (unsigned short)),
+ 9))
+ {
+ throw IEX_NAMESPACE::InputExc ("Data compression (zlib) failed.");
+ }
+
+ *acCompressedSize = destLen;
+ }
+
+ break;
+
+ default:
+
+ assert (false);
+ }
+
+ outDataPtr += *acCompressedSize;
+ }
+
+ //
+ // Handle the DC components separately
+ //
+
+ if (*totalDcUncompressedCount > 0)
+ {
+ *dcCompressedSize = _zip->compress
+ (_packedDcBuffer,
+ (int)(*totalDcUncompressedCount) * sizeof (unsigned short),
+ outDataPtr);
+
+ outDataPtr += *dcCompressedSize;
+ }
+
+ //
+ // If we have RLE data, first RLE encode it and set the uncompressed
+ // size. Then, deflate the results and set the compressed size.
+ //
+
+ if (*rleRawSize > 0)
+ {
+ *rleUncompressedSize = rleCompress
+ ((int)(*rleRawSize),
+ _planarUncBuffer[RLE],
+ (signed char *)_rleBuffer);
+
+ uLongf dstLen = compressBound ((uLongf)*rleUncompressedSize);
+
+ if (Z_OK != ::compress2
+ ((Bytef *)outDataPtr,
+ &dstLen,
+ (Bytef *)_rleBuffer,
+ (uLong)(*rleUncompressedSize),
+ 9))
+ {
+ throw IEX_NAMESPACE::BaseExc ("Error compressing RLE'd data.");
+ }
+
+ *rleCompressedSize = dstLen;
+ outDataPtr += *rleCompressedSize;
+ }
+
+ //
+ // Flip the counters to XDR format
+ //
+
+ for (int i = 0; i < NUM_SIZES_SINGLE; ++i)
+ {
+ Int64 src = *(((Int64 *)_outBuffer) + i);
+ char *dst = (char *)(((Int64 *)_outBuffer) + i);
+
+ Xdr::write<CharPtrIO> (dst, src);
+ }
+
+ //
+ // We're done - compute the number of bytes we packed
+ //
+
+ outPtr = _outBuffer;
+
+ return static_cast<int>(outDataPtr - _outBuffer + 1);
+}
+
+
+int
+DwaCompressor::uncompress
+ (const char *inPtr,
+ int inSize,
+ int minY,
+ const char *&outPtr)
+{
+ return uncompress (inPtr,
+ inSize,
+ IMATH_NAMESPACE::Box2i (IMATH_NAMESPACE::V2i (_min[0], minY),
+ IMATH_NAMESPACE::V2i (_max[0], minY + numScanLines() - 1)),
+ outPtr);
+}
+
+
+int
+DwaCompressor::uncompressTile
+ (const char *inPtr,
+ int inSize,
+ IMATH_NAMESPACE::Box2i range,
+ const char *&outPtr)
+{
+ return uncompress (inPtr, inSize, range, outPtr);
+}
+
+
+int
+DwaCompressor::uncompress
+ (const char *inPtr,
+ int inSize,
+ IMATH_NAMESPACE::Box2i range,
+ const char *&outPtr)
+{
+ int minX = range.min.x;
+ int maxX = std::min (range.max.x, _max[0]);
+ int minY = range.min.y;
+ int maxY = std::min (range.max.y, _max[1]);
+
+ int headerSize = NUM_SIZES_SINGLE*sizeof(Int64);
+ if (inSize < headerSize)
+ {
+ throw IEX_NAMESPACE::InputExc("Error uncompressing DWA data"
+ "(truncated header).");
+ }
+
+ //
+ // Flip the counters from XDR to NATIVE
+ //
+
+ for (int i = 0; i < NUM_SIZES_SINGLE; ++i)
+ {
+ Int64 *dst = (((Int64 *)inPtr) + i);
+ const char *src = (char *)(((Int64 *)inPtr) + i);
+
+ Xdr::read<CharPtrIO> (src, *dst);
+ }
+
+ //
+ // Unwind all the counter info
+ //
+
+ const Int64 *inPtr64 = (const Int64*) inPtr;
+
+ Int64 version = *(inPtr64 + VERSION);
+ Int64 unknownUncompressedSize = *(inPtr64 + UNKNOWN_UNCOMPRESSED_SIZE);
+ Int64 unknownCompressedSize = *(inPtr64 + UNKNOWN_COMPRESSED_SIZE);
+ Int64 acCompressedSize = *(inPtr64 + AC_COMPRESSED_SIZE);
+ Int64 dcCompressedSize = *(inPtr64 + DC_COMPRESSED_SIZE);
+ Int64 rleCompressedSize = *(inPtr64 + RLE_COMPRESSED_SIZE);
+ Int64 rleUncompressedSize = *(inPtr64 + RLE_UNCOMPRESSED_SIZE);
+ Int64 rleRawSize = *(inPtr64 + RLE_RAW_SIZE);
+
+ Int64 totalAcUncompressedCount = *(inPtr64 + AC_UNCOMPRESSED_COUNT);
+ Int64 totalDcUncompressedCount = *(inPtr64 + DC_UNCOMPRESSED_COUNT);
+
+ Int64 acCompression = *(inPtr64 + AC_COMPRESSION);
+
+ Int64 compressedSize = unknownCompressedSize +
+ acCompressedSize +
+ dcCompressedSize +
+ rleCompressedSize;
+
+ const char *dataPtr = inPtr + NUM_SIZES_SINGLE * sizeof(Int64);
+
+ /* Both the sum and individual sizes are checked in case of overflow. */
+ if (inSize < (headerSize + compressedSize) ||
+ inSize < unknownCompressedSize ||
+ inSize < acCompressedSize ||
+ inSize < dcCompressedSize ||
+ inSize < rleCompressedSize)
+ {
+ throw IEX_NAMESPACE::InputExc("Error uncompressing DWA data"
+ "(truncated file).");
+ }
+
+ if ((SInt64)unknownUncompressedSize < 0 ||
+ (SInt64)unknownCompressedSize < 0 ||
+ (SInt64)acCompressedSize < 0 ||
+ (SInt64)dcCompressedSize < 0 ||
+ (SInt64)rleCompressedSize < 0 ||
+ (SInt64)rleUncompressedSize < 0 ||
+ (SInt64)rleRawSize < 0 ||
+ (SInt64)totalAcUncompressedCount < 0 ||
+ (SInt64)totalDcUncompressedCount < 0)
+ {
+ throw IEX_NAMESPACE::InputExc("Error uncompressing DWA data"
+ " (corrupt header).");
+ }
+
+ if (version < 2)
+ initializeLegacyChannelRules();
+ else
+ {
+ unsigned short ruleSize = 0;
+ Xdr::read<CharPtrIO>(dataPtr, ruleSize);
+
+ if (ruleSize < 0)
+ throw IEX_NAMESPACE::InputExc("Error uncompressing DWA data"
+ " (corrupt header file).");
+
+ headerSize += ruleSize;
+ if (inSize < headerSize + compressedSize)
+ throw IEX_NAMESPACE::InputExc("Error uncompressing DWA data"
+ " (truncated file).");
+
+ _channelRules.clear();
+ ruleSize -= Xdr::size<unsigned short> ();
+ while (ruleSize > 0)
+ {
+ Classifier rule(dataPtr, ruleSize);
+
+ _channelRules.push_back(rule);
+ ruleSize -= rule.size();
+ }
+ }
+
+
+ size_t outBufferSize = 0;
+ initializeBuffers(outBufferSize);
+
+ //
+ // Allocate _outBuffer, if we haven't done so already
+ //
+
+ if (_maxScanLineSize * numScanLines() > _outBufferSize)
+ {
+ _outBufferSize = _maxScanLineSize * numScanLines();
+ if (_outBuffer != 0)
+ delete[] _outBuffer;
+ _outBuffer = new char[_maxScanLineSize * numScanLines()];
+ }
+
+
+ char *outBufferEnd = _outBuffer;
+
+
+ //
+ // Find the start of the RLE packed AC components and
+ // the DC components for each channel. This will be handy
+ // if you want to decode the channels in parallel later on.
+ //
+
+ char *packedAcBufferEnd = 0;
+
+ if (_packedAcBuffer)
+ packedAcBufferEnd = _packedAcBuffer;
+
+ char *packedDcBufferEnd = 0;
+
+ if (_packedDcBuffer)
+ packedDcBufferEnd = _packedDcBuffer;
+
+ //
+ // UNKNOWN data is packed first, followed by the
+ // Huffman-compressed AC, then the DC values,
+ // and then the zlib compressed RLE data.
+ //
+
+ const char *compressedUnknownBuf = dataPtr;
+
+ const char *compressedAcBuf = compressedUnknownBuf +
+ static_cast<ptrdiff_t>(unknownCompressedSize);
+ const char *compressedDcBuf = compressedAcBuf +
+ static_cast<ptrdiff_t>(acCompressedSize);
+ const char *compressedRleBuf = compressedDcBuf +
+ static_cast<ptrdiff_t>(dcCompressedSize);
+
+ //
+ // Sanity check that the version is something we expect. Right now,
+ // we can decode version 0, 1, and 2. v1 adds 'end of block' symbols
+ // to the AC RLE. v2 adds channel classification rules at the
+ // start of the data block.
+ //
+
+ if (version > 2)
+ throw IEX_NAMESPACE::InputExc ("Invalid version of compressed data block");
+
+ setupChannelData(minX, minY, maxX, maxY);
+
+ //
+ // Uncompress the UNKNOWN data into _planarUncBuffer[UNKNOWN]
+ //
+
+ if (unknownCompressedSize > 0)
+ {
+ if (unknownUncompressedSize > _planarUncBufferSize[UNKNOWN])
+ {
+ throw IEX_NAMESPACE::InputExc("Error uncompressing DWA data"
+ "(corrupt header).");
+ }
+
+ uLongf outSize = (uLongf)unknownUncompressedSize;
+
+ if (Z_OK != ::uncompress
+ ((Bytef *)_planarUncBuffer[UNKNOWN],
+ &outSize,
+ (Bytef *)compressedUnknownBuf,
+ (uLong)unknownCompressedSize))
+ {
+ throw IEX_NAMESPACE::BaseExc("Error uncompressing UNKNOWN data.");
+ }
+ }
+
+ //
+ // Uncompress the AC data into _packedAcBuffer
+ //
+
+ if (acCompressedSize > 0)
+ {
+ if (totalAcUncompressedCount*sizeof(unsigned short) > _packedAcBufferSize)
+ {
+ throw IEX_NAMESPACE::InputExc("Error uncompressing DWA data"
+ "(corrupt header).");
+ }
+
+ //
+ // Don't trust the user to get it right, look in the file.
+ //
+
+ switch (acCompression)
+ {
+ case STATIC_HUFFMAN:
+
+ hufUncompress
+ (compressedAcBuf,
+ (int)acCompressedSize,
+ (unsigned short *)_packedAcBuffer,
+ (int)totalAcUncompressedCount);
+
+ break;
+
+ case DEFLATE:
+ {
+ uLongf destLen =
+ (int)(totalAcUncompressedCount) * sizeof (unsigned short);
+
+ if (Z_OK != ::uncompress
+ ((Bytef *)_packedAcBuffer,
+ &destLen,
+ (Bytef *)compressedAcBuf,
+ (uLong)acCompressedSize))
+ {
+ throw IEX_NAMESPACE::InputExc ("Data decompression (zlib) failed.");
+ }
+
+ if (totalAcUncompressedCount * sizeof (unsigned short) !=
+ destLen)
+ {
+ throw IEX_NAMESPACE::InputExc ("AC data corrupt.");
+ }
+ }
+ break;
+
+ default:
+
+ throw IEX_NAMESPACE::NoImplExc ("Unknown AC Compression");
+ break;
+ }
+ }
+
+ //
+ // Uncompress the DC data into _packedDcBuffer
+ //
+
+ if (dcCompressedSize > 0)
+ {
+ if (totalDcUncompressedCount*sizeof(unsigned short) > _packedDcBufferSize)
+ {
+ throw IEX_NAMESPACE::InputExc("Error uncompressing DWA data"
+ "(corrupt header).");
+ }
+
+ if (_zip->uncompress
+ (compressedDcBuf, (int)dcCompressedSize, _packedDcBuffer)
+ != (int)totalDcUncompressedCount * sizeof (unsigned short))
+ {
+ throw IEX_NAMESPACE::BaseExc("DC data corrupt.");
+ }
+ }
+
+ //
+ // Uncompress the RLE data into _rleBuffer, then unRLE the results
+ // into _planarUncBuffer[RLE]
+ //
+
+ if (rleRawSize > 0)
+ {
+ if (rleUncompressedSize > _rleBufferSize ||
+ rleRawSize > _planarUncBufferSize[RLE])
+ {
+ throw IEX_NAMESPACE::InputExc("Error uncompressing DWA data"
+ "(corrupt header).");
+ }
+
+ uLongf dstLen = (uLongf)rleUncompressedSize;
+
+ if (Z_OK != ::uncompress
+ ((Bytef *)_rleBuffer,
+ &dstLen,
+ (Bytef *)compressedRleBuf,
+ (uLong)rleCompressedSize))
+ {
+ throw IEX_NAMESPACE::BaseExc("Error uncompressing RLE data.");
+ }
+
+ if (dstLen != rleUncompressedSize)
+ throw IEX_NAMESPACE::BaseExc("RLE data corrupted");
+
+ if (rleUncompress
+ ((int)rleUncompressedSize,
+ (int)rleRawSize,
+ (signed char *)_rleBuffer,
+ _planarUncBuffer[RLE]) != rleRawSize)
+ {
+ throw IEX_NAMESPACE::BaseExc("RLE data corrupted");
+ }
+ }
+
+ //
+ // Determine the start of each row in the output buffer
+ //
+
+ std::vector<bool> decodedChannels (_channelData.size());
+ std::vector< std::vector<char *> > rowPtrs (_channelData.size());
+
+ for (unsigned int chan = 0; chan < _channelData.size(); ++chan)
+ decodedChannels[chan] = false;
+
+ outBufferEnd = _outBuffer;
+
+ for (int y = minY; y <= maxY; ++y)
+ {
+ for (unsigned int chan = 0; chan < _channelData.size(); ++chan)
+ {
+ ChannelData *cd = &_channelData[chan];
+
+ if (IMATH_NAMESPACE::modp (y, cd->ySampling) != 0)
+ continue;
+
+ rowPtrs[chan].push_back (outBufferEnd);
+ outBufferEnd += cd->width * OPENEXR_IMF_NAMESPACE::pixelTypeSize (cd->type);
+ }
+ }
+
+ //
+ // Setup to decode each block of 3 channels that need to
+ // be handled together
+ //
+
+ for (unsigned int csc = 0; csc < _cscSets.size(); ++csc)
+ {
+ int rChan = _cscSets[csc].idx[0];
+ int gChan = _cscSets[csc].idx[1];
+ int bChan = _cscSets[csc].idx[2];
+
+
+ LossyDctDecoderCsc decoder
+ (rowPtrs[rChan],
+ rowPtrs[gChan],
+ rowPtrs[bChan],
+ packedAcBufferEnd,
+ packedDcBufferEnd,
+ get_dwaCompressorToLinear(),
+ _channelData[rChan].width,
+ _channelData[rChan].height,
+ _channelData[rChan].type,
+ _channelData[gChan].type,
+ _channelData[bChan].type);
+
+ decoder.execute();
+
+ packedAcBufferEnd +=
+ decoder.numAcValuesEncoded() * sizeof (unsigned short);
+
+ packedDcBufferEnd +=
+ decoder.numDcValuesEncoded() * sizeof (unsigned short);
+
+ decodedChannels[rChan] = true;
+ decodedChannels[gChan] = true;
+ decodedChannels[bChan] = true;
+ }
+
+ //
+ // Setup to handle the remaining channels by themselves
+ //
+
+ for (unsigned int chan = 0; chan < _channelData.size(); ++chan)
+ {
+ if (decodedChannels[chan])
+ continue;
+
+ ChannelData *cd = &_channelData[chan];
+ int pixelSize = OPENEXR_IMF_NAMESPACE::pixelTypeSize (cd->type);
+
+ switch (cd->compression)
+ {
+ case LOSSY_DCT:
+
+ //
+ // Setup a single-channel lossy DCT decoder pointing
+ // at the output buffer
+ //
+
+ {
+ const unsigned short *linearLut = 0;
+
+ if (!cd->pLinear)
+ linearLut = get_dwaCompressorToLinear();
+
+ LossyDctDecoder decoder
+ (rowPtrs[chan],
+ packedAcBufferEnd,
+ packedDcBufferEnd,
+ linearLut,
+ cd->width,
+ cd->height,
+ cd->type);
+
+ decoder.execute();
+
+ packedAcBufferEnd +=
+ decoder.numAcValuesEncoded() * sizeof (unsigned short);
+
+ packedDcBufferEnd +=
+ decoder.numDcValuesEncoded() * sizeof (unsigned short);
+ }
+
+ break;
+
+ case RLE:
+
+ //
+ // For the RLE case, the data has been un-RLE'd into
+ // planarUncRleEnd[], but is still split out by bytes.
+ // We need to rearrange the bytes back into the correct
+ // order in the output buffer;
+ //
+
+ {
+ int row = 0;
+
+ for (int y = minY; y <= maxY; ++y)
+ {
+ if (IMATH_NAMESPACE::modp (y, cd->ySampling) != 0)
+ continue;
+
+ char *dst = rowPtrs[chan][row];
+
+ if (pixelSize == 2)
+ {
+ interleaveByte2 (dst,
+ cd->planarUncRleEnd[0],
+ cd->planarUncRleEnd[1],
+ cd->width);
+
+ cd->planarUncRleEnd[0] += cd->width;
+ cd->planarUncRleEnd[1] += cd->width;
+ }
+ else
+ {
+ for (int x = 0; x < cd->width; ++x)
+ {
+ for (int byte = 0; byte < pixelSize; ++byte)
+ {
+ *dst++ = *cd->planarUncRleEnd[byte]++;
+ }
+ }
+ }
+
+ row++;
+ }
+ }
+
+ break;
+
+ case UNKNOWN:
+
+ //
+ // In the UNKNOWN case, data is already in planarUncBufferEnd
+ // and just needs to copied over to the output buffer
+ //
+
+ {
+ int row = 0;
+ int dstScanlineSize = cd->width * OPENEXR_IMF_NAMESPACE::pixelTypeSize (cd->type);
+
+ for (int y = minY; y <= maxY; ++y)
+ {
+ if (IMATH_NAMESPACE::modp (y, cd->ySampling) != 0)
+ continue;
+
+ memcpy (rowPtrs[chan][row],
+ cd->planarUncBufferEnd,
+ dstScanlineSize);
+
+ cd->planarUncBufferEnd += dstScanlineSize;
+ row++;
+ }
+ }
+
+ break;
+
+ default:
+
+ throw IEX_NAMESPACE::NoImplExc ("Unhandled compression scheme case");
+ break;
+ }
+
+ decodedChannels[chan] = true;
+ }
+
+ //
+ // Return a ptr to _outBuffer
+ //
+
+ outPtr = _outBuffer;
+ return (int)(outBufferEnd - _outBuffer);
+}
+
+
+// static
+void
+DwaCompressor::initializeFuncs()
+{
+ convertFloatToHalf64 = convertFloatToHalf64_scalar;
+ fromHalfZigZag = fromHalfZigZag_scalar;
+
+ CpuId cpuId;
+
+ //
+ // Setup HALF <-> FLOAT conversion implementations
+ //
+
+ if (cpuId.avx && cpuId.f16c)
+ {
+ convertFloatToHalf64 = convertFloatToHalf64_f16c;
+ fromHalfZigZag = fromHalfZigZag_f16c;
+ }
+
+ //
+ // Setup inverse DCT implementations
+ //
+
+ dctInverse8x8_0 = dctInverse8x8_scalar<0>;
+ dctInverse8x8_1 = dctInverse8x8_scalar<1>;
+ dctInverse8x8_2 = dctInverse8x8_scalar<2>;
+ dctInverse8x8_3 = dctInverse8x8_scalar<3>;
+ dctInverse8x8_4 = dctInverse8x8_scalar<4>;
+ dctInverse8x8_5 = dctInverse8x8_scalar<5>;
+ dctInverse8x8_6 = dctInverse8x8_scalar<6>;
+ dctInverse8x8_7 = dctInverse8x8_scalar<7>;
+
+ if (cpuId.avx)
+ {
+ dctInverse8x8_0 = dctInverse8x8_avx<0>;
+ dctInverse8x8_1 = dctInverse8x8_avx<1>;
+ dctInverse8x8_2 = dctInverse8x8_avx<2>;
+ dctInverse8x8_3 = dctInverse8x8_avx<3>;
+ dctInverse8x8_4 = dctInverse8x8_avx<4>;
+ dctInverse8x8_5 = dctInverse8x8_avx<5>;
+ dctInverse8x8_6 = dctInverse8x8_avx<6>;
+ dctInverse8x8_7 = dctInverse8x8_avx<7>;
+ }
+ else if (cpuId.sse2)
+ {
+ dctInverse8x8_0 = dctInverse8x8_sse2<0>;
+ dctInverse8x8_1 = dctInverse8x8_sse2<1>;
+ dctInverse8x8_2 = dctInverse8x8_sse2<2>;
+ dctInverse8x8_3 = dctInverse8x8_sse2<3>;
+ dctInverse8x8_4 = dctInverse8x8_sse2<4>;
+ dctInverse8x8_5 = dctInverse8x8_sse2<5>;
+ dctInverse8x8_6 = dctInverse8x8_sse2<6>;
+ dctInverse8x8_7 = dctInverse8x8_sse2<7>;
+ }
+}
+
+
+//
+// Handle channel classification and buffer allocation once we know
+// how to classify channels
+//
+
+void
+DwaCompressor::initializeBuffers (size_t &outBufferSize)
+{
+ classifyChannels (_channels, _channelData, _cscSets);
+
+ //
+ // _outBuffer needs to be big enough to hold all our
+ // compressed data - which could vary depending on what sort
+ // of channels we have.
+ //
+
+ int maxOutBufferSize = 0;
+ int numLossyDctChans = 0;
+ int unknownBufferSize = 0;
+ int rleBufferSize = 0;
+
+ int maxLossyDctAcSize = (int)ceil ((float)numScanLines() / 8.0f) *
+ (int)ceil ((float)(_max[0] - _min[0] + 1) / 8.0f) *
+ 63 * sizeof (unsigned short);
+
+ int maxLossyDctDcSize = (int)ceil ((float)numScanLines() / 8.0f) *
+ (int)ceil ((float)(_max[0] - _min[0] + 1) / 8.0f) *
+ sizeof (unsigned short);
+
+ for (unsigned int chan = 0; chan < _channelData.size(); ++chan)
+ {
+ switch (_channelData[chan].compression)
+ {
+ case LOSSY_DCT:
+
+ //
+ // This is the size of the number of packed
+ // components, plus the requirements for
+ // maximum Huffman encoding size (for STATIC_HUFFMAN)
+ // or for zlib compression (for DEFLATE)
+ //
+
+ maxOutBufferSize += std::max(
+ (int)(2 * maxLossyDctAcSize + 65536),
+ (int)compressBound (maxLossyDctAcSize) );
+ numLossyDctChans++;
+ break;
+
+ case RLE:
+ {
+ //
+ // RLE, if gone horribly wrong, could double the size
+ // of the source data.
+ //
+
+ int rleAmount = 2 * numScanLines() * (_max[0] - _min[0] + 1) *
+ OPENEXR_IMF_NAMESPACE::pixelTypeSize (_channelData[chan].type);
+
+ rleBufferSize += rleAmount;
+ }
+ break;
+
+
+ case UNKNOWN:
+
+ unknownBufferSize += numScanLines() * (_max[0] - _min[0] + 1) *
+ OPENEXR_IMF_NAMESPACE::pixelTypeSize (_channelData[chan].type);
+ break;
+
+ default:
+
+ throw IEX_NAMESPACE::NoImplExc ("Unhandled compression scheme case");
+ break;
+ }
+ }
+
+ //
+ // Also, since the results of the RLE are packed into
+ // the output buffer, we need the extra room there. But
+ // we're going to zlib compress() the data we pack,
+ // which could take slightly more space
+ //
+
+ maxOutBufferSize += (int)compressBound ((uLongf)rleBufferSize);
+
+ //
+ // And the same goes for the UNKNOWN data
+ //
+
+ maxOutBufferSize += (int)compressBound ((uLongf)unknownBufferSize);
+
+ //
+ // Allocate a zip/deflate compressor big enought to hold the DC data
+ // and include it's compressed results in the size requirements
+ // for our output buffer
+ //
+
+ if (_zip == 0)
+ _zip = new Zip (maxLossyDctDcSize * numLossyDctChans);
+ else if (_zip->maxRawSize() < maxLossyDctDcSize * numLossyDctChans)
+ {
+ delete _zip;
+ _zip = new Zip (maxLossyDctDcSize * numLossyDctChans);
+ }
+
+
+ maxOutBufferSize += _zip->maxCompressedSize();
+
+ //
+ // We also need to reserve space at the head of the buffer to
+ // write out the size of our various packed and compressed data.
+ //
+
+ maxOutBufferSize += NUM_SIZES_SINGLE * sizeof (Int64);
+
+
+ //
+ // Later, we're going to hijack outBuffer for the result of
+ // both encoding and decoding. So it needs to be big enough
+ // to hold either a buffers' worth of uncompressed or
+ // compressed data
+ //
+ // For encoding, we'll need _outBuffer to hold maxOutBufferSize bytes,
+ // but for decoding, we only need it to be maxScanLineSize*numScanLines.
+ // Cache the max size for now, and alloc the buffer when we either
+ // encode or decode.
+ //
+
+ outBufferSize = maxOutBufferSize;
+
+
+ //
+ // _packedAcBuffer holds the quantized DCT coefficients prior
+ // to Huffman encoding
+ //
+
+ if (maxLossyDctAcSize * numLossyDctChans > _packedAcBufferSize)
+ {
+ _packedAcBufferSize = maxLossyDctAcSize * numLossyDctChans;
+ if (_packedAcBuffer != 0)
+ delete[] _packedAcBuffer;
+ _packedAcBuffer = new char[_packedAcBufferSize];
+ }
+
+ //
+ // _packedDcBuffer holds one quantized DCT coef per 8x8 block
+ //
+
+ if (maxLossyDctDcSize * numLossyDctChans > _packedDcBufferSize)
+ {
+ _packedDcBufferSize = maxLossyDctDcSize * numLossyDctChans;
+ if (_packedDcBuffer != 0)
+ delete[] _packedDcBuffer;
+ _packedDcBuffer = new char[_packedDcBufferSize];
+ }
+
+ if (rleBufferSize > _rleBufferSize)
+ {
+ _rleBufferSize = rleBufferSize;
+ if (_rleBuffer != 0)
+ delete[] _rleBuffer;
+ _rleBuffer = new char[rleBufferSize];
+ }
+
+ //
+ // The planar uncompressed buffer will hold float data for LOSSY_DCT
+ // compressed values, and whatever the native type is for other
+ // channels. We're going to use this to hold data in a planar
+ // format, as opposed to the native interleaved format we take
+ // into compress() and give back from uncompress().
+ //
+ // This also makes it easier to compress the UNKNOWN and RLE data
+ // all in one swoop (for each compression scheme).
+ //
+
+ int planarUncBufferSize[NUM_COMPRESSOR_SCHEMES];
+ for (int i=0; i<NUM_COMPRESSOR_SCHEMES; ++i)
+ planarUncBufferSize[i] = 0;
+
+ for (unsigned int chan = 0; chan < _channelData.size(); ++chan)
+ {
+ switch (_channelData[chan].compression)
+ {
+ case LOSSY_DCT:
+ break;
+
+ case RLE:
+ planarUncBufferSize[RLE] +=
+ numScanLines() * (_max[0] - _min[0] + 1) *
+ OPENEXR_IMF_NAMESPACE::pixelTypeSize (_channelData[chan].type);
+ break;
+
+ case UNKNOWN:
+ planarUncBufferSize[UNKNOWN] +=
+ numScanLines() * (_max[0] - _min[0] + 1) *
+ OPENEXR_IMF_NAMESPACE::pixelTypeSize (_channelData[chan].type);
+ break;
+
+ default:
+ throw IEX_NAMESPACE::NoImplExc ("Unhandled compression scheme case");
+ break;
+ }
+ }
+
+ //
+ // UNKNOWN data is going to be zlib compressed, which needs
+ // a little extra headroom
+ //
+
+ if (planarUncBufferSize[UNKNOWN] > 0)
+ {
+ planarUncBufferSize[UNKNOWN] =
+ compressBound ((uLongf)planarUncBufferSize[UNKNOWN]);
+ }
+
+ for (int i = 0; i < NUM_COMPRESSOR_SCHEMES; ++i)
+ {
+ if (planarUncBufferSize[i] > _planarUncBufferSize[i])
+ {
+ _planarUncBufferSize[i] = planarUncBufferSize[i];
+ if (_planarUncBuffer[i] != 0)
+ delete[] _planarUncBuffer[i];
+ _planarUncBuffer[i] = new char[planarUncBufferSize[i]];
+ }
+ }
+}
+
+
+//
+// Setup channel classification rules to use when writing files
+//
+
+void
+DwaCompressor::initializeDefaultChannelRules ()
+{
+ _channelRules.clear();
+
+ _channelRules.push_back (Classifier ("R", LOSSY_DCT, HALF, 0, false));
+ _channelRules.push_back (Classifier ("R", LOSSY_DCT, FLOAT, 0, false));
+ _channelRules.push_back (Classifier ("G", LOSSY_DCT, HALF, 1, false));
+ _channelRules.push_back (Classifier ("G", LOSSY_DCT, FLOAT, 1, false));
+ _channelRules.push_back (Classifier ("B", LOSSY_DCT, HALF, 2, false));
+ _channelRules.push_back (Classifier ("B", LOSSY_DCT, FLOAT, 2, false));
+
+ _channelRules.push_back (Classifier ("Y", LOSSY_DCT, HALF, -1, false));
+ _channelRules.push_back (Classifier ("Y", LOSSY_DCT, FLOAT, -1, false));
+ _channelRules.push_back (Classifier ("BY", LOSSY_DCT, HALF, -1, false));
+ _channelRules.push_back (Classifier ("BY", LOSSY_DCT, FLOAT, -1, false));
+ _channelRules.push_back (Classifier ("RY", LOSSY_DCT, HALF, -1, false));
+ _channelRules.push_back (Classifier ("RY", LOSSY_DCT, FLOAT, -1, false));
+
+ _channelRules.push_back (Classifier ("A", RLE, UINT, -1, false));
+ _channelRules.push_back (Classifier ("A", RLE, HALF, -1, false));
+ _channelRules.push_back (Classifier ("A", RLE, FLOAT, -1, false));
+}
+
+
+//
+// Setup channel classification rules when reading files with VERSION < 2
+//
+
+void
+DwaCompressor::initializeLegacyChannelRules ()
+{
+ _channelRules.clear();
+
+ _channelRules.push_back (Classifier ("r", LOSSY_DCT, HALF, 0, true));
+ _channelRules.push_back (Classifier ("r", LOSSY_DCT, FLOAT, 0, true));
+ _channelRules.push_back (Classifier ("red", LOSSY_DCT, HALF, 0, true));
+ _channelRules.push_back (Classifier ("red", LOSSY_DCT, FLOAT, 0, true));
+ _channelRules.push_back (Classifier ("g", LOSSY_DCT, HALF, 1, true));
+ _channelRules.push_back (Classifier ("g", LOSSY_DCT, FLOAT, 1, true));
+ _channelRules.push_back (Classifier ("grn", LOSSY_DCT, HALF, 1, true));
+ _channelRules.push_back (Classifier ("grn", LOSSY_DCT, FLOAT, 1, true));
+ _channelRules.push_back (Classifier ("green", LOSSY_DCT, HALF, 1, true));
+ _channelRules.push_back (Classifier ("green", LOSSY_DCT, FLOAT, 1, true));
+ _channelRules.push_back (Classifier ("b", LOSSY_DCT, HALF, 2, true));
+ _channelRules.push_back (Classifier ("b", LOSSY_DCT, FLOAT, 2, true));
+ _channelRules.push_back (Classifier ("blu", LOSSY_DCT, HALF, 2, true));
+ _channelRules.push_back (Classifier ("blu", LOSSY_DCT, FLOAT, 2, true));
+ _channelRules.push_back (Classifier ("blue", LOSSY_DCT, HALF, 2, true));
+ _channelRules.push_back (Classifier ("blue", LOSSY_DCT, FLOAT, 2, true));
+
+ _channelRules.push_back (Classifier ("y", LOSSY_DCT, HALF, -1, true));
+ _channelRules.push_back (Classifier ("y", LOSSY_DCT, FLOAT, -1, true));
+ _channelRules.push_back (Classifier ("by", LOSSY_DCT, HALF, -1, true));
+ _channelRules.push_back (Classifier ("by", LOSSY_DCT, FLOAT, -1, true));
+ _channelRules.push_back (Classifier ("ry", LOSSY_DCT, HALF, -1, true));
+ _channelRules.push_back (Classifier ("ry", LOSSY_DCT, FLOAT, -1, true));
+ _channelRules.push_back (Classifier ("a", RLE, UINT, -1, true));
+ _channelRules.push_back (Classifier ("a", RLE, HALF, -1, true));
+ _channelRules.push_back (Classifier ("a", RLE, FLOAT, -1, true));
+}
+
+
+//
+// Given a set of rules and ChannelData, figure out which rules apply
+//
+
+void
+DwaCompressor::relevantChannelRules (std::vector<Classifier> &rules) const
+{
+ rules.clear();
+
+ std::vector<std::string> suffixes;
+
+ for (size_t cd = 0; cd < _channelData.size(); ++cd)
+ {
+ std::string suffix = _channelData[cd].name;
+ size_t lastDot = suffix.find_last_of ('.');
+
+ if (lastDot != std::string::npos)
+ suffix = suffix.substr (lastDot+1, std::string::npos);
+
+ suffixes.push_back(suffix);
+ }
+
+
+ for (size_t i = 0; i < _channelRules.size(); ++i)
+ {
+ for (size_t cd = 0; cd < _channelData.size(); ++cd)
+ {
+ if (_channelRules[i].match (suffixes[cd], _channelData[cd].type ))
+ {
+ rules.push_back (_channelRules[i]);
+ break;
+ }
+ }
+ }
+}
+
+
+//
+// Take our initial list of channels, and cache the contents.
+//
+// Determine approprate compression schemes for each channel,
+// and figure out which sets should potentially be CSC'ed
+// prior to lossy compression.
+//
+
+void
+DwaCompressor::classifyChannels
+ (ChannelList channels,
+ std::vector<ChannelData> &chanData,
+ std::vector<CscChannelSet> &cscData)
+{
+ //
+ // prefixMap used to map channel name prefixes to
+ // potential CSC-able sets of channels.
+ //
+
+ std::map<std::string, DwaCompressor::CscChannelSet> prefixMap;
+ std::vector<DwaCompressor::CscChannelSet> tmpCscSet;
+
+ unsigned int numChan = 0;
+
+ for (ChannelList::Iterator c = channels.begin(); c != channels.end(); ++c)
+ numChan++;
+
+ if (numChan)
+ chanData.resize (numChan);
+
+ //
+ // Cache the relevant data from the channel structs.
+ //
+
+ unsigned int offset = 0;
+
+ for (ChannelList::Iterator c = channels.begin(); c != channels.end(); ++c)
+ {
+ chanData[offset].name = std::string (c.name());
+ chanData[offset].compression = UNKNOWN;
+ chanData[offset].xSampling = c.channel().xSampling;
+ chanData[offset].ySampling = c.channel().ySampling;
+ chanData[offset].type = c.channel().type;
+ chanData[offset].pLinear = c.channel().pLinear;
+
+ offset++;
+ }
+
+ //
+ // Try and figure out which channels should be
+ // compressed by which means.
+ //
+
+ for (offset = 0; offset<numChan; ++offset)
+ {
+ std::string prefix = "";
+ std::string suffix = chanData[offset].name;
+ size_t lastDot = suffix.find_last_of ('.');
+
+ if (lastDot != std::string::npos)
+ {
+ prefix = suffix.substr (0, lastDot);
+ suffix = suffix.substr (lastDot+1, std::string::npos);
+ }
+
+ //
+ // Make sure we have an entry in our CSC set map
+ //
+
+ std::map<std::string, DwaCompressor::CscChannelSet>::iterator
+ theSet = prefixMap.find (prefix);
+
+ if (theSet == prefixMap.end())
+ {
+ DwaCompressor::CscChannelSet tmpSet;
+
+ tmpSet.idx[0] =
+ tmpSet.idx[1] =
+ tmpSet.idx[2] = -1;
+
+ prefixMap[prefix] = tmpSet;
+ }
+
+ //
+ // Check the suffix against the list of classifications
+ // we defined previously. If the _cscIdx is not negative,
+ // it indicates that we should be part of a CSC group.
+ //
+
+ for (std::vector<Classifier>::iterator i = _channelRules.begin();
+ i != _channelRules.end();
+ ++i)
+ {
+ if ( i->match(suffix, chanData[offset].type) )
+ {
+ chanData[offset].compression = i->_scheme;
+
+ if ( i->_cscIdx >= 0)
+ prefixMap[prefix].idx[i->_cscIdx] = offset;
+ }
+ }
+ }
+
+ //
+ // Finally, try and find RGB sets of channels which
+ // can be CSC'ed to a Y'CbCr space prior to loss, for
+ // better compression.
+ //
+ // Walk over our set of candidates, and see who has
+ // all three channels defined (and has common sampling
+ // patterns, etc).
+ //
+
+ for (std::map<std::string, DwaCompressor::CscChannelSet>::iterator
+ theItem = prefixMap.begin(); theItem != prefixMap.end();
+ ++theItem)
+ {
+ int red = (*theItem).second.idx[0];
+ int grn = (*theItem).second.idx[1];
+ int blu = (*theItem).second.idx[2];
+
+ if ((red < 0) || (grn < 0) || (blu < 0))
+ continue;
+
+ if ((chanData[red].xSampling != chanData[grn].xSampling) ||
+ (chanData[red].xSampling != chanData[blu].xSampling) ||
+ (chanData[grn].xSampling != chanData[blu].xSampling) ||
+ (chanData[red].ySampling != chanData[grn].ySampling) ||
+ (chanData[red].ySampling != chanData[blu].ySampling) ||
+ (chanData[grn].ySampling != chanData[blu].ySampling))
+ {
+ continue;
+ }
+
+ tmpCscSet.push_back ((*theItem).second);
+ }
+
+ size_t numCsc = tmpCscSet.size();
+
+ if (numCsc)
+ cscData.resize(numCsc);
+
+ for (offset = 0; offset < numCsc; ++offset)
+ cscData[offset] = tmpCscSet[offset];
+}
+
+
+
+//
+// Setup some buffer pointers, determine channel sizes, things
+// like that.
+//
+
+void
+DwaCompressor::setupChannelData (int minX, int minY, int maxX, int maxY)
+{
+ char *planarUncBuffer[NUM_COMPRESSOR_SCHEMES];
+
+ for (int i=0; i<NUM_COMPRESSOR_SCHEMES; ++i)
+ {
+ planarUncBuffer[i] = 0;
+
+ if (_planarUncBuffer[i])
+ planarUncBuffer[i] = _planarUncBuffer[i];
+ }
+
+ for (unsigned int chan = 0; chan < _channelData.size(); ++chan)
+ {
+ ChannelData *cd = &_channelData[chan];
+
+ cd->width = OPENEXR_IMF_NAMESPACE::numSamples (cd->xSampling, minX, maxX);
+ cd->height = OPENEXR_IMF_NAMESPACE::numSamples (cd->ySampling, minY, maxY);
+
+ cd->planarUncSize =
+ cd->width * cd->height * OPENEXR_IMF_NAMESPACE::pixelTypeSize (cd->type);
+
+ cd->planarUncBuffer = planarUncBuffer[cd->compression];
+ cd->planarUncBufferEnd = cd->planarUncBuffer;
+
+ cd->planarUncRle[0] = cd->planarUncBuffer;
+ cd->planarUncRleEnd[0] = cd->planarUncRle[0];
+
+ for (int byte = 1; byte < OPENEXR_IMF_NAMESPACE::pixelTypeSize(cd->type); ++byte)
+ {
+ cd->planarUncRle[byte] =
+ cd->planarUncRle[byte-1] + cd->width * cd->height;
+
+ cd->planarUncRleEnd[byte] =
+ cd->planarUncRle[byte];
+ }
+
+ cd->planarUncType = cd->type;
+
+ if (cd->compression == LOSSY_DCT)
+ {
+ cd->planarUncType = FLOAT;
+ }
+ else
+ {
+ planarUncBuffer[cd->compression] +=
+ cd->width * cd->height * OPENEXR_IMF_NAMESPACE::pixelTypeSize (cd->planarUncType);
+ }
+ }
+}
+
+OPENEXR_IMF_INTERNAL_NAMESPACE_SOURCE_EXIT
--- /dev/null
+///////////////////////////////////////////////////////////////////////////
+//
+// Copyright (c) 2009-2014 DreamWorks Animation LLC.
+//
+// All rights reserved.
+//
+// Redistribution and use in source and binary forms, with or without
+// modification, are permitted provided that the following conditions are
+// met:
+// * Redistributions of source code must retain the above copyright
+// notice, this list of conditions and the following disclaimer.
+// * Redistributions in binary form must reproduce the above
+// copyright notice, this list of conditions and the following disclaimer
+// in the documentation and/or other materials provided with the
+// distribution.
+// * Neither the name of DreamWorks Animation nor the names of
+// its contributors may be used to endorse or promote products derived
+// from this software without specific prior written permission.
+//
+// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+//
+///////////////////////////////////////////////////////////////////////////
+
+#ifndef INCLUDED_IMF_DWA_COMRESSOR_H
+#define INCLUDED_IMF_DWA_COMRESSOR_H
+
+//------------------------------------------------------------------------------
+//
+// class DwaCompressor -- Store lossy RGB data by quantizing DCT components.
+//
+//------------------------------------------------------------------------------
+
+#include <vector>
+#include <half.h>
+
+#include "ImfInt64.h"
+#include "ImfZip.h"
+#include "ImfChannelList.h"
+#include "ImfCompressor.h"
+#include "ImfNamespace.h"
+
+OPENEXR_IMF_INTERNAL_NAMESPACE_HEADER_ENTER
+
+class DwaCompressor: public Compressor
+{
+ public:
+
+ enum AcCompression
+ {
+ STATIC_HUFFMAN,
+ DEFLATE,
+ };
+
+
+ IMF_EXPORT
+ DwaCompressor (const Header &hdr,
+ int maxScanLineSize,
+ int numScanLines, // ideally is a multiple of 8
+ AcCompression acCompression);
+
+ IMF_EXPORT
+ virtual ~DwaCompressor ();
+
+ IMF_EXPORT
+ virtual int numScanLines () const;
+
+ IMF_EXPORT
+ virtual OPENEXR_IMF_NAMESPACE::Compressor::Format format () const;
+
+ IMF_EXPORT
+ virtual int compress (const char *inPtr,
+ int inSize,
+ int minY,
+ const char *&outPtr);
+
+ IMF_EXPORT
+ virtual int compressTile (const char *inPtr,
+ int inSize,
+ IMATH_NAMESPACE::Box2i range,
+ const char *&outPtr);
+
+ IMF_EXPORT
+ virtual int uncompress (const char *inPtr,
+ int inSize,
+ int minY,
+ const char *&outPtr);
+
+ IMF_EXPORT
+ virtual int uncompressTile (const char *inPtr,
+ int inSize,
+ IMATH_NAMESPACE::Box2i range,
+ const char *&outPtr);
+
+ IMF_EXPORT
+ static void initializeFuncs ();
+
+ private:
+
+ struct ChannelData;
+ struct CscChannelSet;
+ struct Classifier;
+
+ class LossyDctDecoderBase;
+ class LossyDctDecoder;
+ class LossyDctDecoderCsc;
+
+ class LossyDctEncoderBase;
+ class LossyDctEncoder;
+ class LossyDctEncoderCsc;
+
+ enum CompressorScheme
+ {
+ UNKNOWN = 0,
+ LOSSY_DCT,
+ RLE,
+
+ NUM_COMPRESSOR_SCHEMES
+ };
+
+ //
+ // Per-chunk compressed data sizes, one value per chunk
+ //
+
+ enum DataSizesSingle
+ {
+ VERSION = 0, // Version number:
+ // 0: classic
+ // 1: adds "end of block" to the AC RLE
+
+ UNKNOWN_UNCOMPRESSED_SIZE, // Size of leftover data, uncompressed.
+ UNKNOWN_COMPRESSED_SIZE, // Size of leftover data, zlib compressed.
+
+ AC_COMPRESSED_SIZE, // AC RLE + Huffman size
+ DC_COMPRESSED_SIZE, // DC + Deflate size
+ RLE_COMPRESSED_SIZE, // RLE + Deflate data size
+ RLE_UNCOMPRESSED_SIZE, // RLE'd data size
+ RLE_RAW_SIZE, // Un-RLE'd data size
+
+ AC_UNCOMPRESSED_COUNT, // AC RLE number of elements
+ DC_UNCOMPRESSED_COUNT, // DC number of elements
+
+ AC_COMPRESSION, // AC compression strategy
+ NUM_SIZES_SINGLE
+ };
+
+ AcCompression _acCompression;
+
+ int _maxScanLineSize;
+ int _numScanLines;
+ int _min[2], _max[2];
+
+ ChannelList _channels;
+ std::vector<ChannelData> _channelData;
+ std::vector<CscChannelSet> _cscSets;
+ std::vector<Classifier> _channelRules;
+
+ char *_packedAcBuffer;
+ size_t _packedAcBufferSize;
+ char *_packedDcBuffer;
+ size_t _packedDcBufferSize;
+ char *_rleBuffer;
+ size_t _rleBufferSize;
+ char *_outBuffer;
+ size_t _outBufferSize;
+ char *_planarUncBuffer[NUM_COMPRESSOR_SCHEMES];
+ size_t _planarUncBufferSize[NUM_COMPRESSOR_SCHEMES];
+
+ Zip *_zip;
+ float _dwaCompressionLevel;
+
+ int compress (const char *inPtr,
+ int inSize,
+ IMATH_NAMESPACE::Box2i range,
+ const char *&outPtr);
+
+ int uncompress (const char *inPtr,
+ int inSize,
+ IMATH_NAMESPACE::Box2i range,
+ const char *&outPtr);
+
+ void initializeBuffers (size_t&);
+ void initializeDefaultChannelRules ();
+ void initializeLegacyChannelRules ();
+
+ void relevantChannelRules( std::vector<Classifier> &) const;
+
+ //
+ // Populate our cached version of the channel data with
+ // data from the real channel list. We want to
+ // copy over attributes, determine compression schemes
+ // releveant for the channel type, and find sets of
+ // channels to be compressed from Y'CbCr data instead
+ // of R'G'B'.
+ //
+
+ void classifyChannels (ChannelList channels,
+ std::vector<ChannelData> &chanData,
+ std::vector<CscChannelSet> &cscData);
+
+ //
+ // Compute various buffer pointers for each channel
+ //
+
+ void setupChannelData (int minX, int minY, int maxX, int maxY);
+};
+
+OPENEXR_IMF_INTERNAL_NAMESPACE_HEADER_EXIT
+
+#endif
--- /dev/null
+///////////////////////////////////////////////////////////////////////////
+//
+// Copyright (c) 2009-2014 DreamWorks Animation LLC.
+//
+// All rights reserved.
+//
+// Redistribution and use in source and binary forms, with or without
+// modification, are permitted provided that the following conditions are
+// met:
+// * Redistributions of source code must retain the above copyright
+// notice, this list of conditions and the following disclaimer.
+// * Redistributions in binary form must reproduce the above
+// copyright notice, this list of conditions and the following disclaimer
+// in the documentation and/or other materials provided with the
+// distribution.
+// * Neither the name of DreamWorks Animation nor the names of
+// its contributors may be used to endorse or promote products derived
+// from this software without specific prior written permission.
+//
+// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+//
+///////////////////////////////////////////////////////////////////////////
+
+#ifndef IMF_DWACOMPRESSORSIMD_H_HAS_BEEN_INCLUDED
+#define IMF_DWACOMPRESSORSIMD_H_HAS_BEEN_INCLUDED
+
+//
+// Various SSE accelerated functions, used by Imf::DwaCompressor.
+// These have been separated into a separate .h file, as the fast
+// paths are done with template specialization.
+//
+// Unless otherwise noted, all pointers are assumed to be 32-byte
+// aligned. Unaligned pointers may risk seg-faulting.
+//
+
+#include "ImfNamespace.h"
+#include "ImfSimd.h"
+#include "ImfSystemSpecific.h"
+#include "OpenEXRConfig.h"
+
+#include <half.h>
+#include <assert.h>
+
+#include <algorithm>
+
+OPENEXR_IMF_INTERNAL_NAMESPACE_HEADER_ENTER
+
+#define _SSE_ALIGNMENT 32
+#define _SSE_ALIGNMENT_MASK 0x0F
+#define _AVX_ALIGNMENT_MASK 0x1F
+
+//
+// Test if we should enable GCC inline asm paths for AVX
+//
+
+#ifdef OPENEXR_IMF_HAVE_GCC_INLINE_ASM_AVX
+
+ #define IMF_HAVE_GCC_INLINEASM
+
+ #ifdef __LP64__
+ #define IMF_HAVE_GCC_INLINEASM_64
+ #endif /* __LP64__ */
+
+#endif /* OPENEXR_IMF_HAVE_GCC_INLINE_ASM_AVX */
+
+//
+// A simple 64-element array, aligned properly for SIMD access.
+//
+
+template <class T>
+class SimdAlignedBuffer64
+{
+ public:
+
+ SimdAlignedBuffer64(): _buffer (0), _handle (0)
+ {
+ alloc();
+ }
+
+ SimdAlignedBuffer64(const SimdAlignedBuffer64 &rhs): _handle(0)
+ {
+ alloc();
+ memcpy (_buffer, rhs._buffer, 64 * sizeof (T));
+ }
+
+ SimdAlignedBuffer64 &operator=(const SimdAlignedBuffer64 &rhs)
+ {
+ memcpy (_buffer, rhs._buffer, 64 * sizeof (T));
+ return *this;
+ }
+
+#if __cplusplus >= 201103L
+ SimdAlignedBuffer64(SimdAlignedBuffer64 &&rhs) noexcept
+ : _handle(rhs._handle), _buffer(rhs._buffer)
+ {
+ rhs._handle = nullptr;
+ rhs._buffer = nullptr;
+ }
+
+ SimdAlignedBuffer64 &operator=(SimdAlignedBuffer64 &&rhs) noexcept
+ {
+ std::swap(_handle, rhs._handle);
+ std::swap(_buffer, rhs._buffer);
+ return *this;
+ }
+#endif
+ ~SimdAlignedBuffer64 ()
+ {
+ if (_handle)
+ EXRFreeAligned (_handle);
+ _handle = 0;
+ _buffer = 0;
+ }
+
+ void alloc()
+ {
+ //
+ // Try EXRAllocAligned first - but it might fallback to
+ // unaligned allocs. If so, overalloc.
+ //
+
+ _handle = (char *) EXRAllocAligned
+ (64 * sizeof(T), _SSE_ALIGNMENT);
+
+ if (((size_t)_handle & (_SSE_ALIGNMENT - 1)) == 0)
+ {
+ _buffer = (T *)_handle;
+ return;
+ }
+
+ EXRFreeAligned(_handle);
+ _handle = (char *) EXRAllocAligned
+ (64 * sizeof(T) + _SSE_ALIGNMENT, _SSE_ALIGNMENT);
+
+ char *aligned = _handle;
+
+ while ((size_t)aligned & (_SSE_ALIGNMENT - 1))
+ aligned++;
+
+ _buffer = (T *)aligned;
+ }
+
+ T *_buffer;
+
+ private:
+
+ char *_handle;
+};
+
+typedef SimdAlignedBuffer64<float> SimdAlignedBuffer64f;
+typedef SimdAlignedBuffer64<unsigned short> SimdAlignedBuffer64us;
+
+namespace {
+
+//
+// Color space conversion, Inverse 709 CSC, Y'CbCr -> R'G'B'
+//
+
+void
+csc709Inverse (float &comp0, float &comp1, float &comp2)
+{
+ float src[3];
+
+ src[0] = comp0;
+ src[1] = comp1;
+ src[2] = comp2;
+
+ comp0 = src[0] + 1.5747f * src[2];
+ comp1 = src[0] - 0.1873f * src[1] - 0.4682f * src[2];
+ comp2 = src[0] + 1.8556f * src[1];
+}
+
+#ifndef IMF_HAVE_SSE2
+
+
+//
+// Scalar color space conversion, based on 709 primiary chromaticies.
+// No scaling or offsets, just the matrix
+//
+
+void
+csc709Inverse64 (float *comp0, float *comp1, float *comp2)
+{
+ for (int i = 0; i < 64; ++i)
+ csc709Inverse (comp0[i], comp1[i], comp2[i]);
+}
+
+#else /* IMF_HAVE_SSE2 */
+
+//
+// SSE2 color space conversion
+//
+
+void
+csc709Inverse64 (float *comp0, float *comp1, float *comp2)
+{
+ __m128 c0 = { 1.5747f, 1.5747f, 1.5747f, 1.5747f};
+ __m128 c1 = { 1.8556f, 1.8556f, 1.8556f, 1.8556f};
+ __m128 c2 = {-0.1873f, -0.1873f, -0.1873f, -0.1873f};
+ __m128 c3 = {-0.4682f, -0.4682f, -0.4682f, -0.4682f};
+
+ __m128 *r = (__m128 *)comp0;
+ __m128 *g = (__m128 *)comp1;
+ __m128 *b = (__m128 *)comp2;
+ __m128 src[3];
+
+ #define CSC_INVERSE_709_SSE2_LOOP(i) \
+ src[0] = r[i]; \
+ src[1] = g[i]; \
+ src[2] = b[i]; \
+ \
+ r[i] = _mm_add_ps (r[i], _mm_mul_ps (src[2], c0)); \
+ \
+ g[i] = _mm_mul_ps (g[i], c2); \
+ src[2] = _mm_mul_ps (src[2], c3); \
+ g[i] = _mm_add_ps (g[i], src[0]); \
+ g[i] = _mm_add_ps (g[i], src[2]); \
+ \
+ b[i] = _mm_mul_ps (c1, src[1]); \
+ b[i] = _mm_add_ps (b[i], src[0]);
+
+ CSC_INVERSE_709_SSE2_LOOP (0)
+ CSC_INVERSE_709_SSE2_LOOP (1)
+ CSC_INVERSE_709_SSE2_LOOP (2)
+ CSC_INVERSE_709_SSE2_LOOP (3)
+
+ CSC_INVERSE_709_SSE2_LOOP (4)
+ CSC_INVERSE_709_SSE2_LOOP (5)
+ CSC_INVERSE_709_SSE2_LOOP (6)
+ CSC_INVERSE_709_SSE2_LOOP (7)
+
+ CSC_INVERSE_709_SSE2_LOOP (8)
+ CSC_INVERSE_709_SSE2_LOOP (9)
+ CSC_INVERSE_709_SSE2_LOOP (10)
+ CSC_INVERSE_709_SSE2_LOOP (11)
+
+ CSC_INVERSE_709_SSE2_LOOP (12)
+ CSC_INVERSE_709_SSE2_LOOP (13)
+ CSC_INVERSE_709_SSE2_LOOP (14)
+ CSC_INVERSE_709_SSE2_LOOP (15)
+}
+
+#endif /* IMF_HAVE_SSE2 */
+
+
+//
+// Color space conversion, Forward 709 CSC, R'G'B' -> Y'CbCr
+//
+// Simple FPU color space conversion. Based on the 709
+// primary chromaticies, with no scaling or offsets.
+//
+
+void
+csc709Forward64 (float *comp0, float *comp1, float *comp2)
+{
+ float src[3];
+
+ for (int i = 0; i<64; ++i)
+ {
+ src[0] = comp0[i];
+ src[1] = comp1[i];
+ src[2] = comp2[i];
+
+ comp0[i] = 0.2126f * src[0] + 0.7152f * src[1] + 0.0722f * src[2];
+ comp1[i] = -0.1146f * src[0] - 0.3854f * src[1] + 0.5000f * src[2];
+ comp2[i] = 0.5000f * src[0] - 0.4542f * src[1] - 0.0458f * src[2];
+ }
+}
+
+
+//
+// Byte interleaving of 2 byte arrays:
+// src0 = AAAA
+// src1 = BBBB
+// dst = ABABABAB
+//
+// numBytes is the size of each of the source buffers
+//
+
+#ifndef IMF_HAVE_SSE2
+
+//
+// Scalar default implementation
+//
+
+void
+interleaveByte2 (char *dst, char *src0, char *src1, int numBytes)
+{
+ for (int x = 0; x < numBytes; ++x)
+ {
+ dst[2 * x] = src0[x];
+ dst[2 * x + 1] = src1[x];
+ }
+}
+
+#else /* IMF_HAVE_SSE2 */
+
+//
+// SSE2 byte interleaving
+//
+
+void
+interleaveByte2 (char *dst, char *src0, char *src1, int numBytes)
+{
+ int dstAlignment = (size_t)dst % 16;
+ int src0Alignment = (size_t)src0 % 16;
+ int src1Alignment = (size_t)src1 % 16;
+
+ __m128i *dst_epi8 = (__m128i*)dst;
+ __m128i *src0_epi8 = (__m128i*)src0;
+ __m128i *src1_epi8 = (__m128i*)src1;
+ int sseWidth = numBytes / 16;
+
+ if ((!dstAlignment) && (!src0Alignment) && (!src1Alignment))
+ {
+ __m128i tmp0, tmp1;
+
+ //
+ // Aligned loads and stores
+ //
+
+ for (int x = 0; x < sseWidth; ++x)
+ {
+ tmp0 = src0_epi8[x];
+ tmp1 = src1_epi8[x];
+
+ _mm_stream_si128 (&dst_epi8[2 * x],
+ _mm_unpacklo_epi8 (tmp0, tmp1));
+
+ _mm_stream_si128 (&dst_epi8[2 * x + 1],
+ _mm_unpackhi_epi8 (tmp0, tmp1));
+ }
+
+ //
+ // Then do run the leftovers one at a time
+ //
+
+ for (int x = 16 * sseWidth; x < numBytes; ++x)
+ {
+ dst[2 * x] = src0[x];
+ dst[2 * x + 1] = src1[x];
+ }
+ }
+ else if ((!dstAlignment) && (src0Alignment == 8) && (src1Alignment == 8))
+ {
+ //
+ // Aligned stores, but catch up a few values so we can
+ // use aligned loads
+ //
+
+ for (int x = 0; x < std::min (numBytes, 8); ++x)
+ {
+ dst[2 * x] = src0[x];
+ dst[2 * x + 1] = src1[x];
+ }
+
+ if (numBytes > 8)
+ {
+ dst_epi8 = (__m128i*)&dst[16];
+ src0_epi8 = (__m128i*)&src0[8];
+ src1_epi8 = (__m128i*)&src1[8];
+ sseWidth = (numBytes - 8) / 16;
+
+ for (int x=0; x<sseWidth; ++x)
+ {
+ _mm_stream_si128 (&dst_epi8[2 * x],
+ _mm_unpacklo_epi8 (src0_epi8[x], src1_epi8[x]));
+
+ _mm_stream_si128 (&dst_epi8[2 * x + 1],
+ _mm_unpackhi_epi8 (src0_epi8[x], src1_epi8[x]));
+ }
+
+ //
+ // Then do run the leftovers one at a time
+ //
+
+ for (int x = 16 * sseWidth + 8; x < numBytes; ++x)
+ {
+ dst[2 * x] = src0[x];
+ dst[2 * x + 1] = src1[x];
+ }
+ }
+ }
+ else
+ {
+ //
+ // Unaligned everything
+ //
+
+ for (int x = 0; x < sseWidth; ++x)
+ {
+ __m128i tmpSrc0_epi8 = _mm_loadu_si128 (&src0_epi8[x]);
+ __m128i tmpSrc1_epi8 = _mm_loadu_si128 (&src1_epi8[x]);
+
+ _mm_storeu_si128 (&dst_epi8[2 * x],
+ _mm_unpacklo_epi8 (tmpSrc0_epi8, tmpSrc1_epi8));
+
+ _mm_storeu_si128 (&dst_epi8[2 * x + 1],
+ _mm_unpackhi_epi8 (tmpSrc0_epi8, tmpSrc1_epi8));
+ }
+
+ //
+ // Then do run the leftovers one at a time
+ //
+
+ for (int x = 16 * sseWidth; x < numBytes; ++x)
+ {
+ dst[2 * x] = src0[x];
+ dst[2 * x + 1] = src1[x];
+ }
+ }
+}
+
+#endif /* IMF_HAVE_SSE2 */
+
+
+//
+// Float -> half float conversion
+//
+// To enable F16C based conversion, we can't rely on compile-time
+// detection, hence the multiple defined versions. Pick one based
+// on runtime cpuid detection.
+//
+
+//
+// Default boring conversion
+//
+
+void
+convertFloatToHalf64_scalar (unsigned short *dst, float *src)
+{
+ for (int i=0; i<64; ++i)
+ dst[i] = ((half)src[i]).bits();
+}
+
+
+//
+// F16C conversion - Assumes aligned src and dst
+//
+
+void
+convertFloatToHalf64_f16c (unsigned short *dst, float *src)
+{
+ //
+ // Ordinarly, I'd avoid using inline asm and prefer intrinsics.
+ // However, in order to get the intrinsics, we need to tell
+ // the compiler to generate VEX instructions.
+ //
+ // (On the GCC side, -mf16c goes ahead and activates -mavc,
+ // resulting in VEX code. Without -mf16c, no intrinsics..)
+ //
+ // Now, it's quite likely that we'll find ourselves in situations
+ // where we want to build *without* VEX, in order to maintain
+ // maximum compatability. But to get there with intrinsics,
+ // we'd need to break out code into a separate file. Bleh.
+ // I'll take the asm.
+ //
+
+ #if defined IMF_HAVE_GCC_INLINEASM
+ __asm__
+ ("vmovaps (%0), %%ymm0 \n"
+ "vmovaps 0x20(%0), %%ymm1 \n"
+ "vmovaps 0x40(%0), %%ymm2 \n"
+ "vmovaps 0x60(%0), %%ymm3 \n"
+ "vcvtps2ph $0, %%ymm0, %%xmm0 \n"
+ "vcvtps2ph $0, %%ymm1, %%xmm1 \n"
+ "vcvtps2ph $0, %%ymm2, %%xmm2 \n"
+ "vcvtps2ph $0, %%ymm3, %%xmm3 \n"
+ "vmovdqa %%xmm0, 0x00(%1) \n"
+ "vmovdqa %%xmm1, 0x10(%1) \n"
+ "vmovdqa %%xmm2, 0x20(%1) \n"
+ "vmovdqa %%xmm3, 0x30(%1) \n"
+ "vmovaps 0x80(%0), %%ymm0 \n"
+ "vmovaps 0xa0(%0), %%ymm1 \n"
+ "vmovaps 0xc0(%0), %%ymm2 \n"
+ "vmovaps 0xe0(%0), %%ymm3 \n"
+ "vcvtps2ph $0, %%ymm0, %%xmm0 \n"
+ "vcvtps2ph $0, %%ymm1, %%xmm1 \n"
+ "vcvtps2ph $0, %%ymm2, %%xmm2 \n"
+ "vcvtps2ph $0, %%ymm3, %%xmm3 \n"
+ "vmovdqa %%xmm0, 0x40(%1) \n"
+ "vmovdqa %%xmm1, 0x50(%1) \n"
+ "vmovdqa %%xmm2, 0x60(%1) \n"
+ "vmovdqa %%xmm3, 0x70(%1) \n"
+ #ifndef __AVX__
+ "vzeroupper \n"
+ #endif /* __AVX__ */
+ : /* Output */
+ : /* Input */ "r"(src), "r"(dst)
+ #ifndef __AVX__
+ : /* Clobber */ "%xmm0", "%xmm1", "%xmm2", "%xmm3", "memory"
+ #else
+ : /* Clobber */ "%ymm0", "%ymm1", "%ymm2", "%ymm3", "memory"
+ #endif /* __AVX__ */
+ );
+ #else
+ convertFloatToHalf64_scalar (dst, src);
+ #endif /* IMF_HAVE_GCC_INLINEASM */
+}
+
+
+//
+// Convert an 8x8 block of HALF from zig-zag order to
+// FLOAT in normal order. The order we want is:
+//
+// src dst
+// 0 1 2 3 4 5 6 7 0 1 5 6 14 15 27 28
+// 8 9 10 11 12 13 14 15 2 4 7 13 16 26 29 42
+// 16 17 18 19 20 21 22 23 3 8 12 17 25 30 41 43
+// 24 25 26 27 28 29 30 31 9 11 18 24 31 40 44 53
+// 32 33 34 35 36 37 38 39 10 19 23 32 39 45 52 54
+// 40 41 42 43 44 45 46 47 20 22 33 38 46 51 55 60
+// 48 49 50 51 52 53 54 55 21 34 37 47 50 56 59 61
+// 56 57 58 59 60 61 62 63 35 36 48 49 57 58 62 63
+//
+
+void
+fromHalfZigZag_scalar (unsigned short *src, float *dst)
+{
+ half *srcHalf = (half *)src;
+
+ dst[0] = (float)srcHalf[0];
+ dst[1] = (float)srcHalf[1];
+ dst[2] = (float)srcHalf[5];
+ dst[3] = (float)srcHalf[6];
+ dst[4] = (float)srcHalf[14];
+ dst[5] = (float)srcHalf[15];
+ dst[6] = (float)srcHalf[27];
+ dst[7] = (float)srcHalf[28];
+ dst[8] = (float)srcHalf[2];
+ dst[9] = (float)srcHalf[4];
+
+ dst[10] = (float)srcHalf[7];
+ dst[11] = (float)srcHalf[13];
+ dst[12] = (float)srcHalf[16];
+ dst[13] = (float)srcHalf[26];
+ dst[14] = (float)srcHalf[29];
+ dst[15] = (float)srcHalf[42];
+ dst[16] = (float)srcHalf[3];
+ dst[17] = (float)srcHalf[8];
+ dst[18] = (float)srcHalf[12];
+ dst[19] = (float)srcHalf[17];
+
+ dst[20] = (float)srcHalf[25];
+ dst[21] = (float)srcHalf[30];
+ dst[22] = (float)srcHalf[41];
+ dst[23] = (float)srcHalf[43];
+ dst[24] = (float)srcHalf[9];
+ dst[25] = (float)srcHalf[11];
+ dst[26] = (float)srcHalf[18];
+ dst[27] = (float)srcHalf[24];
+ dst[28] = (float)srcHalf[31];
+ dst[29] = (float)srcHalf[40];
+
+ dst[30] = (float)srcHalf[44];
+ dst[31] = (float)srcHalf[53];
+ dst[32] = (float)srcHalf[10];
+ dst[33] = (float)srcHalf[19];
+ dst[34] = (float)srcHalf[23];
+ dst[35] = (float)srcHalf[32];
+ dst[36] = (float)srcHalf[39];
+ dst[37] = (float)srcHalf[45];
+ dst[38] = (float)srcHalf[52];
+ dst[39] = (float)srcHalf[54];
+
+ dst[40] = (float)srcHalf[20];
+ dst[41] = (float)srcHalf[22];
+ dst[42] = (float)srcHalf[33];
+ dst[43] = (float)srcHalf[38];
+ dst[44] = (float)srcHalf[46];
+ dst[45] = (float)srcHalf[51];
+ dst[46] = (float)srcHalf[55];
+ dst[47] = (float)srcHalf[60];
+ dst[48] = (float)srcHalf[21];
+ dst[49] = (float)srcHalf[34];
+
+ dst[50] = (float)srcHalf[37];
+ dst[51] = (float)srcHalf[47];
+ dst[52] = (float)srcHalf[50];
+ dst[53] = (float)srcHalf[56];
+ dst[54] = (float)srcHalf[59];
+ dst[55] = (float)srcHalf[61];
+ dst[56] = (float)srcHalf[35];
+ dst[57] = (float)srcHalf[36];
+ dst[58] = (float)srcHalf[48];
+ dst[59] = (float)srcHalf[49];
+
+ dst[60] = (float)srcHalf[57];
+ dst[61] = (float)srcHalf[58];
+ dst[62] = (float)srcHalf[62];
+ dst[63] = (float)srcHalf[63];
+}
+
+
+//
+// If we can form the correct ordering in xmm registers,
+// we can use F16C to convert from HALF -> FLOAT. However,
+// making the correct order isn't trivial.
+//
+// We want to re-order a source 8x8 matrix from:
+//
+// 0 1 2 3 4 5 6 7 0 1 5 6 14 15 27 28
+// 8 9 10 11 12 13 14 15 2 4 7 13 16 26 29 42
+// 16 17 18 19 20 21 22 23 3 8 12 17 25 30 41 43
+// 24 25 26 27 28 29 30 31 9 11 18 24 31 40 44 53 (A)
+// 32 33 34 35 36 37 38 39 --> 10 19 23 32 39 45 52 54
+// 40 41 42 43 44 45 46 47 20 22 33 38 46 51 55 60
+// 48 49 50 51 52 53 54 55 21 34 37 47 50 56 59 61
+// 56 57 58 59 60 61 62 63 35 36 48 49 57 58 62 63
+//
+// Which looks like a mess, right?
+//
+// Now, check out the NE/SW diagonals of (A). Along those lines,
+// we have runs of contiguous values! If we rewrite (A) a bit, we get:
+//
+// 0
+// 1 2
+// 5 4 3
+// 6 7 8 9
+// 14 13 12 11 10
+// 15 16 17 18 19 20
+// 27 26 25 24 23 22 21 (B)
+// 28 29 30 31 32 33 34 35
+// 42 41 40 39 38 37 36
+// 43 44 45 46 47 48
+// 53 52 51 50 49
+// 54 55 56 57
+// 60 59 58
+// 61 62
+// 63
+//
+// In this ordering, the columns are the rows (A). If we can 'transpose'
+// (B), we'll achieve our goal. But we want this to fit nicely into
+// xmm registers and still be able to load large runs efficiently.
+// Also, notice that the odd rows are in ascending order, while
+// the even rows are in descending order.
+//
+// If we 'fold' the bottom half up into the top, we can preserve ordered
+// runs accross rows, and still keep all the correct values in columns.
+// After transposing, we'll need to rotate things back into place.
+// This gives us:
+//
+// 0 | 42 41 40 39 38 37 36
+// 1 2 | 43 44 45 46 47 48
+// 5 4 3 | 53 52 51 50 49
+// 6 7 8 9 | 54 55 56 57 (C)
+// 14 13 12 11 10 | 60 59 58
+// 15 16 17 18 19 20 | 61 62
+// 27 26 25 24 23 22 21 | 61
+// 28 29 30 31 32 33 34 35
+//
+// But hang on. We still have the backwards descending rows to deal with.
+// Lets reverse the even rows so that all values are in ascending order
+//
+// 36 37 38 39 40 41 42 | 0
+// 1 2 | 43 44 45 46 47 48
+// 49 50 51 52 53 | 3 4 5
+// 6 7 8 9 | 54 55 56 57 (D)
+// 58 59 60 | 10 11 12 13 14
+// 15 16 17 18 19 20 | 61 62
+// 61 | 21 22 23 24 25 26 27
+// 28 29 30 31 32 33 34 35
+//
+// If we can form (D), we will then:
+// 1) Reverse the even rows
+// 2) Transpose
+// 3) Rotate the rows
+//
+// and we'll have (A).
+//
+
+void
+fromHalfZigZag_f16c (unsigned short *src, float *dst)
+{
+ #if defined IMF_HAVE_GCC_INLINEASM_64
+ __asm__
+
+ /* x3 <- 0
+ * x8 <- [ 0- 7]
+ * x6 <- [56-63]
+ * x9 <- [21-28]
+ * x7 <- [28-35]
+ * x3 <- [ 6- 9] (lower half) */
+
+ ("vpxor %%xmm3, %%xmm3, %%xmm3 \n"
+ "vmovdqa (%0), %%xmm8 \n"
+ "vmovdqa 112(%0), %%xmm6 \n"
+ "vmovdqu 42(%0), %%xmm9 \n"
+ "vmovdqu 56(%0), %%xmm7 \n"
+ "vmovq 12(%0), %%xmm3 \n"
+
+ /* Setup rows 0-2 of A in xmm0-xmm2
+ * x1 <- x8 >> 16 (1 value)
+ * x2 <- x8 << 32 (2 values)
+ * x0 <- alignr([35-42], x8, 2)
+ * x1 <- blend(x1, [41-48])
+ * x2 <- blend(x2, [49-56]) */
+
+ "vpsrldq $2, %%xmm8, %%xmm1 \n"
+ "vpslldq $4, %%xmm8, %%xmm2 \n"
+ "vpalignr $2, 70(%0), %%xmm8, %%xmm0 \n"
+ "vpblendw $0xfc, 82(%0), %%xmm1, %%xmm1 \n"
+ "vpblendw $0x1f, 98(%0), %%xmm2, %%xmm2 \n"
+
+ /* Setup rows 4-6 of A in xmm4-xmm6
+ * x4 <- x6 >> 32 (2 values)
+ * x5 <- x6 << 16 (1 value)
+ * x6 <- alignr(x6,x9,14)
+ * x4 <- blend(x4, [ 7-14])
+ * x5 <- blend(x5, [15-22]) */
+
+ "vpsrldq $4, %%xmm6, %%xmm4 \n"
+ "vpslldq $2, %%xmm6, %%xmm5 \n"
+ "vpalignr $14, %%xmm6, %%xmm9, %%xmm6 \n"
+ "vpblendw $0xf8, 14(%0), %%xmm4, %%xmm4 \n"
+ "vpblendw $0x3f, 30(%0), %%xmm5, %%xmm5 \n"
+
+ /* Load the upper half of row 3 into xmm3
+ * x3 <- [54-57] (upper half) */
+
+ "vpinsrq $1, 108(%0), %%xmm3, %%xmm3\n"
+
+ /* Reverse the even rows. We're not using PSHUFB as
+ * that requires loading an extra constant all the time,
+ * and we're alreadly pretty memory bound.
+ */
+
+ "vpshuflw $0x1b, %%xmm0, %%xmm0 \n"
+ "vpshuflw $0x1b, %%xmm2, %%xmm2 \n"
+ "vpshuflw $0x1b, %%xmm4, %%xmm4 \n"
+ "vpshuflw $0x1b, %%xmm6, %%xmm6 \n"
+
+ "vpshufhw $0x1b, %%xmm0, %%xmm0 \n"
+ "vpshufhw $0x1b, %%xmm2, %%xmm2 \n"
+ "vpshufhw $0x1b, %%xmm4, %%xmm4 \n"
+ "vpshufhw $0x1b, %%xmm6, %%xmm6 \n"
+
+ "vpshufd $0x4e, %%xmm0, %%xmm0 \n"
+ "vpshufd $0x4e, %%xmm2, %%xmm2 \n"
+ "vpshufd $0x4e, %%xmm4, %%xmm4 \n"
+ "vpshufd $0x4e, %%xmm6, %%xmm6 \n"
+
+ /* Transpose xmm0-xmm7 into xmm8-xmm15 */
+
+ "vpunpcklwd %%xmm1, %%xmm0, %%xmm8 \n"
+ "vpunpcklwd %%xmm3, %%xmm2, %%xmm9 \n"
+ "vpunpcklwd %%xmm5, %%xmm4, %%xmm10 \n"
+ "vpunpcklwd %%xmm7, %%xmm6, %%xmm11 \n"
+ "vpunpckhwd %%xmm1, %%xmm0, %%xmm12 \n"
+ "vpunpckhwd %%xmm3, %%xmm2, %%xmm13 \n"
+ "vpunpckhwd %%xmm5, %%xmm4, %%xmm14 \n"
+ "vpunpckhwd %%xmm7, %%xmm6, %%xmm15 \n"
+
+ "vpunpckldq %%xmm9, %%xmm8, %%xmm0 \n"
+ "vpunpckldq %%xmm11, %%xmm10, %%xmm1 \n"
+ "vpunpckhdq %%xmm9, %%xmm8, %%xmm2 \n"
+ "vpunpckhdq %%xmm11, %%xmm10, %%xmm3 \n"
+ "vpunpckldq %%xmm13, %%xmm12, %%xmm4 \n"
+ "vpunpckldq %%xmm15, %%xmm14, %%xmm5 \n"
+ "vpunpckhdq %%xmm13, %%xmm12, %%xmm6 \n"
+ "vpunpckhdq %%xmm15, %%xmm14, %%xmm7 \n"
+
+ "vpunpcklqdq %%xmm1, %%xmm0, %%xmm8 \n"
+ "vpunpckhqdq %%xmm1, %%xmm0, %%xmm9 \n"
+ "vpunpcklqdq %%xmm3, %%xmm2, %%xmm10 \n"
+ "vpunpckhqdq %%xmm3, %%xmm2, %%xmm11 \n"
+ "vpunpcklqdq %%xmm4, %%xmm5, %%xmm12 \n"
+ "vpunpckhqdq %%xmm5, %%xmm4, %%xmm13 \n"
+ "vpunpcklqdq %%xmm7, %%xmm6, %%xmm14 \n"
+ "vpunpckhqdq %%xmm7, %%xmm6, %%xmm15 \n"
+
+ /* Rotate the rows to get the correct final order.
+ * Rotating xmm12 isn't needed, as we can handle
+ * the rotation in the PUNPCKLQDQ above. Rotating
+ * xmm8 isn't needed as it's already in the right order
+ */
+
+ "vpalignr $2, %%xmm9, %%xmm9, %%xmm9 \n"
+ "vpalignr $4, %%xmm10, %%xmm10, %%xmm10 \n"
+ "vpalignr $6, %%xmm11, %%xmm11, %%xmm11 \n"
+ "vpalignr $10, %%xmm13, %%xmm13, %%xmm13 \n"
+ "vpalignr $12, %%xmm14, %%xmm14, %%xmm14 \n"
+ "vpalignr $14, %%xmm15, %%xmm15, %%xmm15 \n"
+
+ /* Convert from half -> float */
+
+ "vcvtph2ps %%xmm8, %%ymm8 \n"
+ "vcvtph2ps %%xmm9, %%ymm9 \n"
+ "vcvtph2ps %%xmm10, %%ymm10 \n"
+ "vcvtph2ps %%xmm11, %%ymm11 \n"
+ "vcvtph2ps %%xmm12, %%ymm12 \n"
+ "vcvtph2ps %%xmm13, %%ymm13 \n"
+ "vcvtph2ps %%xmm14, %%ymm14 \n"
+ "vcvtph2ps %%xmm15, %%ymm15 \n"
+
+ /* Move float values to dst */
+
+ "vmovaps %%ymm8, (%1) \n"
+ "vmovaps %%ymm9, 32(%1) \n"
+ "vmovaps %%ymm10, 64(%1) \n"
+ "vmovaps %%ymm11, 96(%1) \n"
+ "vmovaps %%ymm12, 128(%1) \n"
+ "vmovaps %%ymm13, 160(%1) \n"
+ "vmovaps %%ymm14, 192(%1) \n"
+ "vmovaps %%ymm15, 224(%1) \n"
+ #ifndef __AVX__
+ "vzeroupper \n"
+ #endif /* __AVX__ */
+ : /* Output */
+ : /* Input */ "r"(src), "r"(dst)
+ : /* Clobber */ "memory",
+ #ifndef __AVX__
+ "%xmm0", "%xmm1", "%xmm2", "%xmm3",
+ "%xmm4", "%xmm5", "%xmm6", "%xmm7",
+ "%xmm8", "%xmm9", "%xmm10", "%xmm11",
+ "%xmm12", "%xmm13", "%xmm14", "%xmm15"
+ #else
+ "%ymm0", "%ymm1", "%ymm2", "%ymm3",
+ "%ymm4", "%ymm5", "%ymm6", "%ymm7",
+ "%ymm8", "%ymm9", "%ymm10", "%ymm11",
+ "%ymm12", "%ymm13", "%ymm14", "%ymm15"
+ #endif /* __AVX__ */
+ );
+
+ #else
+ fromHalfZigZag_scalar(src, dst);
+ #endif /* defined IMF_HAVE_GCC_INLINEASM_64 */
+}
+
+
+//
+// Inverse 8x8 DCT, only inverting the DC. This assumes that
+// all AC frequencies are 0.
+//
+
+#ifndef IMF_HAVE_SSE2
+
+void
+dctInverse8x8DcOnly (float *data)
+{
+ float val = data[0] * 3.535536e-01f * 3.535536e-01f;
+
+ for (int i = 0; i < 64; ++i)
+ data[i] = val;
+}
+
+#else /* IMF_HAVE_SSE2 */
+
+void
+dctInverse8x8DcOnly (float *data)
+{
+ __m128 src = _mm_set1_ps (data[0] * 3.535536e-01f * 3.535536e-01f);
+ __m128 *dst = (__m128 *)data;
+
+ for (int i = 0; i < 16; ++i)
+ dst[i] = src;
+}
+
+#endif /* IMF_HAVE_SSE2 */
+
+
+//
+// Full 8x8 Inverse DCT:
+//
+// Simple inverse DCT on an 8x8 block, with scalar ops only.
+// Operates on data in-place.
+//
+// This is based on the iDCT formuation (y = frequency domain,
+// x = spatial domain)
+//
+// [x0] [ ][y0] [ ][y1]
+// [x1] = [ M1 ][y2] + [ M2 ][y3]
+// [x2] [ ][y4] [ ][y5]
+// [x3] [ ][y6] [ ][y7]
+//
+// [x7] [ ][y0] [ ][y1]
+// [x6] = [ M1 ][y2] - [ M2 ][y3]
+// [x5] [ ][y4] [ ][y5]
+// [x4] [ ][y6] [ ][y7]
+//
+// where M1: M2:
+//
+// [a c a f] [b d e g]
+// [a f -a -c] [d -g -b -e]
+// [a -f -a c] [e -b g d]
+// [a -c a -f] [g -e d -b]
+//
+// and the constants are as defined below..
+//
+// If you know how many of the lower rows are zero, that can
+// be passed in to help speed things up. If you don't know,
+// just set zeroedRows=0.
+//
+
+//
+// Default implementation
+//
+
+template <int zeroedRows>
+void
+dctInverse8x8_scalar (float *data)
+{
+ const float a = .5f * cosf (3.14159f / 4.0f);
+ const float b = .5f * cosf (3.14159f / 16.0f);
+ const float c = .5f * cosf (3.14159f / 8.0f);
+ const float d = .5f * cosf (3.f*3.14159f / 16.0f);
+ const float e = .5f * cosf (5.f*3.14159f / 16.0f);
+ const float f = .5f * cosf (3.f*3.14159f / 8.0f);
+ const float g = .5f * cosf (7.f*3.14159f / 16.0f);
+
+ float alpha[4], beta[4], theta[4], gamma[4];
+
+ float *rowPtr = NULL;
+
+ //
+ // First pass - row wise.
+ //
+ // This looks less-compact than the description above in
+ // an attempt to fold together common sub-expressions.
+ //
+
+ for (int row = 0; row < 8 - zeroedRows; ++row)
+ {
+ rowPtr = data + row * 8;
+
+ alpha[0] = c * rowPtr[2];
+ alpha[1] = f * rowPtr[2];
+ alpha[2] = c * rowPtr[6];
+ alpha[3] = f * rowPtr[6];
+
+ beta[0] = b * rowPtr[1] + d * rowPtr[3] + e * rowPtr[5] + g * rowPtr[7];
+ beta[1] = d * rowPtr[1] - g * rowPtr[3] - b * rowPtr[5] - e * rowPtr[7];
+ beta[2] = e * rowPtr[1] - b * rowPtr[3] + g * rowPtr[5] + d * rowPtr[7];
+ beta[3] = g * rowPtr[1] - e * rowPtr[3] + d * rowPtr[5] - b * rowPtr[7];
+
+ theta[0] = a * (rowPtr[0] + rowPtr[4]);
+ theta[3] = a * (rowPtr[0] - rowPtr[4]);
+
+ theta[1] = alpha[0] + alpha[3];
+ theta[2] = alpha[1] - alpha[2];
+
+
+ gamma[0] = theta[0] + theta[1];
+ gamma[1] = theta[3] + theta[2];
+ gamma[2] = theta[3] - theta[2];
+ gamma[3] = theta[0] - theta[1];
+
+
+ rowPtr[0] = gamma[0] + beta[0];
+ rowPtr[1] = gamma[1] + beta[1];
+ rowPtr[2] = gamma[2] + beta[2];
+ rowPtr[3] = gamma[3] + beta[3];
+
+ rowPtr[4] = gamma[3] - beta[3];
+ rowPtr[5] = gamma[2] - beta[2];
+ rowPtr[6] = gamma[1] - beta[1];
+ rowPtr[7] = gamma[0] - beta[0];
+ }
+
+ //
+ // Second pass - column wise.
+ //
+
+ for (int column = 0; column < 8; ++column)
+ {
+ alpha[0] = c * data[16+column];
+ alpha[1] = f * data[16+column];
+ alpha[2] = c * data[48+column];
+ alpha[3] = f * data[48+column];
+
+ beta[0] = b * data[8+column] + d * data[24+column] +
+ e * data[40+column] + g * data[56+column];
+
+ beta[1] = d * data[8+column] - g * data[24+column] -
+ b * data[40+column] - e * data[56+column];
+
+ beta[2] = e * data[8+column] - b * data[24+column] +
+ g * data[40+column] + d * data[56+column];
+
+ beta[3] = g * data[8+column] - e * data[24+column] +
+ d * data[40+column] - b * data[56+column];
+
+ theta[0] = a * (data[column] + data[32+column]);
+ theta[3] = a * (data[column] - data[32+column]);
+
+ theta[1] = alpha[0] + alpha[3];
+ theta[2] = alpha[1] - alpha[2];
+
+ gamma[0] = theta[0] + theta[1];
+ gamma[1] = theta[3] + theta[2];
+ gamma[2] = theta[3] - theta[2];
+ gamma[3] = theta[0] - theta[1];
+
+ data[ column] = gamma[0] + beta[0];
+ data[ 8 + column] = gamma[1] + beta[1];
+ data[16 + column] = gamma[2] + beta[2];
+ data[24 + column] = gamma[3] + beta[3];
+
+ data[32 + column] = gamma[3] - beta[3];
+ data[40 + column] = gamma[2] - beta[2];
+ data[48 + column] = gamma[1] - beta[1];
+ data[56 + column] = gamma[0] - beta[0];
+ }
+}
+
+
+//
+// SSE2 Implementation
+//
+
+template <int zeroedRows>
+void
+dctInverse8x8_sse2 (float *data)
+{
+ #ifdef IMF_HAVE_SSE2
+ __m128 a = {3.535536e-01f,3.535536e-01f,3.535536e-01f,3.535536e-01f};
+ __m128 b = {4.903927e-01f,4.903927e-01f,4.903927e-01f,4.903927e-01f};
+ __m128 c = {4.619398e-01f,4.619398e-01f,4.619398e-01f,4.619398e-01f};
+ __m128 d = {4.157349e-01f,4.157349e-01f,4.157349e-01f,4.157349e-01f};
+ __m128 e = {2.777855e-01f,2.777855e-01f,2.777855e-01f,2.777855e-01f};
+ __m128 f = {1.913422e-01f,1.913422e-01f,1.913422e-01f,1.913422e-01f};
+ __m128 g = {9.754573e-02f,9.754573e-02f,9.754573e-02f,9.754573e-02f};
+
+ __m128 c0 = {3.535536e-01f, 3.535536e-01f, 3.535536e-01f, 3.535536e-01f};
+ __m128 c1 = {4.619398e-01f, 1.913422e-01f,-1.913422e-01f,-4.619398e-01f};
+ __m128 c2 = {3.535536e-01f,-3.535536e-01f,-3.535536e-01f, 3.535536e-01f};
+ __m128 c3 = {1.913422e-01f,-4.619398e-01f, 4.619398e-01f,-1.913422e-01f};
+
+ __m128 c4 = {4.903927e-01f, 4.157349e-01f, 2.777855e-01f, 9.754573e-02f};
+ __m128 c5 = {4.157349e-01f,-9.754573e-02f,-4.903927e-01f,-2.777855e-01f};
+ __m128 c6 = {2.777855e-01f,-4.903927e-01f, 9.754573e-02f, 4.157349e-01f};
+ __m128 c7 = {9.754573e-02f,-2.777855e-01f, 4.157349e-01f,-4.903927e-01f};
+
+ __m128 *srcVec = (__m128 *)data;
+ __m128 x[8], evenSum, oddSum;
+ __m128 in[8], alpha[4], beta[4], theta[4], gamma[4];
+
+ //
+ // Rows -
+ //
+ // Treat this just like matrix-vector multiplication. The
+ // trick is to note that:
+ //
+ // [M00 M01 M02 M03][v0] [(v0 M00) + (v1 M01) + (v2 M02) + (v3 M03)]
+ // [M10 M11 M12 M13][v1] = [(v0 M10) + (v1 M11) + (v2 M12) + (v3 M13)]
+ // [M20 M21 M22 M23][v2] [(v0 M20) + (v1 M21) + (v2 M22) + (v3 M23)]
+ // [M30 M31 M32 M33][v3] [(v0 M30) + (v1 M31) + (v2 M32) + (v3 M33)]
+ //
+ // Then, we can fill a register with v_i and multiply by the i-th column
+ // of M, accumulating across all i-s.
+ //
+ // The kids refer to the populating of a register with a single value
+ // "broadcasting", and it can be done with a shuffle instruction. It
+ // seems to be the slowest part of the whole ordeal.
+ //
+ // Our matrix columns are stored above in c0-c7. c0-3 make up M1, and
+ // c4-7 are from M2.
+ //
+
+ #define DCT_INVERSE_8x8_SS2_ROW_LOOP(i) \
+ /* \
+ * Broadcast the components of the row \
+ */ \
+ \
+ x[0] = _mm_shuffle_ps (srcVec[2 * i], \
+ srcVec[2 * i], \
+ _MM_SHUFFLE (0, 0, 0, 0)); \
+ \
+ x[1] = _mm_shuffle_ps (srcVec[2 * i], \
+ srcVec[2 * i], \
+ _MM_SHUFFLE (1, 1, 1, 1)); \
+ \
+ x[2] = _mm_shuffle_ps (srcVec[2 * i], \
+ srcVec[2 * i], \
+ _MM_SHUFFLE (2, 2, 2, 2)); \
+ \
+ x[3] = _mm_shuffle_ps (srcVec[2 * i], \
+ srcVec[2 * i], \
+ _MM_SHUFFLE (3, 3, 3, 3)); \
+ \
+ x[4] = _mm_shuffle_ps (srcVec[2 * i + 1], \
+ srcVec[2 * i + 1], \
+ _MM_SHUFFLE (0, 0, 0, 0)); \
+ \
+ x[5] = _mm_shuffle_ps (srcVec[2 * i + 1], \
+ srcVec[2 * i + 1], \
+ _MM_SHUFFLE (1, 1, 1, 1)); \
+ \
+ x[6] = _mm_shuffle_ps (srcVec[2 * i + 1], \
+ srcVec[2 * i + 1], \
+ _MM_SHUFFLE (2, 2, 2, 2)); \
+ \
+ x[7] = _mm_shuffle_ps (srcVec[2 * i + 1], \
+ srcVec[2 * i + 1], \
+ _MM_SHUFFLE (3, 3, 3, 3)); \
+ /* \
+ * Multiply the components by each column of the matrix \
+ */ \
+ \
+ x[0] = _mm_mul_ps (x[0], c0); \
+ x[2] = _mm_mul_ps (x[2], c1); \
+ x[4] = _mm_mul_ps (x[4], c2); \
+ x[6] = _mm_mul_ps (x[6], c3); \
+ \
+ x[1] = _mm_mul_ps (x[1], c4); \
+ x[3] = _mm_mul_ps (x[3], c5); \
+ x[5] = _mm_mul_ps (x[5], c6); \
+ x[7] = _mm_mul_ps (x[7], c7); \
+ \
+ /* \
+ * Add across \
+ */ \
+ \
+ evenSum = _mm_setzero_ps(); \
+ evenSum = _mm_add_ps (evenSum, x[0]); \
+ evenSum = _mm_add_ps (evenSum, x[2]); \
+ evenSum = _mm_add_ps (evenSum, x[4]); \
+ evenSum = _mm_add_ps (evenSum, x[6]); \
+ \
+ oddSum = _mm_setzero_ps(); \
+ oddSum = _mm_add_ps (oddSum, x[1]); \
+ oddSum = _mm_add_ps (oddSum, x[3]); \
+ oddSum = _mm_add_ps (oddSum, x[5]); \
+ oddSum = _mm_add_ps (oddSum, x[7]); \
+ \
+ /* \
+ * Final Sum: \
+ * out [0, 1, 2, 3] = evenSum + oddSum \
+ * out [7, 6, 5, 4] = evenSum - oddSum \
+ */ \
+ \
+ srcVec[2 * i] = _mm_add_ps (evenSum, oddSum); \
+ srcVec[2 * i + 1] = _mm_sub_ps (evenSum, oddSum); \
+ srcVec[2 * i + 1] = _mm_shuffle_ps (srcVec[2 * i + 1], \
+ srcVec[2 * i + 1], \
+ _MM_SHUFFLE (0, 1, 2, 3));
+
+ switch (zeroedRows)
+ {
+ case 0:
+ default:
+ DCT_INVERSE_8x8_SS2_ROW_LOOP (0)
+ DCT_INVERSE_8x8_SS2_ROW_LOOP (1)
+ DCT_INVERSE_8x8_SS2_ROW_LOOP (2)
+ DCT_INVERSE_8x8_SS2_ROW_LOOP (3)
+ DCT_INVERSE_8x8_SS2_ROW_LOOP (4)
+ DCT_INVERSE_8x8_SS2_ROW_LOOP (5)
+ DCT_INVERSE_8x8_SS2_ROW_LOOP (6)
+ DCT_INVERSE_8x8_SS2_ROW_LOOP (7)
+ break;
+
+ case 1:
+ DCT_INVERSE_8x8_SS2_ROW_LOOP (0)
+ DCT_INVERSE_8x8_SS2_ROW_LOOP (1)
+ DCT_INVERSE_8x8_SS2_ROW_LOOP (2)
+ DCT_INVERSE_8x8_SS2_ROW_LOOP (3)
+ DCT_INVERSE_8x8_SS2_ROW_LOOP (4)
+ DCT_INVERSE_8x8_SS2_ROW_LOOP (5)
+ DCT_INVERSE_8x8_SS2_ROW_LOOP (6)
+ break;
+
+ case 2:
+ DCT_INVERSE_8x8_SS2_ROW_LOOP (0)
+ DCT_INVERSE_8x8_SS2_ROW_LOOP (1)
+ DCT_INVERSE_8x8_SS2_ROW_LOOP (2)
+ DCT_INVERSE_8x8_SS2_ROW_LOOP (3)
+ DCT_INVERSE_8x8_SS2_ROW_LOOP (4)
+ DCT_INVERSE_8x8_SS2_ROW_LOOP (5)
+ break;
+
+ case 3:
+ DCT_INVERSE_8x8_SS2_ROW_LOOP (0)
+ DCT_INVERSE_8x8_SS2_ROW_LOOP (1)
+ DCT_INVERSE_8x8_SS2_ROW_LOOP (2)
+ DCT_INVERSE_8x8_SS2_ROW_LOOP (3)
+ DCT_INVERSE_8x8_SS2_ROW_LOOP (4)
+ break;
+
+ case 4:
+ DCT_INVERSE_8x8_SS2_ROW_LOOP (0)
+ DCT_INVERSE_8x8_SS2_ROW_LOOP (1)
+ DCT_INVERSE_8x8_SS2_ROW_LOOP (2)
+ DCT_INVERSE_8x8_SS2_ROW_LOOP (3)
+ break;
+
+ case 5:
+ DCT_INVERSE_8x8_SS2_ROW_LOOP (0)
+ DCT_INVERSE_8x8_SS2_ROW_LOOP (1)
+ DCT_INVERSE_8x8_SS2_ROW_LOOP (2)
+ break;
+
+ case 6:
+ DCT_INVERSE_8x8_SS2_ROW_LOOP (0)
+ DCT_INVERSE_8x8_SS2_ROW_LOOP (1)
+ break;
+
+ case 7:
+ DCT_INVERSE_8x8_SS2_ROW_LOOP (0)
+ break;
+ }
+
+ //
+ // Columns -
+ //
+ // This is slightly more straightforward, if less readable. Here
+ // we just operate on 4 columns at a time, in two batches.
+ //
+ // The slight mess is to try and cache sub-expressions, which
+ // we ignore in the row-wise pass.
+ //
+
+ for (int col = 0; col < 2; ++col)
+ {
+
+ for (int i = 0; i < 8; ++i)
+ in[i] = srcVec[2 * i + col];
+
+ alpha[0] = _mm_mul_ps (c, in[2]);
+ alpha[1] = _mm_mul_ps (f, in[2]);
+ alpha[2] = _mm_mul_ps (c, in[6]);
+ alpha[3] = _mm_mul_ps (f, in[6]);
+
+ beta[0] = _mm_add_ps (_mm_add_ps (_mm_mul_ps (in[1], b),
+ _mm_mul_ps (in[3], d)),
+ _mm_add_ps (_mm_mul_ps (in[5], e),
+ _mm_mul_ps (in[7], g)));
+
+ beta[1] = _mm_sub_ps (_mm_sub_ps (_mm_mul_ps (in[1], d),
+ _mm_mul_ps (in[3], g)),
+ _mm_add_ps (_mm_mul_ps (in[5], b),
+ _mm_mul_ps (in[7], e)));
+
+ beta[2] = _mm_add_ps (_mm_sub_ps (_mm_mul_ps (in[1], e),
+ _mm_mul_ps (in[3], b)),
+ _mm_add_ps (_mm_mul_ps (in[5], g),
+ _mm_mul_ps (in[7], d)));
+
+ beta[3] = _mm_add_ps (_mm_sub_ps (_mm_mul_ps (in[1], g),
+ _mm_mul_ps (in[3], e)),
+ _mm_sub_ps (_mm_mul_ps (in[5], d),
+ _mm_mul_ps (in[7], b)));
+
+ theta[0] = _mm_mul_ps (a, _mm_add_ps (in[0], in[4]));
+ theta[3] = _mm_mul_ps (a, _mm_sub_ps (in[0], in[4]));
+
+ theta[1] = _mm_add_ps (alpha[0], alpha[3]);
+ theta[2] = _mm_sub_ps (alpha[1], alpha[2]);
+
+ gamma[0] = _mm_add_ps (theta[0], theta[1]);
+ gamma[1] = _mm_add_ps (theta[3], theta[2]);
+ gamma[2] = _mm_sub_ps (theta[3], theta[2]);
+ gamma[3] = _mm_sub_ps (theta[0], theta[1]);
+
+ srcVec[ col] = _mm_add_ps (gamma[0], beta[0]);
+ srcVec[2+col] = _mm_add_ps (gamma[1], beta[1]);
+ srcVec[4+col] = _mm_add_ps (gamma[2], beta[2]);
+ srcVec[6+col] = _mm_add_ps (gamma[3], beta[3]);
+
+ srcVec[ 8+col] = _mm_sub_ps (gamma[3], beta[3]);
+ srcVec[10+col] = _mm_sub_ps (gamma[2], beta[2]);
+ srcVec[12+col] = _mm_sub_ps (gamma[1], beta[1]);
+ srcVec[14+col] = _mm_sub_ps (gamma[0], beta[0]);
+ }
+
+ #else /* IMF_HAVE_SSE2 */
+
+ dctInverse8x8_scalar<zeroedRows> (data);
+
+ #endif /* IMF_HAVE_SSE2 */
+}
+
+
+//
+// AVX Implementation
+//
+
+#define STR(A) #A
+
+#define IDCT_AVX_SETUP_2_ROWS(_DST0, _DST1, _TMP0, _TMP1, \
+ _OFF00, _OFF01, _OFF10, _OFF11) \
+ "vmovaps " STR(_OFF00) "(%0), %%xmm" STR(_TMP0) " \n" \
+ "vmovaps " STR(_OFF01) "(%0), %%xmm" STR(_TMP1) " \n" \
+ " \n" \
+ "vinsertf128 $1, " STR(_OFF10) "(%0), %%ymm" STR(_TMP0) ", %%ymm" STR(_TMP0) " \n" \
+ "vinsertf128 $1, " STR(_OFF11) "(%0), %%ymm" STR(_TMP1) ", %%ymm" STR(_TMP1) " \n" \
+ " \n" \
+ "vunpcklpd %%ymm" STR(_TMP1) ", %%ymm" STR(_TMP0) ", %%ymm" STR(_DST0) " \n" \
+ "vunpckhpd %%ymm" STR(_TMP1) ", %%ymm" STR(_TMP0) ", %%ymm" STR(_DST1) " \n" \
+ " \n" \
+ "vunpcklps %%ymm" STR(_DST1) ", %%ymm" STR(_DST0) ", %%ymm" STR(_TMP0) " \n" \
+ "vunpckhps %%ymm" STR(_DST1) ", %%ymm" STR(_DST0) ", %%ymm" STR(_TMP1) " \n" \
+ " \n" \
+ "vunpcklpd %%ymm" STR(_TMP1) ", %%ymm" STR(_TMP0) ", %%ymm" STR(_DST0) " \n" \
+ "vunpckhpd %%ymm" STR(_TMP1) ", %%ymm" STR(_TMP0) ", %%ymm" STR(_DST1) " \n"
+
+#define IDCT_AVX_MMULT_ROWS(_SRC) \
+ /* Broadcast the source values into y12-y15 */ \
+ "vpermilps $0x00, " STR(_SRC) ", %%ymm12 \n" \
+ "vpermilps $0x55, " STR(_SRC) ", %%ymm13 \n" \
+ "vpermilps $0xaa, " STR(_SRC) ", %%ymm14 \n" \
+ "vpermilps $0xff, " STR(_SRC) ", %%ymm15 \n" \
+ \
+ /* Multiple coefs and the broadcasted values */ \
+ "vmulps %%ymm12, %%ymm8, %%ymm12 \n" \
+ "vmulps %%ymm13, %%ymm9, %%ymm13 \n" \
+ "vmulps %%ymm14, %%ymm10, %%ymm14 \n" \
+ "vmulps %%ymm15, %%ymm11, %%ymm15 \n" \
+ \
+ /* Accumulate the result back into the source */ \
+ "vaddps %%ymm13, %%ymm12, %%ymm12 \n" \
+ "vaddps %%ymm15, %%ymm14, %%ymm14 \n" \
+ "vaddps %%ymm14, %%ymm12, " STR(_SRC) "\n"
+
+#define IDCT_AVX_EO_TO_ROW_HALVES(_EVEN, _ODD, _FRONT, _BACK) \
+ "vsubps " STR(_ODD) "," STR(_EVEN) "," STR(_BACK) "\n" \
+ "vaddps " STR(_ODD) "," STR(_EVEN) "," STR(_FRONT) "\n" \
+ /* Reverse the back half */ \
+ "vpermilps $0x1b," STR(_BACK) "," STR(_BACK) "\n"
+
+/* In order to allow for path paths when we know certain rows
+ * of the 8x8 block are zero, most of the body of the DCT is
+ * in the following macro. Statements are wrapped in a ROWn()
+ * macro, where n is the lowest row in the 8x8 block in which
+ * they depend.
+ *
+ * This should work for the cases where we have 2-8 full rows.
+ * the 1-row case is special, and we'll handle it seperately.
+ */
+#define IDCT_AVX_BODY \
+ /* ==============================================
+ * Row 1D DCT
+ * ----------------------------------------------
+ */ \
+ \
+ /* Setup for the row-oriented 1D DCT. Assuming that (%0) holds
+ * the row-major 8x8 block, load ymm0-3 with the even columns
+ * and ymm4-7 with the odd columns. The lower half of the ymm
+ * holds one row, while the upper half holds the next row.
+ *
+ * If our source is:
+ * a0 a1 a2 a3 a4 a5 a6 a7
+ * b0 b1 b2 b3 b4 b5 b6 b7
+ *
+ * We'll be forming:
+ * a0 a2 a4 a6 b0 b2 b4 b6
+ * a1 a3 a5 a7 b1 b3 b5 b7
+ */ \
+ ROW0( IDCT_AVX_SETUP_2_ROWS(0, 4, 14, 15, 0, 16, 32, 48) ) \
+ ROW2( IDCT_AVX_SETUP_2_ROWS(1, 5, 12, 13, 64, 80, 96, 112) ) \
+ ROW4( IDCT_AVX_SETUP_2_ROWS(2, 6, 10, 11, 128, 144, 160, 176) ) \
+ ROW6( IDCT_AVX_SETUP_2_ROWS(3, 7, 8, 9, 192, 208, 224, 240) ) \
+ \
+ /* Multiple the even columns (ymm0-3) by the matrix M1
+ * storing the results back in ymm0-3
+ *
+ * Assume that (%1) holds the matrix in column major order
+ */ \
+ "vbroadcastf128 (%1), %%ymm8 \n" \
+ "vbroadcastf128 16(%1), %%ymm9 \n" \
+ "vbroadcastf128 32(%1), %%ymm10 \n" \
+ "vbroadcastf128 48(%1), %%ymm11 \n" \
+ \
+ ROW0( IDCT_AVX_MMULT_ROWS(%%ymm0) ) \
+ ROW2( IDCT_AVX_MMULT_ROWS(%%ymm1) ) \
+ ROW4( IDCT_AVX_MMULT_ROWS(%%ymm2) ) \
+ ROW6( IDCT_AVX_MMULT_ROWS(%%ymm3) ) \
+ \
+ /* Repeat, but with the odd columns (ymm4-7) and the
+ * matrix M2
+ */ \
+ "vbroadcastf128 64(%1), %%ymm8 \n" \
+ "vbroadcastf128 80(%1), %%ymm9 \n" \
+ "vbroadcastf128 96(%1), %%ymm10 \n" \
+ "vbroadcastf128 112(%1), %%ymm11 \n" \
+ \
+ ROW0( IDCT_AVX_MMULT_ROWS(%%ymm4) ) \
+ ROW2( IDCT_AVX_MMULT_ROWS(%%ymm5) ) \
+ ROW4( IDCT_AVX_MMULT_ROWS(%%ymm6) ) \
+ ROW6( IDCT_AVX_MMULT_ROWS(%%ymm7) ) \
+ \
+ /* Sum the M1 (ymm0-3) and M2 (ymm4-7) results to get the
+ * front halves of the results, and difference to get the
+ * back halves. The front halfs end up in ymm0-3, the back
+ * halves end up in ymm12-15.
+ */ \
+ ROW0( IDCT_AVX_EO_TO_ROW_HALVES(%%ymm0, %%ymm4, %%ymm0, %%ymm12) ) \
+ ROW2( IDCT_AVX_EO_TO_ROW_HALVES(%%ymm1, %%ymm5, %%ymm1, %%ymm13) ) \
+ ROW4( IDCT_AVX_EO_TO_ROW_HALVES(%%ymm2, %%ymm6, %%ymm2, %%ymm14) ) \
+ ROW6( IDCT_AVX_EO_TO_ROW_HALVES(%%ymm3, %%ymm7, %%ymm3, %%ymm15) ) \
+ \
+ /* Reassemble the rows halves into ymm0-7 */ \
+ ROW7( "vperm2f128 $0x13, %%ymm3, %%ymm15, %%ymm7 \n" ) \
+ ROW6( "vperm2f128 $0x02, %%ymm3, %%ymm15, %%ymm6 \n" ) \
+ ROW5( "vperm2f128 $0x13, %%ymm2, %%ymm14, %%ymm5 \n" ) \
+ ROW4( "vperm2f128 $0x02, %%ymm2, %%ymm14, %%ymm4 \n" ) \
+ ROW3( "vperm2f128 $0x13, %%ymm1, %%ymm13, %%ymm3 \n" ) \
+ ROW2( "vperm2f128 $0x02, %%ymm1, %%ymm13, %%ymm2 \n" ) \
+ ROW1( "vperm2f128 $0x13, %%ymm0, %%ymm12, %%ymm1 \n" ) \
+ ROW0( "vperm2f128 $0x02, %%ymm0, %%ymm12, %%ymm0 \n" ) \
+ \
+ \
+ /* ==============================================
+ * Column 1D DCT
+ * ----------------------------------------------
+ */ \
+ \
+ /* Rows should be in ymm0-7, and M2 columns should still be
+ * preserved in ymm8-11. M2 has 4 unique values (and +-
+ * versions of each), and all (positive) values appear in
+ * the first column (and row), which is in ymm8.
+ *
+ * For the column-wise DCT, we need to:
+ * 1) Broadcast each element a row of M2 into 4 vectors
+ * 2) Multiple the odd rows (ymm1,3,5,7) by the broadcasts.
+ * 3) Accumulate into ymm12-15 for the odd outputs.
+ *
+ * Instead of doing 16 broadcasts for each element in M2,
+ * do 4, filling y8-11 with:
+ *
+ * ymm8: [ b b b b | b b b b ]
+ * ymm9: [ d d d d | d d d d ]
+ * ymm10: [ e e e e | e e e e ]
+ * ymm11: [ g g g g | g g g g ]
+ *
+ * And deal with the negative values by subtracting during accum.
+ */ \
+ "vpermilps $0xff, %%ymm8, %%ymm11 \n" \
+ "vpermilps $0xaa, %%ymm8, %%ymm10 \n" \
+ "vpermilps $0x55, %%ymm8, %%ymm9 \n" \
+ "vpermilps $0x00, %%ymm8, %%ymm8 \n" \
+ \
+ /* This one is easy, since we have ymm12-15 open for scratch
+ * ymm12 = b ymm1 + d ymm3 + e ymm5 + g ymm7
+ */ \
+ ROW1( "vmulps %%ymm1, %%ymm8, %%ymm12 \n" ) \
+ ROW3( "vmulps %%ymm3, %%ymm9, %%ymm13 \n" ) \
+ ROW5( "vmulps %%ymm5, %%ymm10, %%ymm14 \n" ) \
+ ROW7( "vmulps %%ymm7, %%ymm11, %%ymm15 \n" ) \
+ \
+ ROW3( "vaddps %%ymm12, %%ymm13, %%ymm12 \n" ) \
+ ROW7( "vaddps %%ymm14, %%ymm15, %%ymm14 \n" ) \
+ ROW5( "vaddps %%ymm12, %%ymm14, %%ymm12 \n" ) \
+ \
+ /* Tricker, since only y13-15 are open for scratch
+ * ymm13 = d ymm1 - g ymm3 - b ymm5 - e ymm7
+ */ \
+ ROW1( "vmulps %%ymm1, %%ymm9, %%ymm13 \n" ) \
+ ROW3( "vmulps %%ymm3, %%ymm11, %%ymm14 \n" ) \
+ ROW5( "vmulps %%ymm5, %%ymm8, %%ymm15 \n" ) \
+ \
+ ROW5( "vaddps %%ymm14, %%ymm15, %%ymm14 \n" ) \
+ ROW3( "vsubps %%ymm14, %%ymm13, %%ymm13 \n" ) \
+ \
+ ROW7( "vmulps %%ymm7, %%ymm10, %%ymm15 \n" ) \
+ ROW7( "vsubps %%ymm15, %%ymm13, %%ymm13 \n" ) \
+ \
+ /* Tricker still, as only y14-15 are open for scratch
+ * ymm14 = e ymm1 - b ymm3 + g ymm5 + d ymm7
+ */ \
+ ROW1( "vmulps %%ymm1, %%ymm10, %%ymm14 \n" ) \
+ ROW3( "vmulps %%ymm3, %%ymm8, %%ymm15 \n" ) \
+ \
+ ROW3( "vsubps %%ymm15, %%ymm14, %%ymm14 \n" ) \
+ \
+ ROW5( "vmulps %%ymm5, %%ymm11, %%ymm15 \n" ) \
+ ROW5( "vaddps %%ymm15, %%ymm14, %%ymm14 \n" ) \
+ \
+ ROW7( "vmulps %%ymm7, %%ymm9, %%ymm15 \n" ) \
+ ROW7( "vaddps %%ymm15, %%ymm14, %%ymm14 \n" ) \
+ \
+ \
+ /* Easy, as we can blow away ymm1,3,5,7 for scratch
+ * ymm15 = g ymm1 - e ymm3 + d ymm5 - b ymm7
+ */ \
+ ROW1( "vmulps %%ymm1, %%ymm11, %%ymm15 \n" ) \
+ ROW3( "vmulps %%ymm3, %%ymm10, %%ymm3 \n" ) \
+ ROW5( "vmulps %%ymm5, %%ymm9, %%ymm5 \n" ) \
+ ROW7( "vmulps %%ymm7, %%ymm8, %%ymm7 \n" ) \
+ \
+ ROW5( "vaddps %%ymm15, %%ymm5, %%ymm15 \n" ) \
+ ROW7( "vaddps %%ymm3, %%ymm7, %%ymm3 \n" ) \
+ ROW3( "vsubps %%ymm3, %%ymm15, %%ymm15 \n" ) \
+ \
+ \
+ /* Load coefs for M1. Because we're going to broadcast
+ * coefs, we don't need to load the actual structure from
+ * M1. Instead, just load enough that we can broadcast.
+ * There are only 6 unique values in M1, but they're in +-
+ * pairs, leaving only 3 unique coefs if we add and subtract
+ * properly.
+ *
+ * Fill ymm1 with coef[2] = [ a a c f | a a c f ]
+ * Broadcast ymm5 with [ f f f f | f f f f ]
+ * Broadcast ymm3 with [ c c c c | c c c c ]
+ * Broadcast ymm1 with [ a a a a | a a a a ]
+ */ \
+ "vbroadcastf128 8(%1), %%ymm1 \n" \
+ "vpermilps $0xff, %%ymm1, %%ymm5 \n" \
+ "vpermilps $0xaa, %%ymm1, %%ymm3 \n" \
+ "vpermilps $0x00, %%ymm1, %%ymm1 \n" \
+ \
+ /* If we expand E = [M1] [x0 x2 x4 x6]^t, we get the following
+ * common expressions:
+ *
+ * E_0 = ymm8 = (a ymm0 + a ymm4) + (c ymm2 + f ymm6)
+ * E_3 = ymm11 = (a ymm0 + a ymm4) - (c ymm2 + f ymm6)
+ *
+ * E_1 = ymm9 = (a ymm0 - a ymm4) + (f ymm2 - c ymm6)
+ * E_2 = ymm10 = (a ymm0 - a ymm4) - (f ymm2 - c ymm6)
+ *
+ * Afterwards, ymm8-11 will hold the even outputs.
+ */ \
+ \
+ /* ymm11 = (a ymm0 + a ymm4), ymm1 = (a ymm0 - a ymm4) */ \
+ ROW0( "vmulps %%ymm1, %%ymm0, %%ymm11 \n" ) \
+ ROW4( "vmulps %%ymm1, %%ymm4, %%ymm4 \n" ) \
+ ROW0( "vmovaps %%ymm11, %%ymm1 \n" ) \
+ ROW4( "vaddps %%ymm4, %%ymm11, %%ymm11 \n" ) \
+ ROW4( "vsubps %%ymm4, %%ymm1, %%ymm1 \n" ) \
+ \
+ /* ymm7 = (c ymm2 + f ymm6) */ \
+ ROW2( "vmulps %%ymm3, %%ymm2, %%ymm7 \n" ) \
+ ROW6( "vmulps %%ymm5, %%ymm6, %%ymm9 \n" ) \
+ ROW6( "vaddps %%ymm9, %%ymm7, %%ymm7 \n" ) \
+ \
+ /* E_0 = ymm8 = (a ymm0 + a ymm4) + (c ymm2 + f ymm6)
+ * E_3 = ymm11 = (a ymm0 + a ymm4) - (c ymm2 + f ymm6)
+ */ \
+ ROW0( "vmovaps %%ymm11, %%ymm8 \n" ) \
+ ROW2( "vaddps %%ymm7, %%ymm8, %%ymm8 \n" ) \
+ ROW2( "vsubps %%ymm7, %%ymm11, %%ymm11 \n" ) \
+ \
+ /* ymm7 = (f ymm2 - c ymm6) */ \
+ ROW2( "vmulps %%ymm5, %%ymm2, %%ymm7 \n" ) \
+ ROW6( "vmulps %%ymm3, %%ymm6, %%ymm9 \n" ) \
+ ROW6( "vsubps %%ymm9, %%ymm7, %%ymm7 \n" ) \
+ \
+ /* E_1 = ymm9 = (a ymm0 - a ymm4) + (f ymm2 - c ymm6)
+ * E_2 = ymm10 = (a ymm0 - a ymm4) - (f ymm2 - c ymm6)
+ */ \
+ ROW0( "vmovaps %%ymm1, %%ymm9 \n" ) \
+ ROW0( "vmovaps %%ymm1, %%ymm10 \n" ) \
+ ROW2( "vaddps %%ymm7, %%ymm1, %%ymm9 \n" ) \
+ ROW2( "vsubps %%ymm7, %%ymm1, %%ymm10 \n" ) \
+ \
+ /* Add the even (ymm8-11) and the odds (ymm12-15),
+ * placing the results into ymm0-7
+ */ \
+ "vaddps %%ymm12, %%ymm8, %%ymm0 \n" \
+ "vaddps %%ymm13, %%ymm9, %%ymm1 \n" \
+ "vaddps %%ymm14, %%ymm10, %%ymm2 \n" \
+ "vaddps %%ymm15, %%ymm11, %%ymm3 \n" \
+ \
+ "vsubps %%ymm12, %%ymm8, %%ymm7 \n" \
+ "vsubps %%ymm13, %%ymm9, %%ymm6 \n" \
+ "vsubps %%ymm14, %%ymm10, %%ymm5 \n" \
+ "vsubps %%ymm15, %%ymm11, %%ymm4 \n" \
+ \
+ /* Copy out the results from ymm0-7 */ \
+ "vmovaps %%ymm0, (%0) \n" \
+ "vmovaps %%ymm1, 32(%0) \n" \
+ "vmovaps %%ymm2, 64(%0) \n" \
+ "vmovaps %%ymm3, 96(%0) \n" \
+ "vmovaps %%ymm4, 128(%0) \n" \
+ "vmovaps %%ymm5, 160(%0) \n" \
+ "vmovaps %%ymm6, 192(%0) \n" \
+ "vmovaps %%ymm7, 224(%0) \n"
+
+/* Output, input, and clobber (OIC) sections of the inline asm */
+#define IDCT_AVX_OIC(_IN0) \
+ : /* Output */ \
+ : /* Input */ "r"(_IN0), "r"(sAvxCoef) \
+ : /* Clobber */ "memory", \
+ "%xmm0", "%xmm1", "%xmm2", "%xmm3", \
+ "%xmm4", "%xmm5", "%xmm6", "%xmm7", \
+ "%xmm8", "%xmm9", "%xmm10", "%xmm11",\
+ "%xmm12", "%xmm13", "%xmm14", "%xmm15"
+
+/* Include vzeroupper for non-AVX builds */
+#ifndef __AVX__
+ #define IDCT_AVX_ASM(_IN0) \
+ __asm__( \
+ IDCT_AVX_BODY \
+ "vzeroupper \n" \
+ IDCT_AVX_OIC(_IN0) \
+ );
+#else /* __AVX__ */
+ #define IDCT_AVX_ASM(_IN0) \
+ __asm__( \
+ IDCT_AVX_BODY \
+ IDCT_AVX_OIC(_IN0) \
+ );
+#endif /* __AVX__ */
+
+template <int zeroedRows>
+void
+dctInverse8x8_avx (float *data)
+{
+ #if defined IMF_HAVE_GCC_INLINEASM_64
+
+ /* The column-major version of M1, followed by the
+ * column-major version of M2:
+ *
+ * [ a c a f ] [ b d e g ]
+ * M1 = [ a f -a -c ] M2 = [ d -g -b -e ]
+ * [ a -f -a c ] [ e -b g d ]
+ * [ a -c a -f ] [ g -e d -b ]
+ */
+ const float sAvxCoef[32] __attribute__((aligned(32))) = {
+ 3.535536e-01, 3.535536e-01, 3.535536e-01, 3.535536e-01, /* a a a a */
+ 4.619398e-01, 1.913422e-01, -1.913422e-01, -4.619398e-01, /* c f -f -c */
+ 3.535536e-01, -3.535536e-01, -3.535536e-01, 3.535536e-01, /* a -a -a a */
+ 1.913422e-01, -4.619398e-01, 4.619398e-01, -1.913422e-01, /* f -c c -f */
+
+ 4.903927e-01, 4.157349e-01, 2.777855e-01, 9.754573e-02, /* b d e g */
+ 4.157349e-01, -9.754573e-02, -4.903927e-01, -2.777855e-01, /* d -g -b -e */
+ 2.777855e-01, -4.903927e-01, 9.754573e-02, 4.157349e-01, /* e -b g d */
+ 9.754573e-02, -2.777855e-01, 4.157349e-01, -4.903927e-01 /* g -e d -b */
+ };
+
+ #define ROW0(_X) _X
+ #define ROW1(_X) _X
+ #define ROW2(_X) _X
+ #define ROW3(_X) _X
+ #define ROW4(_X) _X
+ #define ROW5(_X) _X
+ #define ROW6(_X) _X
+ #define ROW7(_X) _X
+
+ if (zeroedRows == 0) {
+
+ IDCT_AVX_ASM(data)
+
+ } else if (zeroedRows == 1) {
+
+ #undef ROW7
+ #define ROW7(_X)
+ IDCT_AVX_ASM(data)
+
+ } else if (zeroedRows == 2) {
+
+ #undef ROW6
+ #define ROW6(_X)
+ IDCT_AVX_ASM(data)
+
+ } else if (zeroedRows == 3) {
+
+ #undef ROW5
+ #define ROW5(_X)
+ IDCT_AVX_ASM(data)
+
+ } else if (zeroedRows == 4) {
+
+ #undef ROW4
+ #define ROW4(_X)
+ IDCT_AVX_ASM(data)
+
+ } else if (zeroedRows == 5) {
+
+ #undef ROW3
+ #define ROW3(_X)
+ IDCT_AVX_ASM(data)
+
+ } else if (zeroedRows == 6) {
+
+ #undef ROW2
+ #define ROW2(_X)
+ IDCT_AVX_ASM(data)
+
+ } else if (zeroedRows == 7) {
+
+ __asm__(
+
+ /* ==============================================
+ * Row 1D DCT
+ * ----------------------------------------------
+ */
+ IDCT_AVX_SETUP_2_ROWS(0, 4, 14, 15, 0, 16, 32, 48)
+
+ "vbroadcastf128 (%1), %%ymm8 \n"
+ "vbroadcastf128 16(%1), %%ymm9 \n"
+ "vbroadcastf128 32(%1), %%ymm10 \n"
+ "vbroadcastf128 48(%1), %%ymm11 \n"
+
+ /* Stash a vector of [a a a a | a a a a] away in ymm2 */
+ "vinsertf128 $1, %%xmm8, %%ymm8, %%ymm2 \n"
+
+ IDCT_AVX_MMULT_ROWS(%%ymm0)
+
+ "vbroadcastf128 64(%1), %%ymm8 \n"
+ "vbroadcastf128 80(%1), %%ymm9 \n"
+ "vbroadcastf128 96(%1), %%ymm10 \n"
+ "vbroadcastf128 112(%1), %%ymm11 \n"
+
+ IDCT_AVX_MMULT_ROWS(%%ymm4)
+
+ IDCT_AVX_EO_TO_ROW_HALVES(%%ymm0, %%ymm4, %%ymm0, %%ymm12)
+
+ "vperm2f128 $0x02, %%ymm0, %%ymm12, %%ymm0 \n"
+
+ /* ==============================================
+ * Column 1D DCT
+ * ----------------------------------------------
+ */
+
+ /* DC only, so multiple by a and we're done */
+ "vmulps %%ymm2, %%ymm0, %%ymm0 \n"
+
+ /* Copy out results */
+ "vmovaps %%ymm0, (%0) \n"
+ "vmovaps %%ymm0, 32(%0) \n"
+ "vmovaps %%ymm0, 64(%0) \n"
+ "vmovaps %%ymm0, 96(%0) \n"
+ "vmovaps %%ymm0, 128(%0) \n"
+ "vmovaps %%ymm0, 160(%0) \n"
+ "vmovaps %%ymm0, 192(%0) \n"
+ "vmovaps %%ymm0, 224(%0) \n"
+
+ #ifndef __AVX__
+ "vzeroupper \n"
+ #endif /* __AVX__ */
+ IDCT_AVX_OIC(data)
+ );
+ } else {
+ assert(false); // Invalid template instance parameter
+ }
+ #else /* IMF_HAVE_GCC_INLINEASM_64 */
+
+ dctInverse8x8_scalar<zeroedRows>(data);
+
+ #endif /* IMF_HAVE_GCC_INLINEASM_64 */
+}
+
+
+//
+// Full 8x8 Forward DCT:
+//
+// Base forward 8x8 DCT implementation. Works on the data in-place
+//
+// The implementation describedin Pennebaker + Mitchell,
+// section 4.3.2, and illustrated in figure 4-7
+//
+// The basic idea is that the 1D DCT math reduces to:
+//
+// 2*out_0 = c_4 [(s_07 + s_34) + (s_12 + s_56)]
+// 2*out_4 = c_4 [(s_07 + s_34) - (s_12 + s_56)]
+//
+// {2*out_2, 2*out_6} = rot_6 ((d_12 - d_56), (s_07 - s_34))
+//
+// {2*out_3, 2*out_5} = rot_-3 (d_07 - c_4 (s_12 - s_56),
+// d_34 - c_4 (d_12 + d_56))
+//
+// {2*out_1, 2*out_7} = rot_-1 (d_07 + c_4 (s_12 - s_56),
+// -d_34 - c_4 (d_12 + d_56))
+//
+// where:
+//
+// c_i = cos(i*pi/16)
+// s_i = sin(i*pi/16)
+//
+// s_ij = in_i + in_j
+// d_ij = in_i - in_j
+//
+// rot_i(x, y) = {c_i*x + s_i*y, -s_i*x + c_i*y}
+//
+// We'll run the DCT in two passes. First, run the 1D DCT on
+// the rows, in-place. Then, run over the columns in-place,
+// and be done with it.
+//
+
+#ifndef IMF_HAVE_SSE2
+
+//
+// Default implementation
+//
+
+void
+dctForward8x8 (float *data)
+{
+ float A0, A1, A2, A3, A4, A5, A6, A7;
+ float K0, K1, rot_x, rot_y;
+
+ float *srcPtr = data;
+ float *dstPtr = data;
+
+ const float c1 = cosf (3.14159f * 1.0f / 16.0f);
+ const float c2 = cosf (3.14159f * 2.0f / 16.0f);
+ const float c3 = cosf (3.14159f * 3.0f / 16.0f);
+ const float c4 = cosf (3.14159f * 4.0f / 16.0f);
+ const float c5 = cosf (3.14159f * 5.0f / 16.0f);
+ const float c6 = cosf (3.14159f * 6.0f / 16.0f);
+ const float c7 = cosf (3.14159f * 7.0f / 16.0f);
+
+ const float c1Half = .5f * c1;
+ const float c2Half = .5f * c2;
+ const float c3Half = .5f * c3;
+ const float c5Half = .5f * c5;
+ const float c6Half = .5f * c6;
+ const float c7Half = .5f * c7;
+
+ //
+ // First pass - do a 1D DCT over the rows and write the
+ // results back in place
+ //
+
+ for (int row=0; row<8; ++row)
+ {
+ float *srcRowPtr = srcPtr + 8 * row;
+ float *dstRowPtr = dstPtr + 8 * row;
+
+ A0 = srcRowPtr[0] + srcRowPtr[7];
+ A1 = srcRowPtr[1] + srcRowPtr[2];
+ A2 = srcRowPtr[1] - srcRowPtr[2];
+ A3 = srcRowPtr[3] + srcRowPtr[4];
+ A4 = srcRowPtr[3] - srcRowPtr[4];
+ A5 = srcRowPtr[5] + srcRowPtr[6];
+ A6 = srcRowPtr[5] - srcRowPtr[6];
+ A7 = srcRowPtr[0] - srcRowPtr[7];
+
+ K0 = c4 * (A0 + A3);
+ K1 = c4 * (A1 + A5);
+
+ dstRowPtr[0] = .5f * (K0 + K1);
+ dstRowPtr[4] = .5f * (K0 - K1);
+
+ //
+ // (2*dst2, 2*dst6) = rot 6 (d12 - d56, s07 - s34)
+ //
+
+ rot_x = A2 - A6;
+ rot_y = A0 - A3;
+
+ dstRowPtr[2] = c6Half * rot_x + c2Half * rot_y;
+ dstRowPtr[6] = c6Half * rot_y - c2Half * rot_x;
+
+ //
+ // K0, K1 are active until after dst[1],dst[7]
+ // as well as dst[3], dst[5] are computed.
+ //
+
+ K0 = c4 * (A1 - A5);
+ K1 = -1 * c4 * (A2 + A6);
+
+ //
+ // Two ways to do a rotation:
+ //
+ // rot i (x, y) =
+ // X = c_i*x + s_i*y
+ // Y = -s_i*x + c_i*y
+ //
+ // OR
+ //
+ // X = c_i*(x+y) + (s_i-c_i)*y
+ // Y = c_i*y - (s_i+c_i)*x
+ //
+ // the first case has 4 multiplies, but fewer constants,
+ // while the 2nd case has fewer multiplies but takes more space.
+
+ //
+ // (2*dst3, 2*dst5) = rot -3 ( d07 - K0, d34 + K1 )
+ //
+
+ rot_x = A7 - K0;
+ rot_y = A4 + K1;
+
+ dstRowPtr[3] = c3Half * rot_x - c5Half * rot_y;
+ dstRowPtr[5] = c5Half * rot_x + c3Half * rot_y;
+
+ //
+ // (2*dst1, 2*dst7) = rot -1 ( d07 + K0, K1 - d34 )
+ //
+
+ rot_x = A7 + K0;
+ rot_y = K1 - A4;
+
+ //
+ // A: 4, 7 are inactive. All A's are inactive
+ //
+
+ dstRowPtr[1] = c1Half * rot_x - c7Half * rot_y;
+ dstRowPtr[7] = c7Half * rot_x + c1Half * rot_y;
+ }
+
+ //
+ // Second pass - do the same, but on the columns
+ //
+
+ for (int column = 0; column < 8; ++column)
+ {
+
+ A0 = srcPtr[ column] + srcPtr[56 + column];
+ A7 = srcPtr[ column] - srcPtr[56 + column];
+
+ A1 = srcPtr[ 8 + column] + srcPtr[16 + column];
+ A2 = srcPtr[ 8 + column] - srcPtr[16 + column];
+
+ A3 = srcPtr[24 + column] + srcPtr[32 + column];
+ A4 = srcPtr[24 + column] - srcPtr[32 + column];
+
+ A5 = srcPtr[40 + column] + srcPtr[48 + column];
+ A6 = srcPtr[40 + column] - srcPtr[48 + column];
+
+ K0 = c4 * (A0 + A3);
+ K1 = c4 * (A1 + A5);
+
+ dstPtr[ column] = .5f * (K0 + K1);
+ dstPtr[32+column] = .5f * (K0 - K1);
+
+ //
+ // (2*dst2, 2*dst6) = rot 6 ( d12 - d56, s07 - s34 )
+ //
+
+ rot_x = A2 - A6;
+ rot_y = A0 - A3;
+
+ dstPtr[16+column] = .5f * (c6 * rot_x + c2 * rot_y);
+ dstPtr[48+column] = .5f * (c6 * rot_y - c2 * rot_x);
+
+ //
+ // K0, K1 are active until after dst[1],dst[7]
+ // as well as dst[3], dst[5] are computed.
+ //
+
+ K0 = c4 * (A1 - A5);
+ K1 = -1 * c4 * (A2 + A6);
+
+ //
+ // (2*dst3, 2*dst5) = rot -3 ( d07 - K0, d34 + K1 )
+ //
+
+ rot_x = A7 - K0;
+ rot_y = A4 + K1;
+
+ dstPtr[24+column] = .5f * (c3 * rot_x - c5 * rot_y);
+ dstPtr[40+column] = .5f * (c5 * rot_x + c3 * rot_y);
+
+ //
+ // (2*dst1, 2*dst7) = rot -1 ( d07 + K0, K1 - d34 )
+ //
+
+ rot_x = A7 + K0;
+ rot_y = K1 - A4;
+
+ dstPtr[ 8+column] = .5f * (c1 * rot_x - c7 * rot_y);
+ dstPtr[56+column] = .5f * (c7 * rot_x + c1 * rot_y);
+ }
+}
+
+#else /* IMF_HAVE_SSE2 */
+
+//
+// SSE2 implementation
+//
+// Here, we're always doing a column-wise operation
+// plus transposes. This might be faster to do differently
+// between rows-wise and column-wise
+//
+
+void
+dctForward8x8 (float *data)
+{
+ __m128 *srcVec = (__m128 *)data;
+ __m128 a0Vec, a1Vec, a2Vec, a3Vec, a4Vec, a5Vec, a6Vec, a7Vec;
+ __m128 k0Vec, k1Vec, rotXVec, rotYVec;
+ __m128 transTmp[4], transTmp2[4];
+
+ __m128 c4Vec = { .70710678f, .70710678f, .70710678f, .70710678f};
+ __m128 c4NegVec = {-.70710678f, -.70710678f, -.70710678f, -.70710678f};
+
+ __m128 c1HalfVec = {.490392640f, .490392640f, .490392640f, .490392640f};
+ __m128 c2HalfVec = {.461939770f, .461939770f, .461939770f, .461939770f};
+ __m128 c3HalfVec = {.415734810f, .415734810f, .415734810f, .415734810f};
+ __m128 c5HalfVec = {.277785120f, .277785120f, .277785120f, .277785120f};
+ __m128 c6HalfVec = {.191341720f, .191341720f, .191341720f, .191341720f};
+ __m128 c7HalfVec = {.097545161f, .097545161f, .097545161f, .097545161f};
+
+ __m128 halfVec = {.5f, .5f, .5f, .5f};
+
+ for (int iter = 0; iter < 2; ++iter)
+ {
+ //
+ // Operate on 4 columns at a time. The
+ // offsets into our row-major array are:
+ // 0: 0 1
+ // 1: 2 3
+ // 2: 4 5
+ // 3: 6 7
+ // 4: 8 9
+ // 5: 10 11
+ // 6: 12 13
+ // 7: 14 15
+ //
+
+ for (int pass=0; pass<2; ++pass)
+ {
+ a0Vec = _mm_add_ps (srcVec[ 0 + pass], srcVec[14 + pass]);
+ a1Vec = _mm_add_ps (srcVec[ 2 + pass], srcVec[ 4 + pass]);
+ a3Vec = _mm_add_ps (srcVec[ 6 + pass], srcVec[ 8 + pass]);
+ a5Vec = _mm_add_ps (srcVec[10 + pass], srcVec[12 + pass]);
+
+ a7Vec = _mm_sub_ps (srcVec[ 0 + pass], srcVec[14 + pass]);
+ a2Vec = _mm_sub_ps (srcVec[ 2 + pass], srcVec[ 4 + pass]);
+ a4Vec = _mm_sub_ps (srcVec[ 6 + pass], srcVec[ 8 + pass]);
+ a6Vec = _mm_sub_ps (srcVec[10 + pass], srcVec[12 + pass]);
+
+ //
+ // First stage; Compute out_0 and out_4
+ //
+
+ k0Vec = _mm_add_ps (a0Vec, a3Vec);
+ k1Vec = _mm_add_ps (a1Vec, a5Vec);
+
+ k0Vec = _mm_mul_ps (c4Vec, k0Vec);
+ k1Vec = _mm_mul_ps (c4Vec, k1Vec);
+
+ srcVec[0 + pass] = _mm_add_ps (k0Vec, k1Vec);
+ srcVec[8 + pass] = _mm_sub_ps (k0Vec, k1Vec);
+
+ srcVec[0 + pass] = _mm_mul_ps (srcVec[0 + pass], halfVec );
+ srcVec[8 + pass] = _mm_mul_ps (srcVec[8 + pass], halfVec );
+
+
+ //
+ // Second stage; Compute out_2 and out_6
+ //
+
+ k0Vec = _mm_sub_ps (a2Vec, a6Vec);
+ k1Vec = _mm_sub_ps (a0Vec, a3Vec);
+
+ srcVec[ 4 + pass] = _mm_add_ps (_mm_mul_ps (c6HalfVec, k0Vec),
+ _mm_mul_ps (c2HalfVec, k1Vec));
+
+ srcVec[12 + pass] = _mm_sub_ps (_mm_mul_ps (c6HalfVec, k1Vec),
+ _mm_mul_ps (c2HalfVec, k0Vec));
+
+ //
+ // Precompute K0 and K1 for the remaining stages
+ //
+
+ k0Vec = _mm_mul_ps (_mm_sub_ps (a1Vec, a5Vec), c4Vec);
+ k1Vec = _mm_mul_ps (_mm_add_ps (a2Vec, a6Vec), c4NegVec);
+
+ //
+ // Third Stage, compute out_3 and out_5
+ //
+
+ rotXVec = _mm_sub_ps (a7Vec, k0Vec);
+ rotYVec = _mm_add_ps (a4Vec, k1Vec);
+
+ srcVec[ 6 + pass] = _mm_sub_ps (_mm_mul_ps (c3HalfVec, rotXVec),
+ _mm_mul_ps (c5HalfVec, rotYVec));
+
+ srcVec[10 + pass] = _mm_add_ps (_mm_mul_ps (c5HalfVec, rotXVec),
+ _mm_mul_ps (c3HalfVec, rotYVec));
+
+ //
+ // Fourth Stage, compute out_1 and out_7
+ //
+
+ rotXVec = _mm_add_ps (a7Vec, k0Vec);
+ rotYVec = _mm_sub_ps (k1Vec, a4Vec);
+
+ srcVec[ 2 + pass] = _mm_sub_ps (_mm_mul_ps (c1HalfVec, rotXVec),
+ _mm_mul_ps (c7HalfVec, rotYVec));
+
+ srcVec[14 + pass] = _mm_add_ps (_mm_mul_ps (c7HalfVec, rotXVec),
+ _mm_mul_ps (c1HalfVec, rotYVec));
+ }
+
+ //
+ // Transpose the matrix, in 4x4 blocks. So, if we have our
+ // 8x8 matrix divied into 4x4 blocks:
+ //
+ // M0 | M1 M0t | M2t
+ // ----+--- --> -----+------
+ // M2 | M3 M1t | M3t
+ //
+
+ //
+ // M0t, done in place, the first half.
+ //
+
+ transTmp[0] = _mm_shuffle_ps (srcVec[0], srcVec[2], 0x44);
+ transTmp[1] = _mm_shuffle_ps (srcVec[4], srcVec[6], 0x44);
+ transTmp[3] = _mm_shuffle_ps (srcVec[4], srcVec[6], 0xEE);
+ transTmp[2] = _mm_shuffle_ps (srcVec[0], srcVec[2], 0xEE);
+
+ //
+ // M3t, also done in place, the first half.
+ //
+
+ transTmp2[0] = _mm_shuffle_ps (srcVec[ 9], srcVec[11], 0x44);
+ transTmp2[1] = _mm_shuffle_ps (srcVec[13], srcVec[15], 0x44);
+ transTmp2[2] = _mm_shuffle_ps (srcVec[ 9], srcVec[11], 0xEE);
+ transTmp2[3] = _mm_shuffle_ps (srcVec[13], srcVec[15], 0xEE);
+
+ //
+ // M0t, the second half.
+ //
+
+ srcVec[0] = _mm_shuffle_ps (transTmp[0], transTmp[1], 0x88);
+ srcVec[4] = _mm_shuffle_ps (transTmp[2], transTmp[3], 0x88);
+ srcVec[2] = _mm_shuffle_ps (transTmp[0], transTmp[1], 0xDD);
+ srcVec[6] = _mm_shuffle_ps (transTmp[2], transTmp[3], 0xDD);
+
+ //
+ // M3t, the second half.
+ //
+
+ srcVec[ 9] = _mm_shuffle_ps (transTmp2[0], transTmp2[1], 0x88);
+ srcVec[13] = _mm_shuffle_ps (transTmp2[2], transTmp2[3], 0x88);
+ srcVec[11] = _mm_shuffle_ps (transTmp2[0], transTmp2[1], 0xDD);
+ srcVec[15] = _mm_shuffle_ps (transTmp2[2], transTmp2[3], 0xDD);
+
+ //
+ // M1 and M2 need to be done at the same time, because we're
+ // swapping.
+ //
+ // First, the first half of M1t
+ //
+
+ transTmp[0] = _mm_shuffle_ps (srcVec[1], srcVec[3], 0x44);
+ transTmp[1] = _mm_shuffle_ps (srcVec[5], srcVec[7], 0x44);
+ transTmp[2] = _mm_shuffle_ps (srcVec[1], srcVec[3], 0xEE);
+ transTmp[3] = _mm_shuffle_ps (srcVec[5], srcVec[7], 0xEE);
+
+ //
+ // And the first half of M2t
+ //
+
+ transTmp2[0] = _mm_shuffle_ps (srcVec[ 8], srcVec[10], 0x44);
+ transTmp2[1] = _mm_shuffle_ps (srcVec[12], srcVec[14], 0x44);
+ transTmp2[2] = _mm_shuffle_ps (srcVec[ 8], srcVec[10], 0xEE);
+ transTmp2[3] = _mm_shuffle_ps (srcVec[12], srcVec[14], 0xEE);
+
+ //
+ // Second half of M1t
+ //
+
+ srcVec[ 8] = _mm_shuffle_ps (transTmp[0], transTmp[1], 0x88);
+ srcVec[12] = _mm_shuffle_ps (transTmp[2], transTmp[3], 0x88);
+ srcVec[10] = _mm_shuffle_ps (transTmp[0], transTmp[1], 0xDD);
+ srcVec[14] = _mm_shuffle_ps (transTmp[2], transTmp[3], 0xDD);
+
+ //
+ // Second half of M2
+ //
+
+ srcVec[1] = _mm_shuffle_ps (transTmp2[0], transTmp2[1], 0x88);
+ srcVec[5] = _mm_shuffle_ps (transTmp2[2], transTmp2[3], 0x88);
+ srcVec[3] = _mm_shuffle_ps (transTmp2[0], transTmp2[1], 0xDD);
+ srcVec[7] = _mm_shuffle_ps (transTmp2[2], transTmp2[3], 0xDD);
+ }
+}
+
+#endif /* IMF_HAVE_SSE2 */
+
+} // anonymous namespace
+
+OPENEXR_IMF_INTERNAL_NAMESPACE_HEADER_EXIT
+
+#endif
//
// Copyright (c) 2004, Industrial Light & Magic, a division of Lucas
// Digital Ltd. LLC
-//
+//
// All rights reserved.
-//
+//
// Redistribution and use in source and binary forms, with or without
// modification, are permitted provided that the following conditions are
// met:
// distribution.
// * Neither the name of Industrial Light & Magic nor the names of
// its contributors may be used to endorse or promote products derived
-// from this software without specific prior written permission.
-//
+// from this software without specific prior written permission.
+//
// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
//
//-----------------------------------------------------------------------------
-#include <ImfEnvmap.h>
+#include "ImfEnvmap.h"
#include "ImathFun.h"
+#include "ImfNamespace.h"
+
#include <algorithm>
#include <math.h>
using namespace std;
-using namespace Imath;
+using namespace IMATH_NAMESPACE;
+
+
+OPENEXR_IMF_INTERNAL_NAMESPACE_SOURCE_ENTER
+
-namespace Imf {
namespace LatLongMap {
-V2f
+V2f
latLong (const V3f &dir)
{
float r = sqrt (dir.z * dir.z + dir.x * dir.x);
float latitude = (r < abs (dir.y))?
- acos (r / dir.length()) * sign (dir.y):
- asin (dir.y / dir.length());
+ acos (r / dir.length()) * sign (dir.y):
+ asin (dir.y / dir.length());
float longitude = (dir.z == 0 && dir.x == 0)? 0: atan2 (dir.x, dir.z);
if (dataWindow.max.y > dataWindow.min.y)
{
- latitude = -M_PI *
- ((pixelPosition.y - dataWindow.min.y) /
- (dataWindow.max.y - dataWindow.min.y) - 0.5f);
+ latitude = -1 * float(M_PI) *
+ ((pixelPosition.y - dataWindow.min.y) /
+ (dataWindow.max.y - dataWindow.min.y) - 0.5f);
}
else
{
- latitude = 0;
+ latitude = 0;
}
if (dataWindow.max.x > dataWindow.min.x)
{
- longitude = -2 * M_PI *
- ((pixelPosition.x - dataWindow.min.x) /
- (dataWindow.max.x - dataWindow.min.x) - 0.5f);
+ longitude = -2 * float(M_PI) *
+ ((pixelPosition.x - dataWindow.min.x) /
+ (dataWindow.max.x - dataWindow.min.x) - 0.5f);
}
else
{
- longitude = 0;
+ longitude = 0;
}
return V2f (latitude, longitude);
V2f
pixelPosition (const Box2i &dataWindow, const V2f &latLong)
{
- float x = latLong.y / (-2 * M_PI) + 0.5f;
- float y = latLong.x / -M_PI + 0.5f;
+ float x = latLong.y / (-2 * float(M_PI)) + 0.5f;
+ float y = latLong.x / (-1 * float(M_PI)) + 0.5f;
return V2f (x * (dataWindow.max.x - dataWindow.min.x) + dataWindow.min.x,
- y * (dataWindow.max.y - dataWindow.min.y) + dataWindow.min.y);
+ y * (dataWindow.max.y - dataWindow.min.y) + dataWindow.min.y);
}
V2f ll = latLong (dataWindow, pixelPosition);
return V3f (sin (ll.y) * cos (ll.x),
- sin (ll.x),
- cos (ll.y) * cos (ll.x));
+ sin (ll.x),
+ cos (ll.y) * cos (ll.x));
}
} // namespace LatLongMap
sizeOfFace (const Box2i &dataWindow)
{
return min ((dataWindow.max.x - dataWindow.min.x + 1),
- (dataWindow.max.y - dataWindow.min.y + 1) / 6);
+ (dataWindow.max.y - dataWindow.min.y + 1) / 6);
}
{
case CUBEFACE_POS_X:
- pos.x = dwf.min.x + positionInFace.y;
- pos.y = dwf.max.y - positionInFace.x;
- break;
+ pos.x = dwf.min.x + positionInFace.y;
+ pos.y = dwf.max.y - positionInFace.x;
+ break;
case CUBEFACE_NEG_X:
- pos.x = dwf.max.x - positionInFace.y;
- pos.y = dwf.max.y - positionInFace.x;
- break;
+ pos.x = dwf.max.x - positionInFace.y;
+ pos.y = dwf.max.y - positionInFace.x;
+ break;
case CUBEFACE_POS_Y:
- pos.x = dwf.min.x + positionInFace.x;
- pos.y = dwf.max.y - positionInFace.y;
- break;
+ pos.x = dwf.min.x + positionInFace.x;
+ pos.y = dwf.max.y - positionInFace.y;
+ break;
case CUBEFACE_NEG_Y:
- pos.x = dwf.min.x + positionInFace.x;
- pos.y = dwf.min.y + positionInFace.y;
- break;
+ pos.x = dwf.min.x + positionInFace.x;
+ pos.y = dwf.min.y + positionInFace.y;
+ break;
case CUBEFACE_POS_Z:
- pos.x = dwf.max.x - positionInFace.x;
- pos.y = dwf.max.y - positionInFace.y;
- break;
+ pos.x = dwf.max.x - positionInFace.x;
+ pos.y = dwf.max.y - positionInFace.y;
+ break;
case CUBEFACE_NEG_Z:
- pos.x = dwf.min.x + positionInFace.x;
- pos.y = dwf.max.y - positionInFace.y;
- break;
+ pos.x = dwf.min.x + positionInFace.x;
+ pos.y = dwf.max.y - positionInFace.y;
+ break;
}
return pos;
void
faceAndPixelPosition (const V3f &direction,
- const Box2i &dataWindow,
- CubeMapFace &face,
- V2f &pif)
+ const Box2i &dataWindow,
+ CubeMapFace &face,
+ V2f &pif)
{
int sof = sizeOfFace (dataWindow);
float absx = abs (direction.x);
if (absx >= absy && absx >= absz)
{
- if (absx == 0)
- {
- //
- // Special case - direction is (0, 0, 0)
- //
-
- face = CUBEFACE_POS_X;
- pif = V2f (0, 0);
- return;
- }
-
- pif.x = (direction.y / absx + 1) / 2 * (sof - 1);
- pif.y = (direction.z / absx + 1) / 2 * (sof - 1);
-
- if (direction.x > 0)
- face = CUBEFACE_POS_X;
- else
- face = CUBEFACE_NEG_X;
+ if (absx == 0)
+ {
+ //
+ // Special case - direction is (0, 0, 0)
+ //
+
+ face = CUBEFACE_POS_X;
+ pif = V2f (0, 0);
+ return;
+ }
+
+ pif.x = (direction.y / absx + 1) / 2 * (sof - 1);
+ pif.y = (direction.z / absx + 1) / 2 * (sof - 1);
+
+ if (direction.x > 0)
+ face = CUBEFACE_POS_X;
+ else
+ face = CUBEFACE_NEG_X;
}
else if (absy >= absz)
{
- pif.x = (direction.x / absy + 1) / 2 * (sof - 1);
- pif.y = (direction.z / absy + 1) / 2 * (sof - 1);
+ pif.x = (direction.x / absy + 1) / 2 * (sof - 1);
+ pif.y = (direction.z / absy + 1) / 2 * (sof - 1);
- if (direction.y > 0)
- face = CUBEFACE_POS_Y;
- else
- face = CUBEFACE_NEG_Y;
+ if (direction.y > 0)
+ face = CUBEFACE_POS_Y;
+ else
+ face = CUBEFACE_NEG_Y;
}
else
{
- pif.x = (direction.x / absz + 1) / 2 * (sof - 1);
- pif.y = (direction.y / absz + 1) / 2 * (sof - 1);
+ pif.x = (direction.x / absz + 1) / 2 * (sof - 1);
+ pif.y = (direction.y / absz + 1) / 2 * (sof - 1);
- if (direction.z > 0)
- face = CUBEFACE_POS_Z;
- else
- face = CUBEFACE_NEG_Z;
+ if (direction.z > 0)
+ face = CUBEFACE_POS_Z;
+ else
+ face = CUBEFACE_NEG_Z;
}
}
int sof = sizeOfFace (dataWindow);
V2f pos;
-
+
if (sof > 1)
{
- pos = V2f (positionInFace.x / (sof - 1) * 2 - 1,
- positionInFace.y / (sof - 1) * 2 - 1);
+ pos = V2f (positionInFace.x / (sof - 1) * 2 - 1,
+ positionInFace.y / (sof - 1) * 2 - 1);
}
else
{
- pos = V2f (0, 0);
+ pos = V2f (0, 0);
}
V3f dir (1, 0, 0);
{
case CUBEFACE_POS_X:
- dir.x = 1;
- dir.y = pos.x;
- dir.z = pos.y;
- break;
+ dir.x = 1;
+ dir.y = pos.x;
+ dir.z = pos.y;
+ break;
case CUBEFACE_NEG_X:
- dir.x = -1;
- dir.y = pos.x;
- dir.z = pos.y;
- break;
+ dir.x = -1;
+ dir.y = pos.x;
+ dir.z = pos.y;
+ break;
case CUBEFACE_POS_Y:
- dir.x = pos.x;
- dir.y = 1;
- dir.z = pos.y;
- break;
+ dir.x = pos.x;
+ dir.y = 1;
+ dir.z = pos.y;
+ break;
case CUBEFACE_NEG_Y:
- dir.x = pos.x;
- dir.y = -1;
- dir.z = pos.y;
- break;
+ dir.x = pos.x;
+ dir.y = -1;
+ dir.z = pos.y;
+ break;
case CUBEFACE_POS_Z:
- dir.x = pos.x;
- dir.y = pos.y;
- dir.z = 1;
- break;
+ dir.x = pos.x;
+ dir.y = pos.y;
+ dir.z = 1;
+ break;
case CUBEFACE_NEG_Z:
- dir.x = pos.x;
- dir.y = pos.y;
- dir.z = -1;
- break;
+ dir.x = pos.x;
+ dir.y = pos.y;
+ dir.z = -1;
+ break;
}
return dir;
}
} // namespace CubeMap
-} // namespace Imf
+
+
+OPENEXR_IMF_INTERNAL_NAMESPACE_SOURCE_EXIT
//
// Copyright (c) 2004, Industrial Light & Magic, a division of Lucas
// Digital Ltd. LLC
-//
+//
// All rights reserved.
-//
+//
// Redistribution and use in source and binary forms, with or without
// modification, are permitted provided that the following conditions are
// met:
// distribution.
// * Neither the name of Industrial Light & Magic nor the names of
// its contributors may be used to endorse or promote products derived
-// from this software without specific prior written permission.
-//
+// from this software without specific prior written permission.
+//
// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
//-----------------------------------------------------------------------------
#include "ImathBox.h"
+#include "ImfNamespace.h"
+#include "ImfExport.h"
+
-namespace Imf {
+OPENEXR_IMF_INTERNAL_NAMESPACE_HEADER_ENTER
//--------------------------------
// Supported environment map types
// and longitude.
//----------------------------------------------------
- Imath::V2f latLong (const Imath::V3f &direction);
+ IMF_EXPORT
+ IMATH_NAMESPACE::V2f latLong (const IMATH_NAMESPACE::V3f &direction);
//--------------------------------------------------------
// and longitude.
//--------------------------------------------------------
- Imath::V2f latLong (const Imath::Box2i &dataWindow,
- const Imath::V2f &pixelPosition);
+ IMF_EXPORT
+ IMATH_NAMESPACE::V2f latLong (const IMATH_NAMESPACE::Box2i &dataWindow,
+ const IMATH_NAMESPACE::V2f &pixelPosition);
//-------------------------------------------------------------
// longitude and latitude, into a corresponding pixel position.
//-------------------------------------------------------------
- Imath::V2f pixelPosition (const Imath::Box2i &dataWindow,
- const Imath::V2f &latLong);
+ IMF_EXPORT
+ IMATH_NAMESPACE::V2f pixelPosition (const IMATH_NAMESPACE::Box2i &dataWindow,
+ const IMATH_NAMESPACE::V2f &latLong);
//-----------------------------------------------------
// to pixelPosition(dw,latLong(dw,dir)).
//-----------------------------------------------------
- Imath::V2f pixelPosition (const Imath::Box2i &dataWindow,
- const Imath::V3f &direction);
+ IMF_EXPORT
+ IMATH_NAMESPACE::V2f pixelPosition (const IMATH_NAMESPACE::Box2i &dataWindow,
+ const IMATH_NAMESPACE::V3f &direction);
//--------------------------------------------------------
// map into a corresponding 3D direction.
//--------------------------------------------------------
- Imath::V3f direction (const Imath::Box2i &dataWindow,
- const Imath::V2f &pixelPosition);
+ IMF_EXPORT
+ IMATH_NAMESPACE::V3f direction (const IMATH_NAMESPACE::Box2i &dataWindow,
+ const IMATH_NAMESPACE::V2f &pixelPosition);
}
// | | / /
// | |/ /
// 4-----------5 Z
-//
+//
// dataWindow.min
// /
-// /
+// /
// +-----------+
// |3 Y 7|
// | | |
// The size of the data window should be N by 6*N pixels
// (width by height), where N can be any integer greater
// than 0.
-//
+//
//--------------------------------------------------------------
//------------------------------------
// Width and height of a cube's face, in pixels
//---------------------------------------------
- int sizeOfFace (const Imath::Box2i &dataWindow);
+ IMF_EXPORT
+ int sizeOfFace (const IMATH_NAMESPACE::Box2i &dataWindow);
//------------------------------------------
// that is covered by the specified face.
//------------------------------------------
- Imath::Box2i dataWindowForFace (CubeMapFace face,
- const Imath::Box2i &dataWindow);
+ IMF_EXPORT
+ IMATH_NAMESPACE::Box2i dataWindowForFace (CubeMapFace face,
+ const IMATH_NAMESPACE::Box2i &dataWindow);
//----------------------------------------------------
// in the environment map.
//----------------------------------------------------
- Imath::V2f pixelPosition (CubeMapFace face,
- const Imath::Box2i &dataWindow,
- Imath::V2f positionInFace);
+ IMF_EXPORT
+ IMATH_NAMESPACE::V2f pixelPosition (CubeMapFace face,
+ const IMATH_NAMESPACE::Box2i &dataWindow,
+ IMATH_NAMESPACE::V2f positionInFace);
//--------------------------------------------------------------
//
//--------------------------------------------------------------
- void faceAndPixelPosition (const Imath::V3f &direction,
- const Imath::Box2i &dataWindow,
- CubeMapFace &face,
- Imath::V2f &positionInFace);
-
+ IMF_EXPORT
+ void faceAndPixelPosition (const IMATH_NAMESPACE::V3f &direction,
+ const IMATH_NAMESPACE::Box2i &dataWindow,
+ CubeMapFace &face,
+ IMATH_NAMESPACE::V2f &positionInFace);
+
// --------------------------------------------------------
// Given a cube face and a pixel position within that face,
// compute the corresponding 3D direction.
// --------------------------------------------------------
- Imath::V3f direction (CubeMapFace face,
- const Imath::Box2i &dataWindow,
- const Imath::V2f &positionInFace);
+ IMF_EXPORT
+ IMATH_NAMESPACE::V3f direction (CubeMapFace face,
+ const IMATH_NAMESPACE::Box2i &dataWindow,
+ const IMATH_NAMESPACE::V2f &positionInFace);
}
-} // namespace Imf
+OPENEXR_IMF_INTERNAL_NAMESPACE_HEADER_EXIT
+
#endif
//
// Copyright (c) 2004, Industrial Light & Magic, a division of Lucas
// Digital Ltd. LLC
-//
+//
// All rights reserved.
-//
+//
// Redistribution and use in source and binary forms, with or without
// modification, are permitted provided that the following conditions are
// met:
// distribution.
// * Neither the name of Industrial Light & Magic nor the names of
// its contributors may be used to endorse or promote products derived
-// from this software without specific prior written permission.
-//
+// from this software without specific prior written permission.
+//
// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
#include <ImfEnvmapAttribute.h>
-namespace Imf {
+OPENEXR_IMF_INTERNAL_NAMESPACE_SOURCE_ENTER
+using namespace OPENEXR_IMF_INTERNAL_NAMESPACE;
template <>
const char *
template <>
void
-EnvmapAttribute::writeValueTo (OStream &os, int) const
+EnvmapAttribute::writeValueTo (OPENEXR_IMF_INTERNAL_NAMESPACE::OStream &os, int version) const
{
unsigned char tmp = _value;
Xdr::write <StreamIO> (os, tmp);
template <>
void
-EnvmapAttribute::readValueFrom (IStream &is, int, int)
+EnvmapAttribute::readValueFrom (OPENEXR_IMF_INTERNAL_NAMESPACE::IStream &is, int size, int version)
{
unsigned char tmp;
Xdr::read <StreamIO> (is, tmp);
}
-} // namespace Imf
+OPENEXR_IMF_INTERNAL_NAMESPACE_SOURCE_EXIT
//
// Copyright (c) 2004, Industrial Light & Magic, a division of Lucas
// Digital Ltd. LLC
-//
+//
// All rights reserved.
-//
+//
// Redistribution and use in source and binary forms, with or without
// modification, are permitted provided that the following conditions are
// met:
// distribution.
// * Neither the name of Industrial Light & Magic nor the names of
// its contributors may be used to endorse or promote products derived
-// from this software without specific prior written permission.
-//
+// from this software without specific prior written permission.
+//
// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
//
//-----------------------------------------------------------------------------
-#include <ImfAttribute.h>
-#include <ImfEnvmap.h>
+#include "ImfAttribute.h"
+#include "ImfEnvmap.h"
+#include "ImfExport.h"
+OPENEXR_IMF_INTERNAL_NAMESPACE_HEADER_ENTER
-namespace Imf {
+typedef TypedAttribute<OPENEXR_IMF_INTERNAL_NAMESPACE::Envmap> EnvmapAttribute;
-typedef TypedAttribute<Envmap> EnvmapAttribute;
-template <> const char *EnvmapAttribute::staticTypeName ();
-template <> void EnvmapAttribute::writeValueTo (OStream &, int) const;
-template <> void EnvmapAttribute::readValueFrom (IStream &, int, int);
+template <> IMF_EXPORT const char *EnvmapAttribute::staticTypeName ();
+template <> IMF_EXPORT
+void EnvmapAttribute::writeValueTo (OPENEXR_IMF_INTERNAL_NAMESPACE::OStream &,
+ int) const;
-} // namespace Imf
+template <> IMF_EXPORT
+void EnvmapAttribute::readValueFrom (OPENEXR_IMF_INTERNAL_NAMESPACE::IStream &,
+ int,
+ int);
-// Metrowerks compiler wants the .cpp file inlined, too
-#ifdef __MWERKS__
-#include <ImfEnvmapAttribute.cpp>
-#endif
+
+OPENEXR_IMF_INTERNAL_NAMESPACE_HEADER_EXIT
#endif
--- /dev/null
+///////////////////////////////////////////////////////////////////////////
+//
+// Copyright (c) 2012, Industrial Light & Magic, a division of Lucas
+// Digital Ltd. LLC
+//
+// All rights reserved.
+//
+// Redistribution and use in source and binary forms, with or without
+// modification, are permitted provided that the following conditions are
+// met:
+// * Redistributions of source code must retain the above copyright
+// notice, this list of conditions and the following disclaimer.
+// * Redistributions in binary form must reproduce the above
+// copyright notice, this list of conditions and the following disclaimer
+// in the documentation and/or other materials provided with the
+// distribution.
+// * Neither the name of Industrial Light & Magic nor the names of
+// its contributors may be used to endorse or promote products derived
+// from this software without specific prior written permission.
+//
+// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+//
+///////////////////////////////////////////////////////////////////////////
+
+#if defined(OPENEXR_DLL)
+ #if defined(ILMIMF_EXPORTS)
+ #define IMF_EXPORT __declspec(dllexport)
+ #define IMF_EXPORT_CONST extern __declspec(dllexport)
+ #else
+ #define IMF_EXPORT __declspec(dllimport)
+ #define IMF_EXPORT_CONST extern __declspec(dllimport)
+ #endif
+#else
+ #define IMF_EXPORT
+ #define IMF_EXPORT_CONST extern const
+#endif
--- /dev/null
+///////////////////////////////////////////////////////////////////////////
+//
+// Copyright (c) 2009-2014 DreamWorks Animation LLC.
+//
+// All rights reserved.
+//
+// Redistribution and use in source and binary forms, with or without
+// modification, are permitted provided that the following conditions are
+// met:
+// * Redistributions of source code must retain the above copyright
+// notice, this list of conditions and the following disclaimer.
+// * Redistributions in binary form must reproduce the above
+// copyright notice, this list of conditions and the following disclaimer
+// in the documentation and/or other materials provided with the
+// distribution.
+// * Neither the name of DreamWorks Animation nor the names of
+// its contributors may be used to endorse or promote products derived
+// from this software without specific prior written permission.
+//
+// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+//
+///////////////////////////////////////////////////////////////////////////
+
+#include "ImfFastHuf.h"
+#include <Iex.h>
+
+#include <string.h>
+#include <assert.h>
+#include <math.h>
+#include <vector>
+
+OPENEXR_IMF_INTERNAL_NAMESPACE_SOURCE_ENTER
+
+//
+// Adapted from hufUnpackEncTable -
+// We don't need to reconstruct the code book, just the encoded
+// lengths for each symbol. From the lengths, we can build the
+// base + offset tables. This should be a bit more efficient
+// for sparse code books.
+//
+// table - ptr to the start of the code length data. Will be
+// updated as we decode data
+//
+// numBytes - size of the encoded table (I think)?
+//
+// minSymbol - smallest symbol in the code book
+//
+// maxSymbol - largest symbol in the code book.
+//
+// rleSymbol - the symbol to trigger RLE in the encoded bitstream
+//
+
+FastHufDecoder::FastHufDecoder
+ (const char *&table,
+ int numBytes,
+ int minSymbol,
+ int maxSymbol,
+ int rleSymbol)
+:
+ _rleSymbol (rleSymbol),
+ _numSymbols (0),
+ _minCodeLength (255),
+ _maxCodeLength (0),
+ _idToSymbol (0)
+{
+ //
+ // List of symbols that we find with non-zero code lengths
+ // (listed in the order we find them). Store these in the
+ // same format as the code book stores codes + lengths -
+ // low 6 bits are the length, everything above that is
+ // the symbol.
+ //
+
+ std::vector<Int64> symbols;
+
+ //
+ // The 'base' table is the minimum code at each code length. base[i]
+ // is the smallest code (numerically) of length i.
+ //
+
+ Int64 base[MAX_CODE_LEN + 1];
+
+ //
+ // The 'offset' table is the position (in sorted order) of the first id
+ // of a given code lenght. Array is indexed by code length, like base.
+ //
+
+ Int64 offset[MAX_CODE_LEN + 1];
+
+ //
+ // Count of how many codes at each length there are. Array is
+ // indexed by code length, like base and offset.
+ //
+
+ size_t codeCount[MAX_CODE_LEN + 1];
+
+ for (int i = 0; i <= MAX_CODE_LEN; ++i)
+ {
+ codeCount[i] = 0;
+ base[i] = 0xffffffffffffffffULL;
+ offset[i] = 0;
+ }
+
+ //
+ // Count the number of codes, the min/max code lengths, the number of
+ // codes with each length, and record symbols with non-zero code
+ // length as we find them.
+ //
+
+ const char *currByte = table;
+ Int64 currBits = 0;
+ int currBitCount = 0;
+
+ const int SHORT_ZEROCODE_RUN = 59;
+ const int LONG_ZEROCODE_RUN = 63;
+ const int SHORTEST_LONG_RUN = 2 + LONG_ZEROCODE_RUN - SHORT_ZEROCODE_RUN;
+
+ for (Int64 symbol = minSymbol; symbol <= maxSymbol; symbol++)
+ {
+ if (currByte - table > numBytes)
+ {
+ throw IEX_NAMESPACE::InputExc ("Error decoding Huffman table "
+ "(Truncated table data).");
+ }
+
+ //
+ // Next code length - either:
+ // 0-58 (literal code length)
+ // 59-62 (various lengths runs of 0)
+ // 63 (run of n 0's, with n is the next 8 bits)
+ //
+
+ Int64 codeLen = readBits (6, currBits, currBitCount, currByte);
+
+ if (codeLen == (Int64) LONG_ZEROCODE_RUN)
+ {
+ if (currByte - table > numBytes)
+ {
+ throw IEX_NAMESPACE::InputExc ("Error decoding Huffman table "
+ "(Truncated table data).");
+ }
+
+ int runLen = readBits (8, currBits, currBitCount, currByte) +
+ SHORTEST_LONG_RUN;
+
+ if (symbol + runLen > maxSymbol + 1)
+ {
+ throw IEX_NAMESPACE::InputExc ("Error decoding Huffman table "
+ "(Run beyond end of table).");
+ }
+
+ symbol += runLen - 1;
+
+ }
+ else if (codeLen >= (Int64) SHORT_ZEROCODE_RUN)
+ {
+ int runLen = codeLen - SHORT_ZEROCODE_RUN + 2;
+
+ if (symbol + runLen > maxSymbol + 1)
+ {
+ throw IEX_NAMESPACE::InputExc ("Error decoding Huffman table "
+ "(Run beyond end of table).");
+ }
+
+ symbol += runLen - 1;
+
+ }
+ else if (codeLen != 0)
+ {
+ symbols.push_back ((symbol << 6) | (codeLen & 63));
+
+ if (codeLen < _minCodeLength)
+ _minCodeLength = codeLen;
+
+ if (codeLen > _maxCodeLength)
+ _maxCodeLength = codeLen;
+
+ codeCount[codeLen]++;
+ }
+ }
+
+ for (int i = 0; i < MAX_CODE_LEN; ++i)
+ _numSymbols += codeCount[i];
+
+ table = currByte;
+
+ //
+ // Compute base - once we have the code length counts, there
+ // is a closed form solution for this
+ //
+
+ {
+ double* countTmp = new double[_maxCodeLength+1];
+
+ for (int l = _minCodeLength; l <= _maxCodeLength; ++l)
+ {
+ countTmp[l] = (double)codeCount[l] *
+ (double)(2 << (_maxCodeLength-l));
+ }
+
+ for (int l = _minCodeLength; l <= _maxCodeLength; ++l)
+ {
+ double tmp = 0;
+
+ for (int k =l + 1; k <= _maxCodeLength; ++k)
+ tmp += countTmp[k];
+
+ tmp /= (double)(2 << (_maxCodeLength - l));
+
+ base[l] = (Int64)ceil (tmp);
+ }
+
+ delete [] countTmp;
+ }
+
+ //
+ // Compute offset - these are the positions of the first
+ // id (not symbol) that has length [i]
+ //
+
+ offset[_maxCodeLength] = 0;
+
+ for (int i= _maxCodeLength - 1; i >= _minCodeLength; i--)
+ offset[i] = offset[i + 1] + codeCount[i + 1];
+
+ //
+ // Allocate and fill the symbol-to-id mapping. Smaller Ids should be
+ // mapped to less-frequent symbols (which have longer codes). Use
+ // the offset table to tell us where the id's for a given code
+ // length start off.
+ //
+
+ _idToSymbol = new int[_numSymbols];
+
+ Int64 mapping[MAX_CODE_LEN + 1];
+ for (int i = 0; i < MAX_CODE_LEN + 1; ++i)
+ mapping[i] = -1;
+ for (int i = _minCodeLength; i <= _maxCodeLength; ++i)
+ mapping[i] = offset[i];
+
+ for (std::vector<Int64>::const_iterator i = symbols.begin();
+ i != symbols.end();
+ ++i)
+ {
+ int codeLen = *i & 63;
+ int symbol = *i >> 6;
+
+ if (mapping[codeLen] >= _numSymbols)
+ throw IEX_NAMESPACE::InputExc ("Huffman decode error "
+ "(Invalid symbol in header).");
+
+ _idToSymbol[mapping[codeLen]] = symbol;
+ mapping[codeLen]++;
+ }
+
+ buildTables(base, offset);
+}
+
+
+FastHufDecoder::~FastHufDecoder()
+{
+ delete[] _idToSymbol;
+}
+
+
+//
+// Static check if the decoder is enabled.
+//
+// ATM, I only have access to little endian hardware for testing,
+// so I'm not entirely sure that we are reading fom the bit stream
+// properly on BE.
+//
+// If you happen to have more obscure hardware, check that the
+// byte swapping in refill() is happening sensable, add an endian
+// check if needed, and fix the preprocessor magic here.
+//
+
+#define READ64(c) \
+ ((Int64)(c)[0] << 56) | ((Int64)(c)[1] << 48) | ((Int64)(c)[2] << 40) | \
+ ((Int64)(c)[3] << 32) | ((Int64)(c)[4] << 24) | ((Int64)(c)[5] << 16) | \
+ ((Int64)(c)[6] << 8) | ((Int64)(c)[7] )
+
+#ifdef __INTEL_COMPILER // ICC built-in swap for LE hosts
+ #if defined (__i386__) || defined(__x86_64__)
+ #undef READ64
+ #define READ64(c) _bswap64 (*(const Int64*)(c))
+ #endif
+#endif
+
+
+bool
+FastHufDecoder::enabled()
+{
+ #if defined(__INTEL_COMPILER) || defined(__GNUC__)
+
+ //
+ // Enabled for ICC, GCC:
+ // __i386__ -> x86
+ // __x86_64__ -> 64-bit x86
+ //
+
+ #if defined (__i386__) || defined(__x86_64__)
+ return true;
+ #else
+ return false;
+ #endif
+
+ #elif defined (_MSC_VER)
+
+ //
+ // Enabled for Visual Studio:
+ // _M_IX86 -> x86
+ // _M_X64 -> 64bit x86
+
+ #if defined (_M_IX86) || defined(_M_X64)
+ return true;
+ #else
+ return false;
+ #endif
+
+ #else
+
+ //
+ // Unknown compiler - Be safe and disable.
+ //
+ return false;
+ #endif
+}
+
+//
+//
+// Built the acceleration tables for lookups on the upper bits
+// as well as the 'LJ' tables.
+//
+
+void
+FastHufDecoder::buildTables (Int64 *base, Int64 *offset)
+{
+ //
+ // Build the 'left justified' base table, by shifting base left..
+ //
+
+ for (int i = 0; i <= MAX_CODE_LEN; ++i)
+ {
+ if (base[i] != 0xffffffffffffffffULL)
+ {
+ _ljBase[i] = base[i] << (64 - i);
+ }
+ else
+ {
+ //
+ // Unused code length - insert dummy values
+ //
+
+ _ljBase[i] = 0xffffffffffffffffULL;
+ }
+ }
+
+ //
+ // Combine some terms into a big fat constant, which for
+ // lack of a better term we'll call the 'left justified'
+ // offset table (because it serves the same function
+ // as 'offset', when using the left justified base table.
+ //
+
+ for (int i = 0; i <= MAX_CODE_LEN; ++i)
+ _ljOffset[i] = offset[i] - (_ljBase[i] >> (64 - i));
+
+ //
+ // Build the acceleration tables for the lookups of
+ // short codes ( <= TABLE_LOOKUP_BITS long)
+ //
+
+ for (Int64 i = 0; i < 1 << TABLE_LOOKUP_BITS; ++i)
+ {
+ Int64 value = i << (64 - TABLE_LOOKUP_BITS);
+
+ _tableSymbol[i] = 0xffff;
+ _tableCodeLen[i] = 0;
+
+ for (int codeLen = _minCodeLength; codeLen <= _maxCodeLength; ++codeLen)
+ {
+ if (_ljBase[codeLen] <= value)
+ {
+ _tableCodeLen[i] = codeLen;
+
+ Int64 id = _ljOffset[codeLen] + (value >> (64 - codeLen));
+ if (id < _numSymbols)
+ {
+ _tableSymbol[i] = _idToSymbol[id];
+ }
+ else
+ {
+ throw IEX_NAMESPACE::InputExc ("Huffman decode error "
+ "(Overrun).");
+ }
+ break;
+ }
+ }
+ }
+
+ //
+ // Store the smallest value in the table that points to real data.
+ // This should be the entry for the largest length that has
+ // valid data (in our case, non-dummy _ljBase)
+ //
+
+ int minIdx = TABLE_LOOKUP_BITS;
+
+ while (minIdx > 0 && _ljBase[minIdx] == 0xffffffffffffffffULL)
+ minIdx--;
+
+ if (minIdx < 0)
+ {
+ //
+ // Error, no codes with lengths 0-TABLE_LOOKUP_BITS used.
+ // Set the min value such that the table is never tested.
+ //
+
+ _tableMin = 0xffffffffffffffffULL;
+ }
+ else
+ {
+ _tableMin = _ljBase[minIdx];
+ }
+}
+
+
+//
+// For decoding, we're holding onto 2 Int64's.
+//
+// The first (buffer), holds the next bits from the bitstream to be
+// decoded. For certain paths in the decoder, we only need TABLE_LOOKUP_BITS
+// valid bits to decode the next symbol. For other paths, we need a full
+// 64-bits to decode a symbol.
+//
+// When we need to refill 'buffer', we could pull bits straight from
+// the bitstream. But this is very slow and requires lots of book keeping
+// (what's the next bit in the next byte?). Instead, we keep another Int64
+// around that we use to refill from. While this doesn't cut down on the
+// book keeping (still need to know how many valid bits), it does cut
+// down on some of the bit shifting crazy and byte access.
+//
+// The refill Int64 (bufferBack) gets left-shifted after we've pulled
+// off bits. If we run out of bits in the input bit stream, we just
+// shift in 0's to bufferBack.
+//
+// The refill act takes numBits from the top of bufferBack and sticks
+// them in the bottom of buffer. If there arn't enough bits in bufferBack,
+// it gets refilled (to 64-bits) from the input bitstream.
+//
+
+inline void
+FastHufDecoder::refill
+ (Int64 &buffer,
+ int numBits, // number of bits to refill
+ Int64 &bufferBack, // the next 64-bits, to refill from
+ int &bufferBackNumBits, // number of bits left in bufferBack
+ const unsigned char *&currByte, // current byte in the bitstream
+ int &currBitsLeft) // number of bits left in the bitsream
+{
+ //
+ // Refill bits into the bottom of buffer, from the top of bufferBack.
+ // Always top up buffer to be completely full.
+ //
+
+ buffer |= bufferBack >> (64 - numBits);
+
+ if (bufferBackNumBits < numBits)
+ {
+ numBits -= bufferBackNumBits;
+
+ //
+ // Refill all of bufferBack from the bitstream. Either grab
+ // a full 64-bit chunk, or whatever bytes are left. If we
+ // don't have 64-bits left, pad with 0's.
+ //
+
+ if (currBitsLeft >= 64)
+ {
+ bufferBack = READ64 (currByte);
+ bufferBackNumBits = 64;
+ currByte += sizeof (Int64);
+ currBitsLeft -= 8 * sizeof (Int64);
+
+ }
+ else
+ {
+ bufferBack = 0;
+ bufferBackNumBits = 64;
+
+ Int64 shift = 56;
+
+ while (currBitsLeft > 0)
+ {
+ bufferBack |= ((Int64)(*currByte)) << shift;
+
+ currByte++;
+ shift -= 8;
+ currBitsLeft -= 8;
+ }
+
+ //
+ // At this point, currBitsLeft might be negative, just because
+ // we're subtracting whole bytes. To keep anyone from freaking
+ // out, zero the counter.
+ //
+
+ if (currBitsLeft < 0)
+ currBitsLeft = 0;
+ }
+
+ buffer |= bufferBack >> (64 - numBits);
+ }
+
+ bufferBack = bufferBack << numBits;
+ bufferBackNumBits -= numBits;
+
+ //
+ // We can have cases where the previous shift of bufferBack is << 64 -
+ // in which case no shift occurs. The bit count math still works though,
+ // so if we don't have any bits left, zero out bufferBack.
+ //
+
+ if (bufferBackNumBits == 0)
+ bufferBack = 0;
+}
+
+//
+// Read the next few bits out of a bitstream. Will be given a backing buffer
+// (buffer) that may still have data left over from previous reads
+// (bufferNumBits). Bitstream pointer (currByte) will be advanced when needed.
+//
+
+inline Int64
+FastHufDecoder::readBits
+ (int numBits,
+ Int64 &buffer, // c
+ int &bufferNumBits, // lc
+ const char *&currByte) // in
+{
+ while (bufferNumBits < numBits)
+ {
+ buffer = (buffer << 8) | *(unsigned char*)(currByte++);
+ bufferNumBits += 8;
+ }
+
+ bufferNumBits -= numBits;
+ return (buffer >> bufferNumBits) & ((1 << numBits) - 1);
+}
+
+
+//
+// Decode using a the 'One-Shift' strategy for decoding, with a
+// small-ish table to accelerate decoding of short codes.
+//
+// If possible, try looking up codes into the acceleration table.
+// This has a few benifits - there's no search involved; We don't
+// need an additional lookup to map id to symbol; we don't need
+// a full 64-bits (so less refilling).
+//
+
+void
+FastHufDecoder::decode
+ (const unsigned char *src,
+ int numSrcBits,
+ unsigned short *dst,
+ int numDstElems)
+{
+ if (numSrcBits < 128)
+ throw IEX_NAMESPACE::InputExc ("Error choosing Huffman decoder implementation "
+ "(insufficient number of bits).");
+
+ //
+ // Current position (byte/bit) in the src data stream
+ // (after the first buffer fill)
+ //
+
+ const unsigned char *currByte = src + 2 * sizeof (Int64);
+
+ numSrcBits -= 8 * 2 * sizeof (Int64);
+
+ //
+ // 64-bit buffer holding the current bits in the stream
+ //
+
+ Int64 buffer = READ64 (src);
+ int bufferNumBits = 64;
+
+ //
+ // 64-bit buffer holding the next bits in the stream
+ //
+
+ Int64 bufferBack = READ64 ((src + sizeof (Int64)));
+ int bufferBackNumBits = 64;
+
+ int dstIdx = 0;
+
+ while (dstIdx < numDstElems)
+ {
+ int codeLen;
+ int symbol;
+
+ //
+ // Test if we can be table accelerated. If so, directly
+ // lookup the output symbol. Otherwise, we need to fall
+ // back to searching for the code.
+ //
+ // If we're doing table lookups, we don't really need
+ // a re-filled buffer, so long as we have TABLE_LOOKUP_BITS
+ // left. But for a search, we do need a refilled table.
+ //
+
+ if (_tableMin <= buffer)
+ {
+ int tableIdx = buffer >> (64 - TABLE_LOOKUP_BITS);
+
+ //
+ // For invalid codes, _tableCodeLen[] should return 0. This
+ // will cause the decoder to get stuck in the current spot
+ // until we run out of elements, then barf that the codestream
+ // is bad. So we don't need to stick a condition like
+ // if (codeLen > _maxCodeLength) in this inner.
+ //
+
+ codeLen = _tableCodeLen[tableIdx];
+ symbol = _tableSymbol[tableIdx];
+ }
+ else
+ {
+ if (bufferNumBits < 64)
+ {
+ refill (buffer,
+ 64 - bufferNumBits,
+ bufferBack,
+ bufferBackNumBits,
+ currByte,
+ numSrcBits);
+
+ bufferNumBits = 64;
+ }
+
+ //
+ // Brute force search:
+ // Find the smallest length where _ljBase[length] <= buffer
+ //
+
+ codeLen = TABLE_LOOKUP_BITS + 1;
+
+ while (_ljBase[codeLen] > buffer && codeLen <= _maxCodeLength)
+ codeLen++;
+
+ if (codeLen > _maxCodeLength)
+ {
+ throw IEX_NAMESPACE::InputExc ("Huffman decode error "
+ "(Decoded an invalid symbol).");
+ }
+
+ Int64 id = _ljOffset[codeLen] + (buffer >> (64 - codeLen));
+ if (id < _numSymbols)
+ {
+ symbol = _idToSymbol[id];
+ }
+ else
+ {
+ throw IEX_NAMESPACE::InputExc ("Huffman decode error "
+ "(Decoded an invalid symbol).");
+ }
+ }
+
+ //
+ // Shift over bit stream, and update the bit count in the buffer
+ //
+
+ buffer = buffer << codeLen;
+ bufferNumBits -= codeLen;
+
+ //
+ // If we recieved a RLE symbol (_rleSymbol), then we need
+ // to read ahead 8 bits to know how many times to repeat
+ // the previous symbol. Need to ensure we at least have
+ // 8 bits of data in the buffer
+ //
+
+ if (symbol == _rleSymbol)
+ {
+ if (bufferNumBits < 8)
+ {
+ refill (buffer,
+ 64 - bufferNumBits,
+ bufferBack,
+ bufferBackNumBits,
+ currByte,
+ numSrcBits);
+
+ bufferNumBits = 64;
+ }
+
+ int rleCount = buffer >> 56;
+
+ if (dstIdx < 1)
+ {
+ throw IEX_NAMESPACE::InputExc ("Huffman decode error (RLE code "
+ "with no previous symbol).");
+ }
+
+ if (dstIdx + rleCount > numDstElems)
+ {
+ throw IEX_NAMESPACE::InputExc ("Huffman decode error (Symbol run "
+ "beyond expected output buffer length).");
+ }
+
+ if (rleCount <= 0)
+ {
+ throw IEX_NAMESPACE::InputExc("Huffman decode error"
+ " (Invalid RLE length)");
+ }
+
+ for (int i = 0; i < rleCount; ++i)
+ dst[dstIdx + i] = dst[dstIdx - 1];
+
+ dstIdx += rleCount;
+
+ buffer = buffer << 8;
+ bufferNumBits -= 8;
+ }
+ else
+ {
+ dst[dstIdx] = symbol;
+ dstIdx++;
+ }
+
+ //
+ // refill bit stream buffer if we're below the number of
+ // bits needed for a table lookup
+ //
+
+ if (bufferNumBits < TABLE_LOOKUP_BITS)
+ {
+ refill (buffer,
+ 64 - bufferNumBits,
+ bufferBack,
+ bufferBackNumBits,
+ currByte,
+ numSrcBits);
+
+ bufferNumBits = 64;
+ }
+ }
+
+ if (numSrcBits != 0)
+ {
+ throw IEX_NAMESPACE::InputExc ("Huffman decode error (Compressed data remains "
+ "after filling expected output buffer).");
+ }
+}
+
+OPENEXR_IMF_INTERNAL_NAMESPACE_SOURCE_EXIT
--- /dev/null
+///////////////////////////////////////////////////////////////////////////
+//
+// Copyright (c) 2009-2014 DreamWorks Animation LLC.
+//
+// All rights reserved.
+//
+// Redistribution and use in source and binary forms, with or without
+// modification, are permitted provided that the following conditions are
+// met:
+// * Redistributions of source code must retain the above copyright
+// notice, this list of conditions and the following disclaimer.
+// * Redistributions in binary form must reproduce the above
+// copyright notice, this list of conditions and the following disclaimer
+// in the documentation and/or other materials provided with the
+// distribution.
+// * Neither the name of DreamWorks Animation nor the names of
+// its contributors may be used to endorse or promote products derived
+// from this software without specific prior written permission.
+//
+// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+//
+///////////////////////////////////////////////////////////////////////////
+
+#ifndef INCLUDED_IMF_FAST_HUF_H
+#define INCLUDED_IMF_FAST_HUF_H
+
+#include "ImfInt64.h"
+#include "ImfNamespace.h"
+#include "ImfExport.h"
+
+OPENEXR_IMF_INTERNAL_NAMESPACE_HEADER_ENTER
+
+//
+// Alternative Canonical Huffman decoder:
+//
+// Canonical Huffman decoder based on 'On the Implementation of Minimum
+// Redundancy Prefix Codes' by Moffat and Turpin - highly recommended
+// reading as a good description of the problem space, as well as
+// a fast decoding algorithm.
+//
+// The premise is that instead of working directly with the coded
+// symbols, we create a new ordering based on the frequency of symbols.
+// Less frequent symbols (and thus longer codes) are ordered earler.
+// We're calling the values in this ordering 'Ids', as oppsed to
+// 'Symbols' - which are the short values we eventually want decoded.
+//
+// With this new ordering, a few small tables can be derived ('base'
+// and 'offset') which drive the decoding. To cut down on the
+// linear scanning of these tables, you can add a small table
+// to directly look up short codes (as you might in a traditional
+// lookup-table driven decoder).
+//
+// The decoder is meant to be compatible with the encoder (and decoder)
+// in ImfHuf.cpp, just faster. For ease of implementation, this decoder
+// should only be used on compressed bitstreams >= 128 bits long.
+//
+
+class FastHufDecoder
+{
+ public:
+
+ //
+ // Longest compressed code length that ImfHuf supports (58 bits)
+ //
+
+ static const int MAX_CODE_LEN = 58;
+
+ //
+ // Number of bits in our acceleration table. Should match all
+ // codes up to TABLE_LOOKUP_BITS in length.
+ //
+
+ static const int TABLE_LOOKUP_BITS = 12;
+
+ IMF_EXPORT
+ FastHufDecoder (const char*& table,
+ int numBytes,
+ int minSymbol,
+ int maxSymbol,
+ int rleSymbol);
+
+ IMF_EXPORT
+ ~FastHufDecoder ();
+
+ IMF_EXPORT
+ static bool enabled ();
+
+ IMF_EXPORT
+ void decode (const unsigned char *src,
+ int numSrcBits,
+ unsigned short *dst,
+ int numDstElems);
+
+ private:
+
+ void buildTables (Int64*, Int64*);
+ void refill (Int64&, int, Int64&, int&, const unsigned char *&, int&);
+ Int64 readBits (int, Int64&, int&, const char *&);
+
+ int _rleSymbol; // RLE symbol written by the encoder.
+ // This could be 65536, so beware
+ // when you use shorts to hold things.
+
+ int _numSymbols; // Number of symbols in the codebook.
+
+ unsigned char _minCodeLength; // Minimum code length, in bits.
+ unsigned char _maxCodeLength; // Maximum code length, in bits.
+
+ int *_idToSymbol; // Maps Ids to symbols. Ids are a symbol
+ // ordering sorted first in terms of
+ // code length, and by code within
+ // the same length. Ids run from 0
+ // to mNumSymbols-1.
+
+ Int64 _ljBase[MAX_CODE_LEN + 1]; // the 'left justified base' table.
+ // Takes base[i] (i = code length)
+ // and 'left justifies' it into an Int64
+
+ Int64 _ljOffset[MAX_CODE_LEN +1 ]; // There are some other terms that can
+ // be folded into constants when taking
+ // the 'left justified' decode path. This
+ // holds those constants, indexed by
+ // code length
+
+ //
+ // We can accelerate the 'left justified' processing by running the
+ // top TABLE_LOOKUP_BITS through a LUT, to find the symbol and code
+ // length. These are those acceleration tables.
+ //
+ // Even though our evental 'symbols' are ushort's, the encoder adds
+ // a symbol to indicate RLE. So with a dense code book, we could
+ // have 2^16+1 codes, so both mIdToSymbol and mTableSymbol need
+ // to be bigger than 16 bits.
+ //
+
+ int _tableSymbol[1 << TABLE_LOOKUP_BITS];
+ unsigned char _tableCodeLen[1 << TABLE_LOOKUP_BITS];
+ Int64 _tableMin;
+};
+
+OPENEXR_IMF_INTERNAL_NAMESPACE_HEADER_EXIT
+
+#endif
//
// Copyright (c) 2002, Industrial Light & Magic, a division of Lucas
// Digital Ltd. LLC
-//
+//
// All rights reserved.
-//
+//
// Redistribution and use in source and binary forms, with or without
// modification, are permitted provided that the following conditions are
// met:
// distribution.
// * Neither the name of Industrial Light & Magic nor the names of
// its contributors may be used to endorse or promote products derived
-// from this software without specific prior written permission.
-//
+// from this software without specific prior written permission.
+//
// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
#include <ImfFloatAttribute.h>
-namespace Imf {
+OPENEXR_IMF_INTERNAL_NAMESPACE_SOURCE_ENTER
template <>
}
-} // namespace Imf
+OPENEXR_IMF_INTERNAL_NAMESPACE_SOURCE_EXIT
//
// Copyright (c) 2002, Industrial Light & Magic, a division of Lucas
// Digital Ltd. LLC
-//
+//
// All rights reserved.
-//
+//
// Redistribution and use in source and binary forms, with or without
// modification, are permitted provided that the following conditions are
// met:
// distribution.
// * Neither the name of Industrial Light & Magic nor the names of
// its contributors may be used to endorse or promote products derived
-// from this software without specific prior written permission.
-//
+// from this software without specific prior written permission.
+//
// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
//
//-----------------------------------------------------------------------------
-#include <ImfAttribute.h>
+#include "ImfAttribute.h"
-namespace Imf {
+OPENEXR_IMF_INTERNAL_NAMESPACE_HEADER_ENTER
typedef TypedAttribute<float> FloatAttribute;
-template <> const char *FloatAttribute::staticTypeName ();
+template <> IMF_EXPORT const char *FloatAttribute::staticTypeName ();
-} // namespace Imf
-
-// Metrowerks compiler wants the .cpp file inlined, too
-#ifdef __MWERKS__
-#include <ImfFloatAttribute.cpp>
-#endif
+OPENEXR_IMF_INTERNAL_NAMESPACE_HEADER_EXIT
#endif
///////////////////////////////////////////////////////////////////////////
//
-// Copyright (c) 2006, Industrial Light & Magic, a division of Lucas
+// Copyright (c) 2013, Industrial Light & Magic, a division of Lucas
// Digital Ltd. LLC
-//
+//
// All rights reserved.
-//
+//
// Redistribution and use in source and binary forms, with or without
// modification, are permitted provided that the following conditions are
// met:
// distribution.
// * Neither the name of Industrial Light & Magic nor the names of
// its contributors may be used to endorse or promote products derived
-// from this software without specific prior written permission.
-//
+// from this software without specific prior written permission.
+//
// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
//
///////////////////////////////////////////////////////////////////////////
-//---------------------------------------------------------------------------
-//
-// b44ExpLogTable
-//
-// A program to generate lookup tables for
-//
-// y = exp (x / 8)
-//
-// and
-// x = 8 * log (x);
-//
-// where x and y are 16-bit floating-point numbers
+
+//-----------------------------------------------------------------------------
//
-// The tables are used by class B44Compressor.
+// class FloatVectorAttribute
//
-//---------------------------------------------------------------------------
+//-----------------------------------------------------------------------------
-#include <half.h>
-#include <math.h>
-#include <iostream>
-#include <iomanip>
+#include <ImfFloatVectorAttribute.h>
-using namespace std;
-
-//---------------------------------------------
-// Main - prints the half-to-float lookup table
-//---------------------------------------------
-
-int
-main ()
-{
-#ifndef HAVE_IOS_BASE
- cout.setf (ios::hex, ios::basefield);
-#else
- cout.setf (ios_base::hex, ios_base::basefield);
-#endif
- cout << "//\n"
- "// This is an automatically generated file.\n"
- "// Do not edit.\n"
- "//\n\n";
+OPENEXR_IMF_INTERNAL_NAMESPACE_SOURCE_ENTER
- const int iMax = (1 << 16);
- cout << "const unsigned short expTable[] =\n"
- "{\n"
- " ";
+using namespace OPENEXR_IMF_INTERNAL_NAMESPACE;
- for (int i = 0; i < iMax; i++)
- {
- half h;
- h.setBits (i);
- if (!h.isFinite())
- h = 0;
- else if (h >= 8 * log (HALF_MAX))
- h = HALF_MAX;
- else
- h = exp (h / 8);
-
- cout << "0x" << setfill ('0') << setw (4) << h.bits() << ", ";
-
- if (i % 8 == 7)
- {
- cout << "\n";
-
- if (i < iMax - 1)
- cout << " ";
- }
- }
-
- cout << "};\n\n";
+template <>
+const char *
+FloatVectorAttribute::staticTypeName ()
+{
+ return "floatvector";
+}
- cout << "const unsigned short logTable[] =\n"
- "{\n"
- " ";
- for (int i = 0; i < iMax; i++)
- {
- half h;
- h.setBits (i);
+template <>
+void
+FloatVectorAttribute::writeValueTo
+ (OPENEXR_IMF_INTERNAL_NAMESPACE::OStream &os, int version) const
+{
+ int n = _value.size();
- if (!h.isFinite() || h < 0)
- h = 0;
- else
- h = 8 * log (h);
+ for (int i = 0; i < n; ++i)
+ Xdr::write <StreamIO> (os, _value[i]);
+}
- cout << "0x" << setfill ('0') << setw (4) << h.bits() << ", ";
- if (i % 8 == 7)
- {
- cout << "\n";
+template <>
+void
+FloatVectorAttribute::readValueFrom
+ (OPENEXR_IMF_INTERNAL_NAMESPACE::IStream &is, int size, int version)
+{
+ int n = size / Xdr::size<float>();
+ _value.resize (n);
- if (i < iMax - 1)
- cout << " ";
- }
- }
+ for (int i = 0; i < n; ++i)
+ Xdr::read <StreamIO> (is, _value[i]);
+}
- cout << "};\n";
- return 0;
-}
+OPENEXR_IMF_INTERNAL_NAMESPACE_SOURCE_EXIT
--- /dev/null
+///////////////////////////////////////////////////////////////////////////
+//
+// Copyright (c) 2007, Weta Digital Ltd
+//
+// All rights reserved.
+//
+// Redistribution and use in source and binary forms, with or without
+// modification, are permitted provided that the following conditions are
+// met:
+// * Redistributions of source code must retain the above copyright
+// notice, this list of conditions and the following disclaimer.
+// * Redistributions in binary form must reproduce the above
+// copyright notice, this list of conditions and the following disclaimer
+// in the documentation and/or other materials provided with the
+// distribution.
+// * Neither the name of Weta Digital nor the names of
+// its contributors may be used to endorse or promote products derived
+// from this software without specific prior written permission.
+//
+// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+//
+///////////////////////////////////////////////////////////////////////////
+
+
+
+#ifndef INCLUDED_IMF_FLOATVECTOR_ATTRIBUTE_H
+#define INCLUDED_IMF_FLOATVECTOR_ATTRIBUTE_H
+
+//-----------------------------------------------------------------------------
+//
+// class FloatVectorAttribute
+//
+//-----------------------------------------------------------------------------
+
+#include "ImfAttribute.h"
+#include "ImfNamespace.h"
+
+#include <vector>
+
+
+OPENEXR_IMF_INTERNAL_NAMESPACE_HEADER_ENTER
+
+typedef std::vector<float>
+ FloatVector;
+
+typedef TypedAttribute<OPENEXR_IMF_INTERNAL_NAMESPACE::FloatVector>
+ FloatVectorAttribute;
+
+template <>
+IMF_EXPORT
+const char *FloatVectorAttribute::staticTypeName ();
+
+template <>
+IMF_EXPORT
+void FloatVectorAttribute::writeValueTo
+ (OPENEXR_IMF_INTERNAL_NAMESPACE::OStream &, int) const;
+
+template <>
+IMF_EXPORT
+void FloatVectorAttribute::readValueFrom
+ (OPENEXR_IMF_INTERNAL_NAMESPACE::IStream &, int, int);
+
+
+OPENEXR_IMF_INTERNAL_NAMESPACE_HEADER_EXIT
+
+#endif
--- /dev/null
+
+
+///////////////////////////////////////////////////////////////////////////
+//
+// Copyright (c) 2011, Industrial Light & Magic, a division of Lucas
+// Digital Ltd. LLC
+//
+// Portions (c) 2012 Weta Digital Ltd
+//
+// All rights reserved.
+//
+// Redistribution and use in source and binary forms, with or without
+// modification, are permitted provided that the following conditions are
+// met:
+// * Redistributions of source code must retain the above copyright
+// notice, this list of conditions and the following disclaimer.
+// * Redistributions in binary form must reproduce the above
+// copyright notice, this list of conditions and the following disclaimer
+// in the documentation and/or other materials provided with the
+// distribution.
+// * Neither the name of Industrial Light & Magic nor the names of
+// its contributors may be used to endorse or promote products derived
+// from this software without specific prior written permission.
+//
+// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+//
+///////////////////////////////////////////////////////////////////////////
+
+#ifndef INCLUDED_IMF_FORWARD_H
+#define INCLUDED_IMF_FORWARD_H
+
+////////////////////////////////////////////////////////////////////
+//
+// Forward declarations for OpenEXR - correctly declares namespace
+//
+////////////////////////////////////////////////////////////////////
+
+#include "ImfNamespace.h"
+
+OPENEXR_IMF_INTERNAL_NAMESPACE_HEADER_ENTER
+
+
+// classes for basic types;
+template<class T> class Array;
+template<class T> class Array2D;
+struct Channel;
+class ChannelList;
+struct Chromaticities;
+
+// attributes used in headers are TypedAttributes
+class Attribute;
+
+class Header;
+
+// file handling classes
+class OutputFile;
+class TiledInputFile;
+class ScanLineInputFile;
+class InputFile;
+class TiledOutputFile;
+class DeepScanLineInputFile;
+class DeepScanLineOutputFile;
+class DeepTiledInputFile;
+class DeepTiledOutputFile;
+class AcesInputFile;
+class AcesOutputFile;
+class TiledInputPart;
+class TiledInputFile;
+class TileOffsets;
+
+// multipart file handling
+class GenericInputFile;
+class GenericOutputFile;
+class MultiPartInputFile;
+class MultiPartOutputFile;
+
+class InputPart;
+class TiledInputPart;
+class DeepScanLineInputPart;
+class DeepTiledInputPart;
+
+class OutputPart;
+class ScanLineOutputPart;
+class TiledOutputPart;
+class DeepScanLineOutputPart;
+class DeepTiledOutputPart;
+
+
+// internal use only
+struct InputPartData;
+struct OutputStreamMutex;
+struct OutputPartData;
+struct InputStreamMutex;
+
+// frame buffers
+
+class FrameBuffer;
+class DeepFrameBuffer;
+struct DeepSlice;
+
+// compositing
+class DeepCompositing;
+class CompositeDeepScanLine;
+
+// preview image
+class PreviewImage;
+struct PreviewRgba;
+
+// streams
+class OStream;
+class IStream;
+
+
+OPENEXR_IMF_INTERNAL_NAMESPACE_HEADER_EXIT
+
+
+#endif // include guard
//
// Copyright (c) 2002, Industrial Light & Magic, a division of Lucas
// Digital Ltd. LLC
-//
+//
// All rights reserved.
-//
+//
// Redistribution and use in source and binary forms, with or without
// modification, are permitted provided that the following conditions are
// met:
// distribution.
// * Neither the name of Industrial Light & Magic nor the names of
// its contributors may be used to endorse or promote products derived
-// from this software without specific prior written permission.
-//
+// from this software without specific prior written permission.
+//
// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
//-----------------------------------------------------------------------------
//
-// class Slice
-// class FrameBuffer
+// class Slice
+// class FrameBuffer
//
//-----------------------------------------------------------------------------
using namespace std;
-namespace Imf {
+#include "ImfNamespace.h"
+
+OPENEXR_IMF_INTERNAL_NAMESPACE_SOURCE_ENTER
Slice::Slice (PixelType t,
- char *b,
- size_t xst,
- size_t yst,
- int xsm,
- int ysm,
- double fv,
+ char *b,
+ size_t xst,
+ size_t yst,
+ int xsm,
+ int ysm,
+ double fv,
bool xtc,
bool ytc)
:
{
if (name[0] == 0)
{
- THROW (Iex::ArgExc,
- "Frame buffer slice name cannot be an empty string.");
+ THROW (IEX_NAMESPACE::ArgExc,
+ "Frame buffer slice name cannot be an empty string.");
}
_map[name] = slice;
if (i == _map.end())
{
- THROW (Iex::ArgExc,
- "Cannot find frame buffer slice \"" << name << "\".");
+ THROW (IEX_NAMESPACE::ArgExc,
+ "Cannot find frame buffer slice \"" << name << "\".");
}
return i->second;
if (i == _map.end())
{
- THROW (Iex::ArgExc,
- "Cannot find frame buffer slice \"" << name << "\".");
+ THROW (IEX_NAMESPACE::ArgExc,
+ "Cannot find frame buffer slice \"" << name << "\".");
}
return i->second;
}
-} // namespace Imf
+OPENEXR_IMF_INTERNAL_NAMESPACE_SOURCE_EXIT
//
// Copyright (c) 2002, Industrial Light & Magic, a division of Lucas
// Digital Ltd. LLC
-//
+//
// All rights reserved.
-//
+//
// Redistribution and use in source and binary forms, with or without
// modification, are permitted provided that the following conditions are
// met:
// distribution.
// * Neither the name of Industrial Light & Magic nor the names of
// its contributors may be used to endorse or promote products derived
-// from this software without specific prior written permission.
-//
+// from this software without specific prior written permission.
+//
// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
//-----------------------------------------------------------------------------
//
-// class Slice
-// class FrameBuffer
+// class Slice
+// class FrameBuffer
//
//-----------------------------------------------------------------------------
-#include <ImfName.h>
-#include <ImfPixelType.h>
+#include "ImfName.h"
+#include "ImfPixelType.h"
+#include "ImfExport.h"
+#include "ImfNamespace.h"
+
#include <map>
#include <string>
-namespace Imf {
+OPENEXR_IMF_INTERNAL_NAMESPACE_HEADER_ENTER
//-------------------------------------------------------
// Data type; see ImfPixelType.h
//------------------------------
- PixelType type;
+ PixelType type;
//---------------------------------------------------------------------
// Memory layout: The address of pixel (x, y) is
//
- // base + (xp / xSampling) * xStride + (yp / ySampling) * yStride
+ // base + (xp / xSampling) * xStride + (yp / ySampling) * yStride
//
// where xp and yp are computed as follows:
//
- // * If we are reading or writing a scanline-based file:
+ // * If we are reading or writing a scanline-based file:
//
- // xp = x
- // yp = y
+ // xp = x
+ // yp = y
//
// * If we are reading a tile whose upper left coorner is at (xt, yt):
//
- // if xTileCoords is true then xp = x - xt, else xp = x
- // if yTileCoords is true then yp = y - yt, else yp = y
+ // if xTileCoords is true then xp = x - xt, else xp = x
+ // if yTileCoords is true then yp = y - yt, else yp = y
//
//---------------------------------------------------------------------
- char * base;
- size_t xStride;
- size_t yStride;
+ char * base;
+ size_t xStride;
+ size_t yStride;
//--------------------------------------------
// Subsampling: pixel (x, y) is present in the
- // slice only if
+ // slice only if
//
// x % xSampling == 0 && y % ySampling == 0
//
//--------------------------------------------
- int xSampling;
- int ySampling;
+ int xSampling;
+ int ySampling;
//----------------------------------------------------------
// a channel that corresponds to this slice is read.
//----------------------------------------------------------
- double fillValue;
-
+ double fillValue;
+
//-------------------------------------------------------
// For tiled files, the xTileCoords and yTileCoords flags
// Constructor
//------------
+ IMF_EXPORT
Slice (PixelType type = HALF,
- char * base = 0,
- size_t xStride = 0,
- size_t yStride = 0,
- int xSampling = 1,
- int ySampling = 1,
- double fillValue = 0.0,
+ char * base = 0,
+ size_t xStride = 0,
+ size_t yStride = 0,
+ int xSampling = 1,
+ int ySampling = 1,
+ double fillValue = 0.0,
bool xTileCoords = false,
bool yTileCoords = false);
};
// Add a slice
//------------
- void insert (const char name[],
- const Slice &slice);
+ IMF_EXPORT
+ void insert (const char name[],
+ const Slice &slice);
- void insert (const std::string &name,
- const Slice &slice);
+ IMF_EXPORT
+ void insert (const std::string &name,
+ const Slice &slice);
//----------------------------------------------------------------
// Access to existing slices:
//
- // [n] Returns a reference to the slice with name n.
- // If no slice with name n exists, an Iex::ArgExc
- // is thrown.
+ // [n] Returns a reference to the slice with name n.
+ // If no slice with name n exists, an IEX_NAMESPACE::ArgExc
+ // is thrown.
//
- // findSlice(n) Returns a pointer to the slice with name n,
- // or 0 if no slice with name n exists.
+ // findSlice(n) Returns a pointer to the slice with name n,
+ // or 0 if no slice with name n exists.
//
//----------------------------------------------------------------
- Slice & operator [] (const char name[]);
- const Slice & operator [] (const char name[]) const;
+ IMF_EXPORT
+ Slice & operator [] (const char name[]);
+ IMF_EXPORT
+ const Slice & operator [] (const char name[]) const;
- Slice & operator [] (const std::string &name);
- const Slice & operator [] (const std::string &name) const;
+ IMF_EXPORT
+ Slice & operator [] (const std::string &name);
+ IMF_EXPORT
+ const Slice & operator [] (const std::string &name) const;
- Slice * findSlice (const char name[]);
- const Slice * findSlice (const char name[]) const;
+ IMF_EXPORT
+ Slice * findSlice (const char name[]);
+ IMF_EXPORT
+ const Slice * findSlice (const char name[]) const;
- Slice * findSlice (const std::string &name);
- const Slice * findSlice (const std::string &name) const;
+ IMF_EXPORT
+ Slice * findSlice (const std::string &name);
+ IMF_EXPORT
+ const Slice * findSlice (const std::string &name) const;
//-----------------------------------------
class Iterator;
class ConstIterator;
- Iterator begin ();
- ConstIterator begin () const;
+ IMF_EXPORT
+ Iterator begin ();
+ IMF_EXPORT
+ ConstIterator begin () const;
- Iterator end ();
- ConstIterator end () const;
+ IMF_EXPORT
+ Iterator end ();
+ IMF_EXPORT
+ ConstIterator end () const;
- Iterator find (const char name[]);
- ConstIterator find (const char name[]) const;
+ IMF_EXPORT
+ Iterator find (const char name[]);
+ IMF_EXPORT
+ ConstIterator find (const char name[]) const;
- Iterator find (const std::string &name);
- ConstIterator find (const std::string &name) const;
+ IMF_EXPORT
+ Iterator find (const std::string &name);
+ IMF_EXPORT
+ ConstIterator find (const std::string &name) const;
private:
- SliceMap _map;
+ SliceMap _map;
};
{
public:
+ IMF_EXPORT
Iterator ();
+ IMF_EXPORT
Iterator (const FrameBuffer::SliceMap::iterator &i);
- Iterator & operator ++ ();
- Iterator operator ++ (int);
+ IMF_EXPORT
+ Iterator & operator ++ ();
+ IMF_EXPORT
+ Iterator operator ++ (int);
- const char * name () const;
- Slice & slice () const;
+ IMF_EXPORT
+ const char * name () const;
+ IMF_EXPORT
+ Slice & slice () const;
private:
{
public:
+ IMF_EXPORT
ConstIterator ();
+ IMF_EXPORT
ConstIterator (const FrameBuffer::SliceMap::const_iterator &i);
+ IMF_EXPORT
ConstIterator (const FrameBuffer::Iterator &other);
- ConstIterator & operator ++ ();
- ConstIterator operator ++ (int);
+ IMF_EXPORT
+ ConstIterator & operator ++ ();
+ IMF_EXPORT
+ ConstIterator operator ++ (int);
- const char * name () const;
- const Slice & slice () const;
+ IMF_EXPORT
+ const char * name () const;
+ IMF_EXPORT
+ const Slice & slice () const;
private:
inline bool
operator == (const FrameBuffer::ConstIterator &x,
- const FrameBuffer::ConstIterator &y)
+ const FrameBuffer::ConstIterator &y)
{
return x._i == y._i;
}
inline bool
operator != (const FrameBuffer::ConstIterator &x,
- const FrameBuffer::ConstIterator &y)
+ const FrameBuffer::ConstIterator &y)
{
return !(x == y);
}
-} // namespace Imf
+OPENEXR_IMF_INTERNAL_NAMESPACE_HEADER_EXIT
#endif
//
// Copyright (c) 2006, Industrial Light & Magic, a division of Lucas
// Digital Ltd. LLC
-//
+//
// All rights reserved.
-//
+//
// Redistribution and use in source and binary forms, with or without
// modification, are permitted provided that the following conditions are
// met:
// distribution.
// * Neither the name of Industrial Light & Magic nor the names of
// its contributors may be used to endorse or promote products derived
-// from this software without specific prior written permission.
-//
+// from this software without specific prior written permission.
+//
// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
#include <ImfFramesPerSecond.h>
#include "ImathFun.h"
-using namespace Imath;
+using namespace IMATH_NAMESPACE;
+#include "ImfNamespace.h"
-namespace Imf {
+OPENEXR_IMF_INTERNAL_NAMESPACE_SOURCE_ENTER
Rational
guessExactFps (double fps)
const double e = 0.002;
if (abs (double (fps) - double (fps_23_976())) < e)
- return fps_23_976();
+ return fps_23_976();
if (abs (double (fps) - double (fps_29_97())) < e)
- return fps_29_97();
+ return fps_29_97();
if (abs (double (fps) - double (fps_47_952())) < e)
- return fps_47_952();
+ return fps_47_952();
if (abs (double (fps) - double (fps_59_94())) < e)
- return fps_59_94();
+ return fps_59_94();
return fps;
}
-} // namespace Imf
+OPENEXR_IMF_INTERNAL_NAMESPACE_SOURCE_EXIT
//
// Copyright (c) 2006, Industrial Light & Magic, a division of Lucas
// Digital Ltd. LLC
-//
+//
// All rights reserved.
-//
+//
// Redistribution and use in source and binary forms, with or without
// modification, are permitted provided that the following conditions are
// met:
// distribution.
// * Neither the name of Industrial Light & Magic nor the names of
// its contributors may be used to endorse or promote products derived
-// from this software without specific prior written permission.
-//
+// from this software without specific prior written permission.
+//
// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
//
//-----------------------------------------------------------------------------
-#include <ImfRational.h>
+#include "ImfRational.h"
+#include "ImfNamespace.h"
+#include "ImfExport.h"
+
+
+OPENEXR_IMF_INTERNAL_NAMESPACE_HEADER_ENTER
-namespace Imf {
inline Rational fps_23_976 () {return Rational (24000, 1001);}
inline Rational fps_24 () {return Rational (24, 1);}
inline Rational fps_59_94 () {return Rational (60000, 1001);}
inline Rational fps_60 () {return Rational (60, 1);}
-Rational guessExactFps (double fps);
-Rational guessExactFps (const Rational &fps);
+IMF_EXPORT Rational guessExactFps (double fps);
+IMF_EXPORT Rational guessExactFps (const Rational &fps);
+
+
+OPENEXR_IMF_INTERNAL_NAMESPACE_HEADER_EXIT
-} // namespace Imf
#endif
--- /dev/null
+///////////////////////////////////////////////////////////////////////////
+//
+// Copyright (c) 2011, Industrial Light & Magic, a division of Lucas
+// Digital Ltd. LLC
+//
+// All rights reserved.
+//
+// Redistribution and use in source and binary forms, with or without
+// modification, are permitted provided that the following conditions are
+// met:
+// * Redistributions of source code must retain the above copyright
+// notice, this list of conditions and the following disclaimer.
+// * Redistributions in binary form must reproduce the above
+// copyright notice, this list of conditions and the following disclaimer
+// in the documentation and/or other materials provided with the
+// distribution.
+// * Neither the name of Industrial Light & Magic nor the names of
+// its contributors may be used to endorse or promote products derived
+// from this software without specific prior written permission.
+//
+// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+//
+///////////////////////////////////////////////////////////////////////////
+
+#include "ImfGenericInputFile.h"
+
+#include <ImfVersion.h>
+#include <ImfXdr.h>
+#include <Iex.h>
+#include <OpenEXRConfig.h>
+
+OPENEXR_IMF_INTERNAL_NAMESPACE_SOURCE_ENTER
+
+void GenericInputFile::readMagicNumberAndVersionField(OPENEXR_IMF_INTERNAL_NAMESPACE::IStream& is, int& version)
+{
+ //
+ // Read the magic number and the file format version number.
+ // Then check if we can read the rest of this file.
+ //
+
+ int magic;
+
+ OPENEXR_IMF_INTERNAL_NAMESPACE::Xdr::read <OPENEXR_IMF_INTERNAL_NAMESPACE::StreamIO> (is, magic);
+ OPENEXR_IMF_INTERNAL_NAMESPACE::Xdr::read <OPENEXR_IMF_INTERNAL_NAMESPACE::StreamIO> (is, version);
+
+ if (magic != MAGIC)
+ {
+ throw IEX_NAMESPACE::InputExc ("File is not an image file.");
+ }
+
+ if (getVersion (version) != EXR_VERSION)
+ {
+ THROW (IEX_NAMESPACE::InputExc, "Cannot read "
+ "version " << getVersion (version) << " "
+ "image files. Current file format version "
+ "is " << EXR_VERSION << ".");
+ }
+
+ if (!supportsFlags (getFlags (version)))
+ {
+ THROW (IEX_NAMESPACE::InputExc, "The file format version number's flag field "
+ "contains unrecognized flags.");
+ }
+}
+
+OPENEXR_IMF_INTERNAL_NAMESPACE_SOURCE_EXIT
--- /dev/null
+///////////////////////////////////////////////////////////////////////////
+//
+// Copyright (c) 2011, Industrial Light & Magic, a division of Lucas
+// Digital Ltd. LLC
+//
+// All rights reserved.
+//
+// Redistribution and use in source and binary forms, with or without
+// modification, are permitted provided that the following conditions are
+// met:
+// * Redistributions of source code must retain the above copyright
+// notice, this list of conditions and the following disclaimer.
+// * Redistributions in binary form must reproduce the above
+// copyright notice, this list of conditions and the following disclaimer
+// in the documentation and/or other materials provided with the
+// distribution.
+// * Neither the name of Industrial Light & Magic nor the names of
+// its contributors may be used to endorse or promote products derived
+// from this software without specific prior written permission.
+//
+// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+//
+///////////////////////////////////////////////////////////////////////////
+
+#ifndef IMFGENERICINPUTFILE_H_
+#define IMFGENERICINPUTFILE_H_
+
+#include "ImfIO.h"
+#include "ImfHeader.h"
+#include "ImfNamespace.h"
+#include "ImfExport.h"
+
+OPENEXR_IMF_INTERNAL_NAMESPACE_HEADER_ENTER
+
+class GenericInputFile
+{
+ public:
+ IMF_EXPORT
+ virtual ~GenericInputFile() {}
+
+ protected:
+ IMF_EXPORT
+ GenericInputFile() {}
+ IMF_EXPORT
+ void readMagicNumberAndVersionField(OPENEXR_IMF_INTERNAL_NAMESPACE::IStream& is, int& version);
+};
+
+OPENEXR_IMF_INTERNAL_NAMESPACE_HEADER_EXIT
+
+
+#endif /* IMFGENERICINPUTFILE_H_ */
--- /dev/null
+///////////////////////////////////////////////////////////////////////////
+//
+// Copyright (c) 2011, Industrial Light & Magic, a division of Lucas
+// Digital Ltd. LLC
+//
+// All rights reserved.
+//
+// Redistribution and use in source and binary forms, with or without
+// modification, are permitted provided that the following conditions are
+// met:
+// * Redistributions of source code must retain the above copyright
+// notice, this list of conditions and the following disclaimer.
+// * Redistributions in binary form must reproduce the above
+// copyright notice, this list of conditions and the following disclaimer
+// in the documentation and/or other materials provided with the
+// distribution.
+// * Neither the name of Industrial Light & Magic nor the names of
+// its contributors may be used to endorse or promote products derived
+// from this software without specific prior written permission.
+//
+// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+//
+///////////////////////////////////////////////////////////////////////////
+
+#include "ImfGenericOutputFile.h"
+
+#include <ImfBoxAttribute.h>
+#include <ImfFloatAttribute.h>
+#include <ImfTimeCodeAttribute.h>
+#include <ImfChromaticitiesAttribute.h>
+
+#include <ImfMisc.h>
+#include <ImfPartType.h>
+
+#include "ImfNamespace.h"
+
+
+OPENEXR_IMF_INTERNAL_NAMESPACE_SOURCE_ENTER
+
+
+using namespace std;
+
+
+
+void
+GenericOutputFile::writeMagicNumberAndVersionField (OPENEXR_IMF_INTERNAL_NAMESPACE::OStream& os,
+ const Header& header)
+{
+ OPENEXR_IMF_INTERNAL_NAMESPACE::Xdr::write <OPENEXR_IMF_INTERNAL_NAMESPACE::StreamIO> (os, MAGIC);
+
+ int version = EXR_VERSION;
+
+ if (header.hasType() && isDeepData(header.type()))
+ {
+ version |= NON_IMAGE_FLAG;
+ }
+ else
+ {
+ // (TODO) we may want to check something else in function signature
+ // instead of hasTileDescription()?
+ if (header.hasTileDescription())
+ version |= TILED_FLAG;
+ }
+
+ if (usesLongNames (header))
+ version |= LONG_NAMES_FLAG;
+
+ OPENEXR_IMF_INTERNAL_NAMESPACE::Xdr::write <OPENEXR_IMF_INTERNAL_NAMESPACE::StreamIO> (os, version);
+}
+
+void
+GenericOutputFile::writeMagicNumberAndVersionField (OPENEXR_IMF_INTERNAL_NAMESPACE::OStream& os,
+ const Header * headers,
+ int parts)
+{
+ OPENEXR_IMF_INTERNAL_NAMESPACE::Xdr::write <OPENEXR_IMF_INTERNAL_NAMESPACE::StreamIO> (os, MAGIC);
+
+ int version = EXR_VERSION;
+
+ if (parts == 1)
+ {
+ if (headers[0].type() == TILEDIMAGE)
+ version |= TILED_FLAG;
+ }
+ else
+ {
+ version |= MULTI_PART_FILE_FLAG;
+ }
+
+ for (int i = 0; i < parts; i++)
+ {
+ if (usesLongNames (headers[i]))
+ version |= LONG_NAMES_FLAG;
+
+ if (headers[i].hasType() && isImage(headers[i].type()) == false)
+ version |= NON_IMAGE_FLAG;
+ }
+
+ OPENEXR_IMF_INTERNAL_NAMESPACE::Xdr::write <OPENEXR_IMF_INTERNAL_NAMESPACE::StreamIO> (os, version);
+}
+
+OPENEXR_IMF_INTERNAL_NAMESPACE_SOURCE_EXIT
--- /dev/null
+///////////////////////////////////////////////////////////////////////////
+//
+// Copyright (c) 2011, Industrial Light & Magic, a division of Lucas
+// Digital Ltd. LLC
+//
+// All rights reserved.
+//
+// Redistribution and use in source and binary forms, with or without
+// modification, are permitted provided that the following conditions are
+// met:
+// * Redistributions of source code must retain the above copyright
+// notice, this list of conditions and the following disclaimer.
+// * Redistributions in binary form must reproduce the above
+// copyright notice, this list of conditions and the following disclaimer
+// in the documentation and/or other materials provided with the
+// distribution.
+// * Neither the name of Industrial Light & Magic nor the names of
+// its contributors may be used to endorse or promote products derived
+// from this software without specific prior written permission.
+//
+// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+//
+///////////////////////////////////////////////////////////////////////////
+
+#ifndef IMFGENERICOUTPUTFILE_H_
+#define IMFGENERICOUTPUTFILE_H_
+
+#include "ImfVersion.h"
+#include "ImfIO.h"
+#include "ImfXdr.h"
+#include "ImfHeader.h"
+#include "ImfNamespace.h"
+#include "ImfExport.h"
+
+OPENEXR_IMF_INTERNAL_NAMESPACE_HEADER_ENTER
+
+
+class GenericOutputFile
+{
+ public:
+ IMF_EXPORT
+ virtual ~GenericOutputFile() {}
+
+ protected:
+ IMF_EXPORT
+ GenericOutputFile() {}
+ IMF_EXPORT
+ void writeMagicNumberAndVersionField (OPENEXR_IMF_INTERNAL_NAMESPACE::OStream& os, const Header& header);
+ IMF_EXPORT
+ void writeMagicNumberAndVersionField (OPENEXR_IMF_INTERNAL_NAMESPACE::OStream& os, const Header * headers, int parts);
+
+};
+
+OPENEXR_IMF_INTERNAL_NAMESPACE_HEADER_EXIT
+
+#endif /* GENERICOUTPUTFILE_H_ */
//
// Copyright (c) 2004, Industrial Light & Magic, a division of Lucas
// Digital Ltd. LLC
-//
+//
// All rights reserved.
-//
+//
// Redistribution and use in source and binary forms, with or without
// modification, are permitted provided that the following conditions are
// met:
// distribution.
// * Neither the name of Industrial Light & Magic nor the names of
// its contributors may be used to endorse or promote products derived
-// from this software without specific prior written permission.
-//
+// from this software without specific prior written permission.
+//
// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
#include <ImfChannelListAttribute.h>
#include <ImfChromaticitiesAttribute.h>
#include <ImfCompressionAttribute.h>
+#include <ImfDeepImageStateAttribute.h>
#include <ImfDoubleAttribute.h>
+#include <ImfDwaCompressor.h>
#include <ImfEnvmapAttribute.h>
#include <ImfFloatAttribute.h>
+#include <ImfFloatVectorAttribute.h>
#include <ImfIntAttribute.h>
#include <ImfKeyCodeAttribute.h>
#include <ImfLineOrderAttribute.h>
#include <ImfTileDescriptionAttribute.h>
#include <ImfTimeCodeAttribute.h>
#include <ImfVecAttribute.h>
+#include <ImfPartType.h>
#include "IlmThreadMutex.h"
#include "Iex.h"
#include <sstream>
#include <stdlib.h>
#include <time.h>
+#include "ImfNamespace.h"
-namespace Imf {
+OPENEXR_IMF_INTERNAL_NAMESPACE_SOURCE_ENTER
using namespace std;
-using Imath::Box2i;
-using Imath::V2i;
-using Imath::V2f;
-using IlmThread::Mutex;
-using IlmThread::Lock;
+using IMATH_NAMESPACE::Box2i;
+using IMATH_NAMESPACE::V2i;
+using IMATH_NAMESPACE::V2f;
+using ILMTHREAD_NAMESPACE::Mutex;
+using ILMTHREAD_NAMESPACE::Lock;
namespace {
void
initialize (Header &header,
- const Box2i &displayWindow,
- const Box2i &dataWindow,
- float pixelAspectRatio,
- const V2f &screenWindowCenter,
- float screenWindowWidth,
- LineOrder lineOrder,
- Compression compression)
+ const Box2i &displayWindow,
+ const Box2i &dataWindow,
+ float pixelAspectRatio,
+ const V2f &screenWindowCenter,
+ float screenWindowWidth,
+ LineOrder lineOrder,
+ Compression compression)
{
header.insert ("displayWindow", Box2iAttribute (displayWindow));
header.insert ("dataWindow", Box2iAttribute (dataWindow));
header.insert ("channels", ChannelListAttribute ());
}
-
-bool
-usesLongNames (const Header &header)
-{
- //
- // If an OpenEXR file contains any attribute names, attribute type names
- // or channel names longer than 31 characters, then the file cannot be
- // read by older versions of the IlmImf library (up to OpenEXR 1.6.1).
- // Before writing the file header, we check if the header contains
- // any names longer than 31 characters; if it does, then we set the
- // LONG_NAMES_FLAG in the file version number. Older versions of the
- // IlmImf library will refuse to read files that have the LONG_NAMES_FLAG
- // set. Without the flag, older versions of the library would mis-
- // interpret the file as broken.
- //
-
- for (Header::ConstIterator i = header.begin();
- i != header.end();
- ++i)
- {
- if (strlen (i.name()) >= 32 || strlen (i.attribute().typeName()) >= 32)
- return true;
- }
-
- const ChannelList &channels = header.channels();
-
- for (ChannelList::ConstIterator i = channels.begin();
- i != channels.end();
- ++i)
- {
- if (strlen (i.name()) >= 32)
- return true;
- }
-
- return false;
-}
-
template <size_t N>
void checkIsNullTerminated (const char (&str)[N], const char *what)
{
- for (int i = 0; i < N; ++i) {
- if (str[i] == '\0')
- return;
- }
- std::stringstream s;
- s << "Invalid " << what << ": it is more than " << (N - 1)
- << " characters long.";
- throw Iex::InputExc(s);
+ for (size_t i = 0; i < N; ++i) {
+ if (str[i] == '\0')
+ return;
+ }
+ std::stringstream s;
+ s << "Invalid " << what << ": it is more than " << (N - 1)
+ << " characters long.";
+ throw IEX_NAMESPACE::InputExc(s);
}
} // namespace
Header::Header (int width,
- int height,
- float pixelAspectRatio,
- const V2f &screenWindowCenter,
- float screenWindowWidth,
- LineOrder lineOrder,
- Compression compression)
+ int height,
+ float pixelAspectRatio,
+ const V2f &screenWindowCenter,
+ float screenWindowWidth,
+ LineOrder lineOrder,
+ Compression compression)
:
_map()
{
Box2i displayWindow (V2i (0, 0), V2i (width - 1, height - 1));
initialize (*this,
- displayWindow,
- displayWindow,
- pixelAspectRatio,
- screenWindowCenter,
- screenWindowWidth,
- lineOrder,
- compression);
+ displayWindow,
+ displayWindow,
+ pixelAspectRatio,
+ screenWindowCenter,
+ screenWindowWidth,
+ lineOrder,
+ compression);
}
Header::Header (int width,
- int height,
- const Box2i &dataWindow,
- float pixelAspectRatio,
- const V2f &screenWindowCenter,
- float screenWindowWidth,
- LineOrder lineOrder,
- Compression compression)
+ int height,
+ const Box2i &dataWindow,
+ float pixelAspectRatio,
+ const V2f &screenWindowCenter,
+ float screenWindowWidth,
+ LineOrder lineOrder,
+ Compression compression)
:
_map()
{
Box2i displayWindow (V2i (0, 0), V2i (width - 1, height - 1));
initialize (*this,
- displayWindow,
- dataWindow,
- pixelAspectRatio,
- screenWindowCenter,
- screenWindowWidth,
- lineOrder,
- compression);
+ displayWindow,
+ dataWindow,
+ pixelAspectRatio,
+ screenWindowCenter,
+ screenWindowWidth,
+ lineOrder,
+ compression);
}
Header::Header (const Box2i &displayWindow,
- const Box2i &dataWindow,
- float pixelAspectRatio,
- const V2f &screenWindowCenter,
- float screenWindowWidth,
- LineOrder lineOrder,
- Compression compression)
+ const Box2i &dataWindow,
+ float pixelAspectRatio,
+ const V2f &screenWindowCenter,
+ float screenWindowWidth,
+ LineOrder lineOrder,
+ Compression compression)
:
_map()
{
staticInitialize();
initialize (*this,
- displayWindow,
- dataWindow,
- pixelAspectRatio,
- screenWindowCenter,
- screenWindowWidth,
- lineOrder,
- compression);
+ displayWindow,
+ dataWindow,
+ pixelAspectRatio,
+ screenWindowCenter,
+ screenWindowWidth,
+ lineOrder,
+ compression);
}
Header::Header (const Header &other): _map()
{
for (AttributeMap::const_iterator i = other._map.begin();
- i != other._map.end();
- ++i)
+ i != other._map.end();
+ ++i)
{
- insert (*i->first, *i->second);
+ insert (*i->first, *i->second);
}
}
Header::~Header ()
{
for (AttributeMap::iterator i = _map.begin();
- i != _map.end();
- ++i)
+ i != _map.end();
+ ++i)
{
- delete i->second;
+ delete i->second;
}
}
-Header &
+Header &
Header::operator = (const Header &other)
{
if (this != &other)
{
- for (AttributeMap::iterator i = _map.begin();
- i != _map.end();
- ++i)
- {
- delete i->second;
+ for (AttributeMap::iterator i = _map.begin();
+ i != _map.end();
+ ++i)
+ {
+ delete i->second;
+ }
+
+ _map.erase (_map.begin(), _map.end());
+
+ for (AttributeMap::const_iterator i = other._map.begin();
+ i != other._map.end();
+ ++i)
+ {
+ insert (*i->first, *i->second);
+ }
}
- _map.erase (_map.begin(), _map.end());
+ return *this;
+}
- for (AttributeMap::const_iterator i = other._map.begin();
- i != other._map.end();
- ++i)
- {
- insert (*i->first, *i->second);
- }
- }
- return *this;
+void
+Header::erase (const char name[])
+{
+ if (name[0] == 0)
+ THROW (IEX_NAMESPACE::ArgExc, "Image attribute name cannot be an empty string.");
+
+
+ AttributeMap::iterator i = _map.find (name);
+ if (i != _map.end())
+ _map.erase (i);
+
}
void
+Header::erase (const string &name)
+{
+ erase (name.c_str());
+}
+
+
+void
Header::insert (const char name[], const Attribute &attribute)
{
if (name[0] == 0)
- THROW (Iex::ArgExc, "Image attribute name cannot be an empty string.");
+ THROW (IEX_NAMESPACE::ArgExc, "Image attribute name cannot be an empty string.");
AttributeMap::iterator i = _map.find (name);
if (i == _map.end())
{
- Attribute *tmp = attribute.copy();
-
- try
- {
- _map[name] = tmp;
- }
- catch (...)
- {
- delete tmp;
- throw;
- }
+ Attribute *tmp = attribute.copy();
+
+ try
+ {
+ _map[name] = tmp;
+ }
+ catch (...)
+ {
+ delete tmp;
+ throw;
+ }
}
else
{
- if (strcmp (i->second->typeName(), attribute.typeName()))
- THROW (Iex::TypeExc, "Cannot assign a value of "
- "type \"" << attribute.typeName() << "\" "
- "to image attribute \"" << name << "\" of "
- "type \"" << i->second->typeName() << "\".");
-
- Attribute *tmp = attribute.copy();
- delete i->second;
- i->second = tmp;
+ if (strcmp (i->second->typeName(), attribute.typeName()))
+ THROW (IEX_NAMESPACE::TypeExc, "Cannot assign a value of "
+ "type \"" << attribute.typeName() << "\" "
+ "to image attribute \"" << name << "\" of "
+ "type \"" << i->second->typeName() << "\".");
+
+ Attribute *tmp = attribute.copy();
+ delete i->second;
+ i->second = tmp;
}
}
}
-Attribute &
+Attribute &
Header::operator [] (const char name[])
{
AttributeMap::iterator i = _map.find (name);
if (i == _map.end())
- THROW (Iex::ArgExc, "Cannot find image attribute \"" << name << "\".");
+ THROW (IEX_NAMESPACE::ArgExc, "Cannot find image attribute \"" << name << "\".");
return *i->second;
}
-const Attribute &
+const Attribute &
Header::operator [] (const char name[]) const
{
AttributeMap::const_iterator i = _map.find (name);
if (i == _map.end())
- THROW (Iex::ArgExc, "Cannot find image attribute \"" << name << "\".");
+ THROW (IEX_NAMESPACE::ArgExc, "Cannot find image attribute \"" << name << "\".");
return *i->second;
}
-Attribute &
+Attribute &
Header::operator [] (const string &name)
{
return this->operator[] (name.c_str());
}
-const Attribute &
+const Attribute &
Header::operator [] (const string &name) const
{
return this->operator[] (name.c_str());
}
-Imath::Box2i &
+IMATH_NAMESPACE::Box2i &
Header::displayWindow ()
{
return static_cast <Box2iAttribute &>
- ((*this)["displayWindow"]).value();
+ ((*this)["displayWindow"]).value();
}
-const Imath::Box2i &
+const IMATH_NAMESPACE::Box2i &
Header::displayWindow () const
{
return static_cast <const Box2iAttribute &>
- ((*this)["displayWindow"]).value();
+ ((*this)["displayWindow"]).value();
}
-Imath::Box2i &
+IMATH_NAMESPACE::Box2i &
Header::dataWindow ()
{
return static_cast <Box2iAttribute &>
- ((*this)["dataWindow"]).value();
+ ((*this)["dataWindow"]).value();
}
-const Imath::Box2i &
+const IMATH_NAMESPACE::Box2i &
Header::dataWindow () const
{
return static_cast <const Box2iAttribute &>
- ((*this)["dataWindow"]).value();
+ ((*this)["dataWindow"]).value();
}
-float &
+float &
Header::pixelAspectRatio ()
{
return static_cast <FloatAttribute &>
- ((*this)["pixelAspectRatio"]).value();
+ ((*this)["pixelAspectRatio"]).value();
}
-const float &
+const float &
Header::pixelAspectRatio () const
{
return static_cast <const FloatAttribute &>
- ((*this)["pixelAspectRatio"]).value();
+ ((*this)["pixelAspectRatio"]).value();
}
-Imath::V2f &
+IMATH_NAMESPACE::V2f &
Header::screenWindowCenter ()
{
return static_cast <V2fAttribute &>
- ((*this)["screenWindowCenter"]).value();
+ ((*this)["screenWindowCenter"]).value();
}
-const Imath::V2f &
+const IMATH_NAMESPACE::V2f &
Header::screenWindowCenter () const
{
return static_cast <const V2fAttribute &>
- ((*this)["screenWindowCenter"]).value();
+ ((*this)["screenWindowCenter"]).value();
}
-float &
+float &
Header::screenWindowWidth ()
{
return static_cast <FloatAttribute &>
- ((*this)["screenWindowWidth"]).value();
+ ((*this)["screenWindowWidth"]).value();
}
-const float &
+const float &
Header::screenWindowWidth () const
{
return static_cast <const FloatAttribute &>
- ((*this)["screenWindowWidth"]).value();
+ ((*this)["screenWindowWidth"]).value();
}
-ChannelList &
+ChannelList &
Header::channels ()
{
return static_cast <ChannelListAttribute &>
- ((*this)["channels"]).value();
+ ((*this)["channels"]).value();
}
-const ChannelList &
+const ChannelList &
Header::channels () const
{
return static_cast <const ChannelListAttribute &>
- ((*this)["channels"]).value();
+ ((*this)["channels"]).value();
}
Header::lineOrder ()
{
return static_cast <LineOrderAttribute &>
- ((*this)["lineOrder"]).value();
+ ((*this)["lineOrder"]).value();
}
Header::lineOrder () const
{
return static_cast <const LineOrderAttribute &>
- ((*this)["lineOrder"]).value();
+ ((*this)["lineOrder"]).value();
}
Header::compression ()
{
return static_cast <CompressionAttribute &>
- ((*this)["compression"]).value();
+ ((*this)["compression"]).value();
}
Header::compression () const
{
return static_cast <const CompressionAttribute &>
- ((*this)["compression"]).value();
+ ((*this)["compression"]).value();
+}
+
+
+void
+Header::setName(const string& name)
+{
+ insert ("name", StringAttribute (name));
+}
+
+
+bool
+Header::hasName() const
+{
+ return findTypedAttribute <StringAttribute> ("name") != 0;
+}
+
+
+string &
+Header::name()
+{
+ return typedAttribute <StringAttribute> ("name").value();
+}
+
+
+const string &
+Header::name() const
+{
+ return typedAttribute <StringAttribute> ("name").value();
+}
+
+
+void
+Header::setType(const string& type)
+{
+ if (isSupportedType(type) == false)
+ {
+ throw IEX_NAMESPACE::ArgExc (type + "is not a supported image type." +
+ "The following are supported: " +
+ SCANLINEIMAGE + ", " +
+ TILEDIMAGE + ", " +
+ DEEPSCANLINE + " or " +
+ DEEPTILE + ".");
+ }
+
+ insert ("type", StringAttribute (type));
+
+ // (TODO) Should we do it here?
+ if (isDeepData(type) && hasVersion() == false)
+ {
+ setVersion(1);
+ }
+}
+
+
+bool
+Header::hasType() const
+{
+ return findTypedAttribute <StringAttribute> ("type") != 0;
+}
+
+
+string &
+Header::type()
+{
+ return typedAttribute <StringAttribute> ("type").value();
+}
+
+
+const string &
+Header::type() const
+{
+ return typedAttribute <StringAttribute> ("type").value();
}
void
+Header::setView(const string& view)
+{
+ insert ("view", StringAttribute (view));
+}
+
+
+bool
+Header::hasView() const
+{
+ return findTypedAttribute <StringAttribute> ("view") != 0;
+}
+
+
+string &
+Header::view()
+{
+ return typedAttribute <StringAttribute> ("view").value();
+}
+
+
+const string &
+Header::view() const
+{
+ return typedAttribute <StringAttribute> ("view").value();
+}
+
+
+void
+Header::setVersion(const int version)
+{
+ if (version != 1)
+ {
+ throw IEX_NAMESPACE::ArgExc ("We can only process version 1");
+ }
+
+ insert ("version", IntAttribute (version));
+}
+
+
+bool
+Header::hasVersion() const
+{
+ return findTypedAttribute <IntAttribute> ("version") != 0;
+}
+
+
+int &
+Header::version()
+{
+ return typedAttribute <IntAttribute> ("version").value();
+}
+
+
+const int &
+Header::version() const
+{
+ return typedAttribute <IntAttribute> ("version").value();
+}
+
+void
+Header::setChunkCount(int chunks)
+{
+ insert("chunkCount",IntAttribute(chunks));
+}
+
+bool
+Header::hasChunkCount() const
+{
+ return findTypedAttribute<IntAttribute>("chunkCount") != 0;
+}
+
+int&
+Header::chunkCount()
+{
+ return typedAttribute <IntAttribute> ("chunkCount").value();
+}
+
+const int&
+Header::chunkCount() const
+{
+ return typedAttribute <IntAttribute> ("chunkCount").value();
+}
+
+void
Header::setTileDescription(const TileDescription& td)
{
insert ("tiles", TileDescriptionAttribute (td));
return typedAttribute <TileDescriptionAttribute> ("tiles").value();
}
-void
+void
Header::setPreviewImage (const PreviewImage &pi)
{
insert ("preview", PreviewImageAttribute (pi));
}
-bool
+bool
Header::hasPreviewImage () const
{
return findTypedAttribute <PreviewImageAttribute> ("preview") != 0;
}
-void
-Header::sanityCheck (bool isTiled) const
+void
+Header::sanityCheck (bool isTiled, bool isMultipartFile) const
{
//
// The display window and the data window must each
const Box2i &displayWindow = this->displayWindow();
if (displayWindow.min.x > displayWindow.max.x ||
- displayWindow.min.y > displayWindow.max.y ||
- displayWindow.min.x <= -(INT_MAX / 2) ||
- displayWindow.min.y <= -(INT_MAX / 2) ||
- displayWindow.max.x >= (INT_MAX / 2) ||
- displayWindow.max.y >= (INT_MAX / 2))
+ displayWindow.min.y > displayWindow.max.y ||
+ displayWindow.min.x <= -(INT_MAX / 2) ||
+ displayWindow.min.y <= -(INT_MAX / 2) ||
+ displayWindow.max.x >= (INT_MAX / 2) ||
+ displayWindow.max.y >= (INT_MAX / 2))
{
- throw Iex::ArgExc ("Invalid display window in image header.");
+ throw IEX_NAMESPACE::ArgExc ("Invalid display window in image header.");
}
const Box2i &dataWindow = this->dataWindow();
if (dataWindow.min.x > dataWindow.max.x ||
- dataWindow.min.y > dataWindow.max.y ||
- dataWindow.min.x <= -(INT_MAX / 2) ||
- dataWindow.min.y <= -(INT_MAX / 2) ||
- dataWindow.max.x >= (INT_MAX / 2) ||
- dataWindow.max.y >= (INT_MAX / 2))
+ dataWindow.min.y > dataWindow.max.y ||
+ dataWindow.min.x <= -(INT_MAX / 2) ||
+ dataWindow.min.y <= -(INT_MAX / 2) ||
+ dataWindow.max.x >= (INT_MAX / 2) ||
+ dataWindow.max.y >= (INT_MAX / 2))
{
- throw Iex::ArgExc ("Invalid data window in image header.");
+ throw IEX_NAMESPACE::ArgExc ("Invalid data window in image header.");
}
if (maxImageWidth > 0 &&
- maxImageWidth < dataWindow.max.x - dataWindow.min.x + 1)
+ maxImageWidth < (dataWindow.max.x - dataWindow.min.x + 1))
{
- THROW (Iex::ArgExc, "The width of the data window exceeds the "
- "maximum width of " << maxImageWidth << "pixels.");
+ THROW (IEX_NAMESPACE::ArgExc, "The width of the data window exceeds the "
+ "maximum width of " << maxImageWidth << "pixels.");
}
if (maxImageHeight > 0 &&
- maxImageHeight < dataWindow.max.y - dataWindow.min.y + 1)
+ maxImageHeight < dataWindow.max.y - dataWindow.min.y + 1)
{
- THROW (Iex::ArgExc, "The width of the data window exceeds the "
- "maximum width of " << maxImageHeight << "pixels.");
+ THROW (IEX_NAMESPACE::ArgExc, "The width of the data window exceeds the "
+ "maximum width of " << maxImageHeight << "pixels.");
}
+ // chunk table must be smaller than the maximum image area
+ // (only reachable for unknown types or damaged files: will have thrown earlier
+ // for regular image types)
+ if( maxImageHeight>0 && maxImageWidth>0 &&
+ hasChunkCount() && chunkCount()>Int64(maxImageWidth)*Int64(maxImageHeight))
+ {
+ THROW (IEX_NAMESPACE::ArgExc, "chunkCount exceeds maximum area of "
+ << Int64(maxImageWidth)*Int64(maxImageHeight) << " pixels." );
+
+ }
+
+
//
// The pixel aspect ratio must be greater than 0.
// In applications, numbers like the the display or
const float MAX_PIXEL_ASPECT_RATIO = 1e+6f;
if (pixelAspectRatio < MIN_PIXEL_ASPECT_RATIO ||
- pixelAspectRatio > MAX_PIXEL_ASPECT_RATIO)
+ pixelAspectRatio > MAX_PIXEL_ASPECT_RATIO)
{
- throw Iex::ArgExc ("Invalid pixel aspect ratio in image header.");
+ throw IEX_NAMESPACE::ArgExc ("Invalid pixel aspect ratio in image header.");
}
//
float screenWindowWidth = this->screenWindowWidth();
if (screenWindowWidth < 0)
- throw Iex::ArgExc ("Invalid screen window width in image header.");
+ throw IEX_NAMESPACE::ArgExc ("Invalid screen window width in image header.");
//
- // If the file is tiled, verify that the tile description has resonable
- // values and check to see if the lineOrder is one of the predefined 3.
- // If the file is not tiled, then the lineOrder can only be INCREASING_Y
- // or DECREASING_Y.
+ // If the file has multiple parts, verify that each header has attribute
+ // name and type.
+ // (TODO) We may want to check more stuff here.
//
- LineOrder lineOrder = this->lineOrder();
-
- if (isTiled)
+ if (isMultipartFile)
{
- if (!hasTileDescription())
- {
- throw Iex::ArgExc ("Tiled image has no tile "
- "description attribute.");
- }
-
- const TileDescription &tileDesc = tileDescription();
+ if (!hasName())
+ {
+ throw IEX_NAMESPACE::ArgExc ("Headers in a multipart file should"
+ " have name attribute.");
+ }
- if (tileDesc.xSize <= 0 || tileDesc.ySize <= 0)
- throw Iex::ArgExc ("Invalid tile size in image header.");
+ if (!hasType())
+ {
+ throw IEX_NAMESPACE::ArgExc ("Headers in a multipart file should"
+ " have type attribute.");
+ }
- if (maxTileWidth > 0 &&
- maxTileWidth < tileDesc.xSize)
- {
- THROW (Iex::ArgExc, "The width of the tiles exceeds the maximum "
- "width of " << maxTileWidth << "pixels.");
}
-
- if (maxTileHeight > 0 &&
- maxTileHeight < tileDesc.ySize)
+
+ const std::string & part_type=hasType() ? type() : "";
+
+ if(part_type!="" && !isSupportedType(part_type))
{
- THROW (Iex::ArgExc, "The width of the tiles exceeds the maximum "
- "width of " << maxTileHeight << "pixels.");
+ //
+ // skip remaining sanity checks with unsupported types - they may not hold
+ //
+ return;
}
+
+
+ //
+ // If the file is tiled, verify that the tile description has reasonable
+ // values and check to see if the lineOrder is one of the predefined 3.
+ // If the file is not tiled, then the lineOrder can only be INCREASING_Y
+ // or DECREASING_Y.
+ //
- if (tileDesc.mode != ONE_LEVEL &&
- tileDesc.mode != MIPMAP_LEVELS &&
- tileDesc.mode != RIPMAP_LEVELS)
- throw Iex::ArgExc ("Invalid level mode in image header.");
-
- if (tileDesc.roundingMode != ROUND_UP &&
- tileDesc.roundingMode != ROUND_DOWN)
- throw Iex::ArgExc ("Invalid level rounding mode in image header.");
+ LineOrder lineOrder = this->lineOrder();
- if (lineOrder != INCREASING_Y &&
- lineOrder != DECREASING_Y &&
- lineOrder != RANDOM_Y)
- throw Iex::ArgExc ("Invalid line order in image header.");
+ if (isTiled)
+ {
+ if (!hasTileDescription())
+ {
+ throw IEX_NAMESPACE::ArgExc ("Tiled image has no tile "
+ "description attribute.");
+ }
+
+ const TileDescription &tileDesc = tileDescription();
+
+ if (tileDesc.xSize <= 0 || tileDesc.ySize <= 0)
+ throw IEX_NAMESPACE::ArgExc ("Invalid tile size in image header.");
+
+ if (maxTileWidth > 0 &&
+ maxTileWidth < int(tileDesc.xSize))
+ {
+ THROW (IEX_NAMESPACE::ArgExc, "The width of the tiles exceeds the maximum "
+ "width of " << maxTileWidth << "pixels.");
+ }
+
+ if (maxTileHeight > 0 &&
+ maxTileHeight < int(tileDesc.ySize))
+ {
+ THROW (IEX_NAMESPACE::ArgExc, "The width of the tiles exceeds the maximum "
+ "width of " << maxTileHeight << "pixels.");
+ }
+
+ if (tileDesc.mode != ONE_LEVEL &&
+ tileDesc.mode != MIPMAP_LEVELS &&
+ tileDesc.mode != RIPMAP_LEVELS)
+ throw IEX_NAMESPACE::ArgExc ("Invalid level mode in image header.");
+
+ if (tileDesc.roundingMode != ROUND_UP &&
+ tileDesc.roundingMode != ROUND_DOWN)
+ throw IEX_NAMESPACE::ArgExc ("Invalid level rounding mode in image header.");
+
+ if (lineOrder != INCREASING_Y &&
+ lineOrder != DECREASING_Y &&
+ lineOrder != RANDOM_Y)
+ throw IEX_NAMESPACE::ArgExc ("Invalid line order in image header.");
}
else
{
- if (lineOrder != INCREASING_Y &&
- lineOrder != DECREASING_Y)
- throw Iex::ArgExc ("Invalid line order in image header.");
+ if (lineOrder != INCREASING_Y &&
+ lineOrder != DECREASING_Y)
+ throw IEX_NAMESPACE::ArgExc ("Invalid line order in image header.");
+
+
}
//
//
if (!isValidCompression (this->compression()))
- throw Iex::ArgExc ("Unknown compression type in image header.");
+ throw IEX_NAMESPACE::ArgExc ("Unknown compression type in image header.");
+
+ if(isDeepData(part_type))
+ {
+ if (!isValidDeepCompression (this->compression()))
+ throw IEX_NAMESPACE::ArgExc ("Compression type in header not valid for deep data");
+ }
//
// Check the channel list:
//
const ChannelList &channels = this->channels();
-
+
if (isTiled)
{
- for (ChannelList::ConstIterator i = channels.begin();
- i != channels.end();
- ++i)
- {
- if (i.channel().type != UINT &&
- i.channel().type != HALF &&
- i.channel().type != FLOAT)
- {
- THROW (Iex::ArgExc, "Pixel type of \"" << i.name() << "\" "
- "image channel is invalid.");
- }
-
- if (i.channel().xSampling != 1)
- {
- THROW (Iex::ArgExc, "The x subsampling factor for the "
- "\"" << i.name() << "\" channel "
- "is not 1.");
- }
-
- if (i.channel().ySampling != 1)
- {
- THROW (Iex::ArgExc, "The y subsampling factor for the "
- "\"" << i.name() << "\" channel "
- "is not 1.");
- }
- }
+ for (ChannelList::ConstIterator i = channels.begin();
+ i != channels.end();
+ ++i)
+ {
+ if (i.channel().type != OPENEXR_IMF_INTERNAL_NAMESPACE::UINT &&
+ i.channel().type != OPENEXR_IMF_INTERNAL_NAMESPACE::HALF &&
+ i.channel().type != OPENEXR_IMF_INTERNAL_NAMESPACE::FLOAT)
+ {
+ THROW (IEX_NAMESPACE::ArgExc, "Pixel type of \"" << i.name() << "\" "
+ "image channel is invalid.");
+ }
+
+ if (i.channel().xSampling != 1)
+ {
+ THROW (IEX_NAMESPACE::ArgExc, "The x subsampling factor for the "
+ "\"" << i.name() << "\" channel "
+ "is not 1.");
+ }
+
+ if (i.channel().ySampling != 1)
+ {
+ THROW (IEX_NAMESPACE::ArgExc, "The y subsampling factor for the "
+ "\"" << i.name() << "\" channel "
+ "is not 1.");
+ }
+ }
}
else
{
- for (ChannelList::ConstIterator i = channels.begin();
- i != channels.end();
- ++i)
- {
- if (i.channel().type != UINT &&
- i.channel().type != HALF &&
- i.channel().type != FLOAT)
- {
- THROW (Iex::ArgExc, "Pixel type of \"" << i.name() << "\" "
- "image channel is invalid.");
- }
-
- if (i.channel().xSampling < 1)
- {
- THROW (Iex::ArgExc, "The x subsampling factor for the "
- "\"" << i.name() << "\" channel "
- "is invalid.");
- }
-
- if (i.channel().ySampling < 1)
- {
- THROW (Iex::ArgExc, "The y subsampling factor for the "
- "\"" << i.name() << "\" channel "
- "is invalid.");
- }
-
- if (dataWindow.min.x % i.channel().xSampling)
- {
- THROW (Iex::ArgExc, "The minimum x coordinate of the "
- "image's data window is not a multiple "
- "of the x subsampling factor of "
- "the \"" << i.name() << "\" channel.");
- }
-
- if (dataWindow.min.y % i.channel().ySampling)
- {
- THROW (Iex::ArgExc, "The minimum y coordinate of the "
- "image's data window is not a multiple "
- "of the y subsampling factor of "
- "the \"" << i.name() << "\" channel.");
- }
-
- if ((dataWindow.max.x - dataWindow.min.x + 1) %
- i.channel().xSampling)
- {
- THROW (Iex::ArgExc, "Number of pixels per row in the "
- "image's data window is not a multiple "
- "of the x subsampling factor of "
- "the \"" << i.name() << "\" channel.");
- }
-
- if ((dataWindow.max.y - dataWindow.min.y + 1) %
- i.channel().ySampling)
- {
- THROW (Iex::ArgExc, "Number of pixels per column in the "
- "image's data window is not a multiple "
- "of the y subsampling factor of "
- "the \"" << i.name() << "\" channel.");
- }
- }
+ for (ChannelList::ConstIterator i = channels.begin();
+ i != channels.end();
+ ++i)
+ {
+ if (i.channel().type != OPENEXR_IMF_INTERNAL_NAMESPACE::UINT &&
+ i.channel().type != OPENEXR_IMF_INTERNAL_NAMESPACE::HALF &&
+ i.channel().type != OPENEXR_IMF_INTERNAL_NAMESPACE::FLOAT)
+ {
+ THROW (IEX_NAMESPACE::ArgExc, "Pixel type of \"" << i.name() << "\" "
+ "image channel is invalid.");
+ }
+
+ if (i.channel().xSampling < 1)
+ {
+ THROW (IEX_NAMESPACE::ArgExc, "The x subsampling factor for the "
+ "\"" << i.name() << "\" channel "
+ "is invalid.");
+ }
+
+ if (i.channel().ySampling < 1)
+ {
+ THROW (IEX_NAMESPACE::ArgExc, "The y subsampling factor for the "
+ "\"" << i.name() << "\" channel "
+ "is invalid.");
+ }
+
+ if (dataWindow.min.x % i.channel().xSampling)
+ {
+ THROW (IEX_NAMESPACE::ArgExc, "The minimum x coordinate of the "
+ "image's data window is not a multiple "
+ "of the x subsampling factor of "
+ "the \"" << i.name() << "\" channel.");
+ }
+
+ if (dataWindow.min.y % i.channel().ySampling)
+ {
+ THROW (IEX_NAMESPACE::ArgExc, "The minimum y coordinate of the "
+ "image's data window is not a multiple "
+ "of the y subsampling factor of "
+ "the \"" << i.name() << "\" channel.");
+ }
+
+ if ((dataWindow.max.x - dataWindow.min.x + 1) %
+ i.channel().xSampling)
+ {
+ THROW (IEX_NAMESPACE::ArgExc, "Number of pixels per row in the "
+ "image's data window is not a multiple "
+ "of the x subsampling factor of "
+ "the \"" << i.name() << "\" channel.");
+ }
+
+ if ((dataWindow.max.y - dataWindow.min.y + 1) %
+ i.channel().ySampling)
+ {
+ THROW (IEX_NAMESPACE::ArgExc, "Number of pixels per column in the "
+ "image's data window is not a multiple "
+ "of the y subsampling factor of "
+ "the \"" << i.name() << "\" channel.");
+ }
+ }
}
}
-void
+void
Header::setMaxImageSize (int maxWidth, int maxHeight)
{
maxImageWidth = maxWidth;
}
-void
+void
Header::setMaxTileSize (int maxWidth, int maxHeight)
{
maxTileWidth = maxWidth;
}
+bool
+Header::readsNothing()
+{
+ return _readsNothing;
+}
+
+
Int64
-Header::writeTo (OStream &os, bool isTiled) const
+Header::writeTo (OPENEXR_IMF_INTERNAL_NAMESPACE::OStream &os, bool isTiled) const
{
//
// Write a "magic number" to identify the file as an image file.
// Write the current file format version number.
//
- Xdr::write <StreamIO> (os, MAGIC);
-
int version = EXR_VERSION;
- if (isTiled)
- version |= TILED_FLAG;
-
- if (usesLongNames (*this))
- version |= LONG_NAMES_FLAG;
-
- Xdr::write <StreamIO> (os, version);
-
//
// Write all attributes. If we have a preview image attribute,
// keep track of its position in the file.
Int64 previewPosition = 0;
const Attribute *preview =
- findTypedAttribute <PreviewImageAttribute> ("preview");
+ findTypedAttribute <PreviewImageAttribute> ("preview");
for (ConstIterator i = begin(); i != end(); ++i)
{
- //
- // Write the attribute's name and type.
- //
+ //
+ // Write the attribute's name and type.
+ //
- Xdr::write <StreamIO> (os, i.name());
- Xdr::write <StreamIO> (os, i.attribute().typeName());
+ OPENEXR_IMF_INTERNAL_NAMESPACE::Xdr::write <OPENEXR_IMF_INTERNAL_NAMESPACE::StreamIO> (os, i.name());
+ OPENEXR_IMF_INTERNAL_NAMESPACE::Xdr::write <OPENEXR_IMF_INTERNAL_NAMESPACE::StreamIO> (os, i.attribute().typeName());
- //
- // Write the size of the attribute value,
- // and the value itself.
- //
+ //
+ // Write the size of the attribute value,
+ // and the value itself.
+ //
- StdOSStream oss;
- i.attribute().writeValueTo (oss, version);
+ StdOSStream oss;
+ i.attribute().writeValueTo (oss, version);
- std::string s = oss.str();
- Xdr::write <StreamIO> (os, (int) s.length());
+ std::string s = oss.str();
+ OPENEXR_IMF_INTERNAL_NAMESPACE::Xdr::write <OPENEXR_IMF_INTERNAL_NAMESPACE::StreamIO> (os, (int) s.length());
- if (&i.attribute() == preview)
- previewPosition = os.tellp();
+ if (&i.attribute() == preview)
+ previewPosition = os.tellp();
- os.write (s.data(), s.length());
+ os.write (s.data(), int(s.length()));
}
//
// Write zero-length attribute name to mark the end of the header.
//
- Xdr::write <StreamIO> (os, "");
+ OPENEXR_IMF_INTERNAL_NAMESPACE::Xdr::write <OPENEXR_IMF_INTERNAL_NAMESPACE::StreamIO> (os, "");
return previewPosition;
}
void
-Header::readFrom (IStream &is, int &version)
+Header::readFrom (OPENEXR_IMF_INTERNAL_NAMESPACE::IStream &is, int &version)
{
//
- // Read the magic number and the file format version number.
- // Then check if we can read the rest of this file.
- //
-
- int magic;
-
- Xdr::read <StreamIO> (is, magic);
- Xdr::read <StreamIO> (is, version);
-
- if (magic != MAGIC)
- {
- throw Iex::InputExc ("File is not an image file.");
- }
-
- if (getVersion (version) != EXR_VERSION)
- {
- THROW (Iex::InputExc, "Cannot read "
- "version " << getVersion (version) << " "
- "image files. Current file format version "
- "is " << EXR_VERSION << ".");
- }
-
- if (!supportsFlags (getFlags (version)))
- {
- THROW (Iex::InputExc, "The file format version number's flag field "
- "contains unrecognized flags.");
- }
-
- //
// Read all attributes.
//
- while (true)
- {
- //
- // Read the name of the attribute.
- // A zero-length attribute name indicates the end of the header.
- //
-
- char name[Name::SIZE];
- Xdr::read <StreamIO> (is, Name::MAX_LENGTH, name);
-
- if (name[0] == 0)
- break;
-
- checkIsNullTerminated (name, "attribute name");
-
- //
- // Read the attribute type and the size of the attribute value.
- //
-
- char typeName[Name::SIZE];
- int size;
-
- Xdr::read <StreamIO> (is, Name::MAX_LENGTH, typeName);
- checkIsNullTerminated (typeName, "attribute type name");
- Xdr::read <StreamIO> (is, size);
-
- AttributeMap::iterator i = _map.find (name);
-
- if (i != _map.end())
- {
- //
- // The attribute already exists (for example,
- // because it is a predefined attribute).
- // Read the attribute's new value from the file.
- //
-
- if (strncmp (i->second->typeName(), typeName, sizeof (typeName)))
- THROW (Iex::InputExc, "Unexpected type for image attribute "
- "\"" << name << "\".");
+ int attrCount = 0;
- i->second->readValueFrom (is, size, version);
- }
- else
+ while (true)
{
- //
- // The new attribute does not exist yet.
- // If the attribute type is of a known type,
- // read the attribute value. If the attribute
- // is of an unknown type, read its value and
- // store it as an OpaqueAttribute.
- //
-
- Attribute *attr;
-
- if (Attribute::knownType (typeName))
- attr = Attribute::newAttribute (typeName);
- else
- attr = new OpaqueAttribute (typeName);
-
- try
- {
- attr->readValueFrom (is, size, version);
- _map[name] = attr;
- }
- catch (...)
- {
- delete attr;
- throw;
- }
- }
+ //
+ // Read the name of the attribute.
+ // A zero-length attribute name indicates the end of the header.
+ //
+
+ char name[Name::SIZE];
+ OPENEXR_IMF_INTERNAL_NAMESPACE::Xdr::read <OPENEXR_IMF_INTERNAL_NAMESPACE::StreamIO> (is, Name::MAX_LENGTH, name);
+
+ if (name[0] == 0)
+ {
+ if (attrCount == 0) _readsNothing = true;
+ else _readsNothing = false;
+ break;
+ }
+
+ attrCount++;
+
+ checkIsNullTerminated (name, "attribute name");
+
+ //
+ // Read the attribute type and the size of the attribute value.
+ //
+
+ char typeName[Name::SIZE];
+ int size;
+
+ OPENEXR_IMF_INTERNAL_NAMESPACE::Xdr::read <OPENEXR_IMF_INTERNAL_NAMESPACE::StreamIO> (is, Name::MAX_LENGTH, typeName);
+ checkIsNullTerminated (typeName, "attribute type name");
+ OPENEXR_IMF_INTERNAL_NAMESPACE::Xdr::read <OPENEXR_IMF_INTERNAL_NAMESPACE::StreamIO> (is, size);
+
+ AttributeMap::iterator i = _map.find (name);
+
+ if (i != _map.end())
+ {
+ //
+ // The attribute already exists (for example,
+ // because it is a predefined attribute).
+ // Read the attribute's new value from the file.
+ //
+
+ if (strncmp (i->second->typeName(), typeName, sizeof (typeName)))
+ THROW (IEX_NAMESPACE::InputExc, "Unexpected type for image attribute "
+ "\"" << name << "\".");
+
+ i->second->readValueFrom (is, size, version);
+ }
+ else
+ {
+ //
+ // The new attribute does not exist yet.
+ // If the attribute type is of a known type,
+ // read the attribute value. If the attribute
+ // is of an unknown type, read its value and
+ // store it as an OpaqueAttribute.
+ //
+
+ Attribute *attr;
+
+ if (Attribute::knownType (typeName))
+ attr = Attribute::newAttribute (typeName);
+ else
+ attr = new OpaqueAttribute (typeName);
+
+ try
+ {
+ attr->readValueFrom (is, size, version);
+ _map[name] = attr;
+ }
+ catch (...)
+ {
+ delete attr;
+ throw;
+ }
+ }
}
}
if (!initialized)
{
- //
- // One-time initialization -- register
- // some predefined attribute types.
- //
-
- Box2fAttribute::registerAttributeType();
- Box2iAttribute::registerAttributeType();
- ChannelListAttribute::registerAttributeType();
- CompressionAttribute::registerAttributeType();
- ChromaticitiesAttribute::registerAttributeType();
- DoubleAttribute::registerAttributeType();
- EnvmapAttribute::registerAttributeType();
- FloatAttribute::registerAttributeType();
- IntAttribute::registerAttributeType();
- KeyCodeAttribute::registerAttributeType();
- LineOrderAttribute::registerAttributeType();
- M33dAttribute::registerAttributeType();
- M33fAttribute::registerAttributeType();
- M44dAttribute::registerAttributeType();
- M44fAttribute::registerAttributeType();
- PreviewImageAttribute::registerAttributeType();
- RationalAttribute::registerAttributeType();
- StringAttribute::registerAttributeType();
+ //
+ // One-time initialization -- register
+ // some predefined attribute types.
+ //
+
+ Box2fAttribute::registerAttributeType();
+ Box2iAttribute::registerAttributeType();
+ ChannelListAttribute::registerAttributeType();
+ CompressionAttribute::registerAttributeType();
+ ChromaticitiesAttribute::registerAttributeType();
+ DeepImageStateAttribute::registerAttributeType();
+ DoubleAttribute::registerAttributeType();
+ EnvmapAttribute::registerAttributeType();
+ FloatAttribute::registerAttributeType();
+ FloatVectorAttribute::registerAttributeType();
+ IntAttribute::registerAttributeType();
+ KeyCodeAttribute::registerAttributeType();
+ LineOrderAttribute::registerAttributeType();
+ M33dAttribute::registerAttributeType();
+ M33fAttribute::registerAttributeType();
+ M44dAttribute::registerAttributeType();
+ M44fAttribute::registerAttributeType();
+ PreviewImageAttribute::registerAttributeType();
+ RationalAttribute::registerAttributeType();
+ StringAttribute::registerAttributeType();
StringVectorAttribute::registerAttributeType();
- TileDescriptionAttribute::registerAttributeType();
- TimeCodeAttribute::registerAttributeType();
- V2dAttribute::registerAttributeType();
- V2fAttribute::registerAttributeType();
- V2iAttribute::registerAttributeType();
- V3dAttribute::registerAttributeType();
- V3fAttribute::registerAttributeType();
- V3iAttribute::registerAttributeType();
-
- initialized = true;
+ TileDescriptionAttribute::registerAttributeType();
+ TimeCodeAttribute::registerAttributeType();
+ V2dAttribute::registerAttributeType();
+ V2fAttribute::registerAttributeType();
+ V2iAttribute::registerAttributeType();
+ V3dAttribute::registerAttributeType();
+ V3fAttribute::registerAttributeType();
+ V3iAttribute::registerAttributeType();
+ DwaCompressor::initializeFuncs();
+
+ initialized = true;
}
}
-} // namespace Imf
+OPENEXR_IMF_INTERNAL_NAMESPACE_SOURCE_EXIT
//
// Copyright (c) 2004, Industrial Light & Magic, a division of Lucas
// Digital Ltd. LLC
-//
+//
// All rights reserved.
-//
+//
// Redistribution and use in source and binary forms, with or without
// modification, are permitted provided that the following conditions are
// met:
// distribution.
// * Neither the name of Industrial Light & Magic nor the names of
// its contributors may be used to endorse or promote products derived
-// from this software without specific prior written permission.
-//
+// from this software without specific prior written permission.
+//
// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
//
//-----------------------------------------------------------------------------
-#include <ImfLineOrder.h>
-#include <ImfCompression.h>
-#include <ImfName.h>
-#include <ImfTileDescription.h>
-#include <ImfInt64.h>
+#include "ImfLineOrder.h"
+#include "ImfCompression.h"
+#include "ImfName.h"
+#include "ImfTileDescription.h"
+#include "ImfInt64.h"
#include "ImathVec.h"
#include "ImathBox.h"
#include "IexBaseExc.h"
+
+#include "ImfForward.h"
+#include "ImfNamespace.h"
+#include "ImfExport.h"
+
#include <map>
#include <iosfwd>
#include <string>
-namespace Imf {
+OPENEXR_IMF_INTERNAL_NAMESPACE_HEADER_ENTER
-class Attribute;
-class ChannelList;
-class IStream;
-class OStream;
-class PreviewImage;
+using std::string;
class Header
{
public:
-
+
//----------------------------------------------------------------
// Default constructor -- the display window and the data window
// are both set to Box2i (V2i (0, 0), V2i (width-1, height-1).
//----------------------------------------------------------------
+ IMF_EXPORT
Header (int width = 64,
- int height = 64,
- float pixelAspectRatio = 1,
- const Imath::V2f &screenWindowCenter = Imath::V2f (0, 0),
- float screenWindowWidth = 1,
- LineOrder lineOrder = INCREASING_Y,
- Compression = ZIP_COMPRESSION);
+ int height = 64,
+ float pixelAspectRatio = 1,
+ const IMATH_NAMESPACE::V2f &screenWindowCenter = IMATH_NAMESPACE::V2f (0, 0),
+ float screenWindowWidth = 1,
+ LineOrder lineOrder = INCREASING_Y,
+ Compression = ZIP_COMPRESSION);
//--------------------------------------------------------------------
// window is set to Box2i (V2i (0, 0), V2i (width-1, height-1).
//--------------------------------------------------------------------
+ IMF_EXPORT
Header (int width,
- int height,
- const Imath::Box2i &dataWindow,
- float pixelAspectRatio = 1,
- const Imath::V2f &screenWindowCenter = Imath::V2f (0, 0),
- float screenWindowWidth = 1,
- LineOrder lineOrder = INCREASING_Y,
- Compression = ZIP_COMPRESSION);
+ int height,
+ const IMATH_NAMESPACE::Box2i &dataWindow,
+ float pixelAspectRatio = 1,
+ const IMATH_NAMESPACE::V2f &screenWindowCenter = IMATH_NAMESPACE::V2f (0, 0),
+ float screenWindowWidth = 1,
+ LineOrder lineOrder = INCREASING_Y,
+ Compression = ZIP_COMPRESSION);
//----------------------------------------------------------
// both specified explicitly.
//----------------------------------------------------------
- Header (const Imath::Box2i &displayWindow,
- const Imath::Box2i &dataWindow,
- float pixelAspectRatio = 1,
- const Imath::V2f &screenWindowCenter = Imath::V2f (0, 0),
- float screenWindowWidth = 1,
- LineOrder lineOrder = INCREASING_Y,
- Compression = ZIP_COMPRESSION);
+ IMF_EXPORT
+ Header (const IMATH_NAMESPACE::Box2i &displayWindow,
+ const IMATH_NAMESPACE::Box2i &dataWindow,
+ float pixelAspectRatio = 1,
+ const IMATH_NAMESPACE::V2f &screenWindowCenter = IMATH_NAMESPACE::V2f (0, 0),
+ float screenWindowWidth = 1,
+ LineOrder lineOrder = INCREASING_Y,
+ Compression = ZIP_COMPRESSION);
//-----------------
// Copy constructor
//-----------------
+ IMF_EXPORT
Header (const Header &other);
// Destructor
//-----------
+ IMF_EXPORT
~Header ();
// Assignment
//-----------
+ IMF_EXPORT
Header & operator = (const Header &other);
// is copied into this attribute.
//
// If an attribute with name n exists, and its
- // type is different from attr, an Iex::TypeExc
+ // type is different from attr, an IEX_NAMESPACE::TypeExc
// is thrown.
//
//---------------------------------------------------------------
+ IMF_EXPORT
void insert (const char name[],
- const Attribute &attribute);
+ const Attribute &attribute);
+ IMF_EXPORT
void insert (const std::string &name,
- const Attribute &attribute);
+ const Attribute &attribute);
+
+ //---------------------------------------------------------------
+ // Remove an attribute:
+ //
+ // remove(n) If an attribute with name n exists, then it
+ // is removed from the map of present attributes.
+ //
+ // If no attribute with name n exists, then this
+ // functions becomes a 'no-op'
+ //
+ //---------------------------------------------------------------
+ IMF_EXPORT
+ void erase (const char name[]);
+ IMF_EXPORT
+ void erase (const std::string &name);
+
+
+
//------------------------------------------------------------------
// Access to existing attributes:
//
// [n] Returns a reference to the attribute
// with name n. If no attribute with
- // name n exists, an Iex::ArgExc is thrown.
+ // name n exists, an IEX_NAMESPACE::ArgExc is thrown.
//
// typedAttribute<T>(n) Returns a reference to the attribute
// with name n and type T. If no attribute
- // with name n exists, an Iex::ArgExc is
+ // with name n exists, an IEX_NAMESPACE::ArgExc is
// thrown. If an attribute with name n
// exists, but its type is not T, an
- // Iex::TypeExc is thrown.
+ // IEX_NAMESPACE::TypeExc is thrown.
//
// findTypedAttribute<T>(n) Returns a pointer to the attribute with
// name n and type T, or 0 if no attribute
//
//------------------------------------------------------------------
+ IMF_EXPORT
Attribute & operator [] (const char name[]);
+ IMF_EXPORT
const Attribute & operator [] (const char name[]) const;
+ IMF_EXPORT
Attribute & operator [] (const std::string &name);
+ IMF_EXPORT
const Attribute & operator [] (const std::string &name) const;
template <class T> T& typedAttribute (const char name[]);
template <class T> T* findTypedAttribute (const std::string &name);
template <class T> const T* findTypedAttribute (const std::string &name)
- const;
+ const;
//---------------------------------------------
// Iterator-style access to existing attributes
class Iterator;
class ConstIterator;
+ IMF_EXPORT
Iterator begin ();
+ IMF_EXPORT
ConstIterator begin () const;
+ IMF_EXPORT
Iterator end ();
+ IMF_EXPORT
ConstIterator end () const;
+ IMF_EXPORT
Iterator find (const char name[]);
+ IMF_EXPORT
ConstIterator find (const char name[]) const;
+ IMF_EXPORT
Iterator find (const std::string &name);
+ IMF_EXPORT
ConstIterator find (const std::string &name) const;
// Access to predefined attributes
//--------------------------------
- Imath::Box2i & displayWindow ();
- const Imath::Box2i & displayWindow () const;
+ IMF_EXPORT
+ IMATH_NAMESPACE::Box2i & displayWindow ();
+ IMF_EXPORT
+ const IMATH_NAMESPACE::Box2i & displayWindow () const;
- Imath::Box2i & dataWindow ();
- const Imath::Box2i & dataWindow () const;
+ IMF_EXPORT
+ IMATH_NAMESPACE::Box2i & dataWindow ();
+ IMF_EXPORT
+ const IMATH_NAMESPACE::Box2i & dataWindow () const;
+ IMF_EXPORT
float & pixelAspectRatio ();
+ IMF_EXPORT
const float & pixelAspectRatio () const;
- Imath::V2f & screenWindowCenter ();
- const Imath::V2f & screenWindowCenter () const;
+ IMF_EXPORT
+ IMATH_NAMESPACE::V2f & screenWindowCenter ();
+ IMF_EXPORT
+ const IMATH_NAMESPACE::V2f & screenWindowCenter () const;
+ IMF_EXPORT
float & screenWindowWidth ();
+ IMF_EXPORT
const float & screenWindowWidth () const;
+ IMF_EXPORT
ChannelList & channels ();
+ IMF_EXPORT
const ChannelList & channels () const;
+ IMF_EXPORT
LineOrder & lineOrder ();
+ IMF_EXPORT
const LineOrder & lineOrder () const;
+ IMF_EXPORT
Compression & compression ();
+ IMF_EXPORT
const Compression & compression () const;
+ //-----------------------------------------------------
+ // Access to required attributes for multipart files
+ // They are optional to non-multipart files and mandatory
+ // for multipart files.
+ //-----------------------------------------------------
+ IMF_EXPORT
+ void setName (const string& name);
+
+ IMF_EXPORT
+ string& name();
+ IMF_EXPORT
+ const string& name() const;
+
+ IMF_EXPORT
+ bool hasName() const;
+
+ IMF_EXPORT
+ void setType (const string& Type);
+
+ IMF_EXPORT
+ string& type();
+ IMF_EXPORT
+ const string& type() const;
+
+ IMF_EXPORT
+ bool hasType() const;
+
+ IMF_EXPORT
+ void setVersion (const int version);
+
+ IMF_EXPORT
+ int& version();
+ IMF_EXPORT
+ const int& version() const;
+
+ IMF_EXPORT
+ bool hasVersion() const;
+
+ //
+ // the chunkCount attribute is set automatically when a file is written.
+ // There is no need to set it manually
+ //
+ IMF_EXPORT
+ void setChunkCount(int chunks);
+ IMF_EXPORT
+ bool hasChunkCount() const;
+ IMF_EXPORT
+ const int & chunkCount() const;
+ IMF_EXPORT
+ int & chunkCount();
+
+
+ //
+ // for multipart files, return whether the file has a view string attribute
+ // (for the deprecated single part multiview format EXR, see ImfMultiView.h)
+ //
+ IMF_EXPORT
+ void setView(const string & view);
+ IMF_EXPORT
+ bool hasView() const;
+ IMF_EXPORT
+ string & view();
+ IMF_EXPORT
+ const string & view() const;
+
+
//----------------------------------------------------------------------
// Tile Description:
//
//
//----------------------------------------------------------------------
+ IMF_EXPORT
void setTileDescription (const TileDescription & td);
+ IMF_EXPORT
TileDescription & tileDescription ();
+ IMF_EXPORT
const TileDescription & tileDescription () const;
+ IMF_EXPORT
bool hasTileDescription() const;
//
//----------------------------------------------------------------------
+ IMF_EXPORT
void setPreviewImage (const PreviewImage &p);
+ IMF_EXPORT
PreviewImage & previewImage ();
+ IMF_EXPORT
const PreviewImage & previewImage () const;
+ IMF_EXPORT
bool hasPreviewImage () const;
// header
//-------------------------------------------------------------
- void sanityCheck (bool isTiled = false) const;
+ IMF_EXPORT
+ void sanityCheck (bool isTiled = false,
+ bool isMultipartFile = false) const;
//----------------------------------------------------------------
// sanityCheck() will throw an exception if the width or height of
// the data window exceeds the maximum image width or height, or
// if the size of a tile exceeds the maximum tile width or height.
- //
+ //
// At program startup the maximum image and tile width and height
// are set to zero, meaning that width and height are unlimited.
//
// a damaged image file.
//----------------------------------------------------------------
+ IMF_EXPORT
static void setMaxImageSize (int maxWidth, int maxHeight);
+ IMF_EXPORT
static void setMaxTileSize (int maxWidth, int maxHeight);
+ //
+ // Check if the header reads nothing.
+ //
+ IMF_EXPORT
+ bool readsNothing();
+
//------------------------------------------------------------------
// Input and output:
//------------------------------------------------------------------
- Int64 writeTo (OStream &os,
- bool isTiled = false) const;
+ IMF_EXPORT
+ Int64 writeTo (OPENEXR_IMF_INTERNAL_NAMESPACE::OStream &os,
+ bool isTiled = false) const;
- void readFrom (IStream &is, int &version);
+ IMF_EXPORT
+ void readFrom (OPENEXR_IMF_INTERNAL_NAMESPACE::IStream &is,
+ int &version);
+
private:
AttributeMap _map;
+
+ bool _readsNothing;
};
{
public:
+ IMF_EXPORT
Iterator ();
+ IMF_EXPORT
Iterator (const Header::AttributeMap::iterator &i);
+ IMF_EXPORT
Iterator & operator ++ ();
+ IMF_EXPORT
Iterator operator ++ (int);
+ IMF_EXPORT
const char * name () const;
+ IMF_EXPORT
Attribute & attribute () const;
private:
{
public:
+ IMF_EXPORT
ConstIterator ();
+ IMF_EXPORT
ConstIterator (const Header::AttributeMap::const_iterator &i);
+ IMF_EXPORT
ConstIterator (const Header::Iterator &other);
+ IMF_EXPORT
ConstIterator & operator ++ ();
+ IMF_EXPORT
ConstIterator operator ++ (int);
+ IMF_EXPORT
const char * name () const;
+ IMF_EXPORT
const Attribute & attribute () const;
private:
//
//------------------------------------------------------------------------
-void staticInitialize ();
+void IMF_EXPORT staticInitialize ();
//-----------------
}
-inline Header::Iterator &
+inline Header::Iterator &
Header::Iterator::operator ++ ()
{
++_i;
}
-inline Header::Iterator
+inline Header::Iterator
Header::Iterator::operator ++ (int)
{
Iterator tmp = *this;
}
-inline Attribute &
+inline Attribute &
Header::Iterator::attribute () const
{
return *_i->second;
}
-inline Header::ConstIterator
+inline Header::ConstIterator
Header::ConstIterator::operator ++ (int)
{
ConstIterator tmp = *this;
}
-inline const Attribute &
+inline const Attribute &
Header::ConstIterator::attribute () const
{
return *_i->second;
T *tattr = dynamic_cast <T*> (attr);
if (tattr == 0)
- throw Iex::TypeExc ("Unexpected attribute type.");
+ throw IEX_NAMESPACE::TypeExc ("Unexpected attribute type.");
return *tattr;
}
const T *tattr = dynamic_cast <const T*> (attr);
if (tattr == 0)
- throw Iex::TypeExc ("Unexpected attribute type.");
+ throw IEX_NAMESPACE::TypeExc ("Unexpected attribute type.");
return *tattr;
}
}
-} // namespace Imf
+OPENEXR_IMF_INTERNAL_NAMESPACE_HEADER_EXIT
#endif
//
// Copyright (c) 2002, Industrial Light & Magic, a division of Lucas
// Digital Ltd. LLC
-//
+//
// All rights reserved.
-//
+//
// Redistribution and use in source and binary forms, with or without
// modification, are permitted provided that the following conditions are
// met:
// distribution.
// * Neither the name of Industrial Light & Magic nor the names of
// its contributors may be used to endorse or promote products derived
-// from this software without specific prior written permission.
-//
+// from this software without specific prior written permission.
+//
// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
#include <ImfHuf.h>
#include <ImfInt64.h>
-#include <ImfAutoArray.h>
+#include "ImfAutoArray.h"
+#include "ImfFastHuf.h"
#include "Iex.h"
-#include <string.h>
-#include <assert.h>
+#include <cstring>
+#include <cassert>
#include <algorithm>
using namespace std;
-using namespace Iex;
+using namespace IEX_NAMESPACE;
+#include "ImfNamespace.h"
+
+OPENEXR_IMF_INTERNAL_NAMESPACE_SOURCE_ENTER
-namespace Imf {
namespace {
struct HufDec
{ // short code long code
- //-------------------------------
- int len:8; // code length 0
- int lit:24; // lit p size
- int * p; // 0 lits
+ //-------------------------------
+ int len:8; // code length 0
+ int lit:24; // lit p size
+ int * p; // 0 lits
};
invalidNBits ()
{
throw InputExc ("Error in header for Huffman-encoded data "
- "(invalid number of bits).");
+ "(invalid number of bits).");
}
tooMuchData ()
{
throw InputExc ("Error in Huffman-encoded data "
- "(decoded data are longer than expected).");
+ "(decoded data are longer than expected).");
}
notEnoughData ()
{
throw InputExc ("Error in Huffman-encoded data "
- "(decoded data are shorter than expected).");
+ "(decoded data are shorter than expected).");
}
invalidCode ()
{
throw InputExc ("Error in Huffman-encoded data "
- "(invalid code).");
+ "(invalid code).");
}
invalidTableSize ()
{
throw InputExc ("Error in Huffman-encoded data "
- "(invalid code table size).");
+ "(invalid code table size).");
}
unexpectedEndOfTable ()
{
throw InputExc ("Error in Huffman-encoded data "
- "(unexpected end of code table data).");
+ "(unexpected end of code table data).");
}
tableTooLong ()
{
throw InputExc ("Error in Huffman-encoded data "
- "(code table is longer than expected).");
+ "(code table is longer than expected).");
}
invalidTableEntry ()
{
throw InputExc ("Error in Huffman-encoded data "
- "(invalid code table entry).");
+ "(invalid code table entry).");
}
c |= bits;
while (lc >= 8)
- *out++ = (c >> (lc -= 8));
+ *out++ = (c >> (lc -= 8));
}
{
while (lc < nBits)
{
- c = (c << 8) | *(unsigned char *)(in++);
- lc += 8;
+ c = (c << 8) | *(unsigned char *)(in++);
+ lc += 8;
}
lc -= nBits;
//
for (int i = 0; i <= 58; ++i)
- n[i] = 0;
+ n[i] = 0;
for (int i = 0; i < HUF_ENCSIZE; ++i)
- n[hcode[i]] += 1;
+ n[hcode[i]] += 1;
//
// For each i from 58 through 1, compute the
for (int i = 58; i > 0; --i)
{
- Int64 nc = ((c + n[i]) >> 1);
- n[i] = c;
- c = nc;
+ Int64 nc = ((c + n[i]) >> 1);
+ n[i] = c;
+ c = nc;
}
//
for (int i = 0; i < HUF_ENCSIZE; ++i)
{
- int l = hcode[i];
+ int l = hcode[i];
- if (l > 0)
- hcode[i] = l | (n[l]++ << 6);
+ if (l > 0)
+ hcode[i] = l | (n[l]++ << 6);
}
}
*im = 0;
while (!frq[*im])
- (*im)++;
+ (*im)++;
int nf = 0;
for (int i = *im; i < HUF_ENCSIZE; i++)
{
- hlink[i] = i;
-
- if (frq[i])
- {
- fHeap[nf] = &frq[i];
- nf++;
- *iM = i;
- }
+ hlink[i] = i;
+
+ if (frq[i])
+ {
+ fHeap[nf] = &frq[i];
+ nf++;
+ *iM = i;
+ }
}
//
while (nf > 1)
{
- //
- // Find the indices, mm and m, of the two smallest non-zero frq
- // values in fHeap, add the smallest frq to the second-smallest
- // frq, and remove the smallest frq value from fHeap.
- //
-
- int mm = fHeap[0] - frq;
- pop_heap (&fHeap[0], &fHeap[nf], FHeapCompare());
- --nf;
-
- int m = fHeap[0] - frq;
- pop_heap (&fHeap[0], &fHeap[nf], FHeapCompare());
-
- frq[m ] += frq[mm];
- push_heap (&fHeap[0], &fHeap[nf], FHeapCompare());
-
- //
- // The entries in scode are linked into lists with the
- // entries in hlink serving as "next" pointers and with
- // the end of a list marked by hlink[j] == j.
- //
- // Traverse the lists that start at scode[m] and scode[mm].
- // For each element visited, increment the length of the
- // corresponding code by one bit. (If we visit scode[j]
- // during the traversal, then the code for symbol j becomes
- // one bit longer.)
- //
- // Merge the lists that start at scode[m] and scode[mm]
- // into a single list that starts at scode[m].
- //
-
- //
- // Add a bit to all codes in the first list.
- //
-
- for (int j = m; true; j = hlink[j])
- {
- scode[j]++;
-
- assert (scode[j] <= 58);
-
- if (hlink[j] == j)
- {
- //
- // Merge the two lists.
- //
-
- hlink[j] = mm;
- break;
- }
- }
-
- //
- // Add a bit to all codes in the second list
- //
-
- for (int j = mm; true; j = hlink[j])
- {
- scode[j]++;
-
- assert (scode[j] <= 58);
-
- if (hlink[j] == j)
- break;
- }
+ //
+ // Find the indices, mm and m, of the two smallest non-zero frq
+ // values in fHeap, add the smallest frq to the second-smallest
+ // frq, and remove the smallest frq value from fHeap.
+ //
+
+ int mm = fHeap[0] - frq;
+ pop_heap (&fHeap[0], &fHeap[nf], FHeapCompare());
+ --nf;
+
+ int m = fHeap[0] - frq;
+ pop_heap (&fHeap[0], &fHeap[nf], FHeapCompare());
+
+ frq[m ] += frq[mm];
+ push_heap (&fHeap[0], &fHeap[nf], FHeapCompare());
+
+ //
+ // The entries in scode are linked into lists with the
+ // entries in hlink serving as "next" pointers and with
+ // the end of a list marked by hlink[j] == j.
+ //
+ // Traverse the lists that start at scode[m] and scode[mm].
+ // For each element visited, increment the length of the
+ // corresponding code by one bit. (If we visit scode[j]
+ // during the traversal, then the code for symbol j becomes
+ // one bit longer.)
+ //
+ // Merge the lists that start at scode[m] and scode[mm]
+ // into a single list that starts at scode[m].
+ //
+
+ //
+ // Add a bit to all codes in the first list.
+ //
+
+ for (int j = m; true; j = hlink[j])
+ {
+ scode[j]++;
+
+ assert (scode[j] <= 58);
+
+ if (hlink[j] == j)
+ {
+ //
+ // Merge the two lists.
+ //
+
+ hlink[j] = mm;
+ break;
+ }
+ }
+
+ //
+ // Add a bit to all codes in the second list
+ //
+
+ for (int j = mm; true; j = hlink[j])
+ {
+ scode[j]++;
+
+ assert (scode[j] <= 58);
+
+ if (hlink[j] == j)
+ break;
+ }
}
//
for (; im <= iM; im++)
{
- int l = hufLength (hcode[im]);
-
- if (l == 0)
- {
- int zerun = 1;
-
- while ((im < iM) && (zerun < LONGEST_LONG_RUN))
- {
- if (hufLength (hcode[im+1]) > 0 )
- break;
- im++;
- zerun++;
- }
-
- if (zerun >= 2)
- {
- if (zerun >= SHORTEST_LONG_RUN)
- {
- outputBits (6, LONG_ZEROCODE_RUN, c, lc, p);
- outputBits (8, zerun - SHORTEST_LONG_RUN, c, lc, p);
- }
- else
- {
- outputBits (6, SHORT_ZEROCODE_RUN + zerun - 2, c, lc, p);
- }
- continue;
- }
- }
-
- outputBits (6, l, c, lc, p);
+ int l = hufLength (hcode[im]);
+
+ if (l == 0)
+ {
+ int zerun = 1;
+
+ while ((im < iM) && (zerun < LONGEST_LONG_RUN))
+ {
+ if (hufLength (hcode[im+1]) > 0 )
+ break;
+ im++;
+ zerun++;
+ }
+
+ if (zerun >= 2)
+ {
+ if (zerun >= SHORTEST_LONG_RUN)
+ {
+ outputBits (6, LONG_ZEROCODE_RUN, c, lc, p);
+ outputBits (8, zerun - SHORTEST_LONG_RUN, c, lc, p);
+ }
+ else
+ {
+ outputBits (6, SHORT_ZEROCODE_RUN + zerun - 2, c, lc, p);
+ }
+ continue;
+ }
+ }
+
+ outputBits (6, l, c, lc, p);
}
if (lc > 0)
- *p++ = (unsigned char) (c << (8 - lc));
+ *p++ = (unsigned char) (c << (8 - lc));
*pcode = p;
}
for (; im <= iM; im++)
{
- if (p - *pcode > ni)
- unexpectedEndOfTable();
+ if (p - *pcode > ni)
+ unexpectedEndOfTable();
- Int64 l = hcode[im] = getBits (6, c, lc, p); // code length
+ Int64 l = hcode[im] = getBits (6, c, lc, p); // code length
- if (l == (Int64) LONG_ZEROCODE_RUN)
- {
- if (p - *pcode > ni)
- unexpectedEndOfTable();
+ if (l == (Int64) LONG_ZEROCODE_RUN)
+ {
+ if (p - *pcode > ni)
+ unexpectedEndOfTable();
- int zerun = getBits (8, c, lc, p) + SHORTEST_LONG_RUN;
+ int zerun = getBits (8, c, lc, p) + SHORTEST_LONG_RUN;
- if (im + zerun > iM + 1)
- tableTooLong();
+ if (im + zerun > iM + 1)
+ tableTooLong();
- while (zerun--)
- hcode[im++] = 0;
+ while (zerun--)
+ hcode[im++] = 0;
- im--;
- }
- else if (l >= (Int64) SHORT_ZEROCODE_RUN)
- {
- int zerun = l - SHORT_ZEROCODE_RUN + 2;
+ im--;
+ }
+ else if (l >= (Int64) SHORT_ZEROCODE_RUN)
+ {
+ int zerun = l - SHORT_ZEROCODE_RUN + 2;
- if (im + zerun > iM + 1)
- tableTooLong();
+ if (im + zerun > iM + 1)
+ tableTooLong();
- while (zerun--)
- hcode[im++] = 0;
+ while (zerun--)
+ hcode[im++] = 0;
- im--;
- }
+ im--;
+ }
}
- *pcode = (char *) p;
+ *pcode = const_cast<char *>(p);
hufCanonicalCodeTable (hcode);
}
void
hufClearDecTable
(HufDec * hdecod) // io: (allocated by caller)
- // decoding table [HUF_DECSIZE]
+ // decoding table [HUF_DECSIZE]
{
memset (hdecod, 0, sizeof (HufDec) * HUF_DECSIZE);
}
int im, // i : min index in hcode
int iM, // i : max index in hcode
HufDec * hdecod) // o: (allocated by caller)
- // decoding table [HUF_DECSIZE]
+ // decoding table [HUF_DECSIZE]
{
//
// Init hashtable & loop on all codes.
for (; im <= iM; im++)
{
- Int64 c = hufCode (hcode[im]);
- int l = hufLength (hcode[im]);
-
- if (c >> l)
- {
- //
- // Error: c is supposed to be an l-bit code,
- // but c contains a value that is greater
- // than the largest l-bit number.
- //
-
- invalidTableEntry();
- }
-
- if (l > HUF_DECBITS)
- {
- //
- // Long code: add a secondary entry
- //
-
- HufDec *pl = hdecod + (c >> (l - HUF_DECBITS));
-
- if (pl->len)
- {
- //
- // Error: a short code has already
- // been stored in table entry *pl.
- //
-
- invalidTableEntry();
- }
-
- pl->lit++;
-
- if (pl->p)
- {
- int *p = pl->p;
- pl->p = new int [pl->lit];
-
- for (int i = 0; i < pl->lit - 1; ++i)
- pl->p[i] = p[i];
-
- delete [] p;
- }
- else
- {
- pl->p = new int [1];
- }
-
- pl->p[pl->lit - 1]= im;
- }
- else if (l)
- {
- //
- // Short code: init all primary entries
- //
-
- HufDec *pl = hdecod + (c << (HUF_DECBITS - l));
-
- for (Int64 i = 1 << (HUF_DECBITS - l); i > 0; i--, pl++)
- {
- if (pl->len || pl->p)
- {
- //
- // Error: a short code or a long code has
- // already been stored in table entry *pl.
- //
-
- invalidTableEntry();
- }
-
- pl->len = l;
- pl->lit = im;
- }
- }
+ Int64 c = hufCode (hcode[im]);
+ int l = hufLength (hcode[im]);
+
+ if (c >> l)
+ {
+ //
+ // Error: c is supposed to be an l-bit code,
+ // but c contains a value that is greater
+ // than the largest l-bit number.
+ //
+
+ invalidTableEntry();
+ }
+
+ if (l > HUF_DECBITS)
+ {
+ //
+ // Long code: add a secondary entry
+ //
+
+ HufDec *pl = hdecod + (c >> (l - HUF_DECBITS));
+
+ if (pl->len)
+ {
+ //
+ // Error: a short code has already
+ // been stored in table entry *pl.
+ //
+
+ invalidTableEntry();
+ }
+
+ pl->lit++;
+
+ if (pl->p)
+ {
+ int *p = pl->p;
+ pl->p = new int [pl->lit];
+
+ for (int i = 0; i < pl->lit - 1; ++i)
+ pl->p[i] = p[i];
+
+ delete [] p;
+ }
+ else
+ {
+ pl->p = new int [1];
+ }
+
+ pl->p[pl->lit - 1]= im;
+ }
+ else if (l)
+ {
+ //
+ // Short code: init all primary entries
+ //
+
+ HufDec *pl = hdecod + (c << (HUF_DECBITS - l));
+
+ for (Int64 i = 1 << (HUF_DECBITS - l); i > 0; i--, pl++)
+ {
+ if (pl->len || pl->p)
+ {
+ //
+ // Error: a short code or a long code has
+ // already been stored in table entry *pl.
+ //
+
+ invalidTableEntry();
+ }
+
+ pl->len = l;
+ pl->lit = im;
+ }
+ }
}
}
{
for (int i = 0; i < HUF_DECSIZE; i++)
{
- if (hdecod[i].p)
- {
- delete [] hdecod[i].p;
- hdecod[i].p = 0;
- }
+ if (hdecod[i].p)
+ {
+ delete [] hdecod[i].p;
+ hdecod[i].p = 0;
+ }
}
}
inline void
sendCode (Int64 sCode, int runCount, Int64 runCode,
- Int64 &c, int &lc, char *&out)
+ Int64 &c, int &lc, char *&out)
{
- static const int RLMIN = 32; // min count to activate run-length coding
-
- if (runCount > RLMIN)
+ //
+ // Output a run of runCount instances of the symbol sCount.
+ // Output the symbols explicitly, or if that is shorter, output
+ // the sCode symbol once followed by a runCode symbol and runCount
+ // expressed as an 8-bit number.
+ //
+
+ if (hufLength (sCode) + hufLength (runCode) + 8 <
+ hufLength (sCode) * runCount)
{
- outputCode (sCode, c, lc, out);
- outputCode (runCode, c, lc, out);
- outputBits (8, runCount, c, lc, out);
+ outputCode (sCode, c, lc, out);
+ outputCode (runCode, c, lc, out);
+ outputBits (8, runCount, c, lc, out);
}
else
{
- while (runCount-- >= 0)
- outputCode (sCode, c, lc, out);
+ while (runCount-- >= 0)
+ outputCode (sCode, c, lc, out);
}
}
for (int i = 1; i < ni; i++)
{
- //
- // Count same values or send code
- //
-
- if (s == in[i] && cs < 255)
- {
- cs++;
- }
- else
- {
- sendCode (hcode[s], cs, hcode[rlc], c, lc, out);
- cs=0;
- }
-
- s = in[i];
+ //
+ // Count same values or send code
+ //
+
+ if (s == in[i] && cs < 255)
+ {
+ cs++;
+ }
+ else
+ {
+ sendCode (hcode[s], cs, hcode[rlc], c, lc, out);
+ cs=0;
+ }
+
+ s = in[i];
}
//
sendCode (hcode[s], cs, hcode[rlc], c, lc, out);
if (lc)
- *out = (c << (8 - lc)) & 0xff;
+ *out = (c << (8 - lc)) & 0xff;
return (out - outStart) * 8 + lc;
}
}
-#define getCode(po, rlc, c, lc, in, out, oe) \
+#define getCode(po, rlc, c, lc, in, out, ob, oe)\
{ \
if (po == rlc) \
{ \
- if (lc < 8) \
- getChar(c, lc, in); \
- \
- lc -= 8; \
- \
- unsigned char cs = (c >> lc); \
- \
- if (out + cs > oe) \
- tooMuchData(); \
- \
- unsigned short s = out[-1]; \
- \
- while (cs-- > 0) \
- *out++ = s; \
+ if (lc < 8) \
+ getChar(c, lc, in); \
+ \
+ lc -= 8; \
+ \
+ unsigned char cs = (c >> lc); \
+ \
+ if (out + cs > oe) \
+ tooMuchData(); \
+ else if (out - 1 < ob) \
+ notEnoughData(); \
+ \
+ unsigned short s = out[-1]; \
+ \
+ while (cs-- > 0) \
+ *out++ = s; \
} \
else if (out < oe) \
{ \
- *out++ = po; \
+ *out++ = po; \
} \
else \
{ \
- tooMuchData(); \
+ tooMuchData(); \
} \
}
while (in < ie)
{
- getChar (c, lc, in);
-
- //
- // Access decoding table
- //
-
- while (lc >= HUF_DECBITS)
- {
- const HufDec pl = hdecod[(c >> (lc-HUF_DECBITS)) & HUF_DECMASK];
-
- if (pl.len)
- {
- //
- // Get short code
- //
-
- lc -= pl.len;
- getCode (pl.lit, rlc, c, lc, in, out, oe);
- }
- else
- {
- if (!pl.p)
- invalidCode(); // wrong code
-
- //
- // Search long code
- //
-
- int j;
-
- for (j = 0; j < pl.lit; j++)
- {
- int l = hufLength (hcode[pl.p[j]]);
-
- while (lc < l && in < ie) // get more bits
- getChar (c, lc, in);
-
- if (lc >= l)
- {
- if (hufCode (hcode[pl.p[j]]) ==
- ((c >> (lc - l)) & ((Int64(1) << l) - 1)))
- {
- //
- // Found : get long code
- //
-
- lc -= l;
- getCode (pl.p[j], rlc, c, lc, in, out, oe);
- break;
- }
- }
- }
-
- if (j == pl.lit)
- invalidCode(); // Not found
- }
- }
+ getChar (c, lc, in);
+
+ //
+ // Access decoding table
+ //
+
+ while (lc >= HUF_DECBITS)
+ {
+ const HufDec pl = hdecod[(c >> (lc-HUF_DECBITS)) & HUF_DECMASK];
+
+ if (pl.len)
+ {
+ //
+ // Get short code
+ //
+
+ lc -= pl.len;
+ getCode (pl.lit, rlc, c, lc, in, out, outb, oe);
+ }
+ else
+ {
+ if (!pl.p)
+ invalidCode(); // wrong code
+
+ //
+ // Search long code
+ //
+
+ int j;
+
+ for (j = 0; j < pl.lit; j++)
+ {
+ int l = hufLength (hcode[pl.p[j]]);
+
+ while (lc < l && in < ie) // get more bits
+ getChar (c, lc, in);
+
+ if (lc >= l)
+ {
+ if (hufCode (hcode[pl.p[j]]) ==
+ ((c >> (lc - l)) & ((Int64(1) << l) - 1)))
+ {
+ //
+ // Found : get long code
+ //
+
+ lc -= l;
+ getCode (pl.p[j], rlc, c, lc, in, out, outb, oe);
+ break;
+ }
+ }
+ }
+
+ if (j == pl.lit)
+ invalidCode(); // Not found
+ }
+ }
}
//
while (lc > 0)
{
- const HufDec pl = hdecod[(c << (HUF_DECBITS - lc)) & HUF_DECMASK];
-
- if (pl.len)
- {
- lc -= pl.len;
- getCode (pl.lit, rlc, c, lc, in, out, oe);
- }
- else
- {
- invalidCode(); // wrong (long) code
- }
+ const HufDec pl = hdecod[(c << (HUF_DECBITS - lc)) & HUF_DECMASK];
+
+ if (pl.len)
+ {
+ lc -= pl.len;
+ getCode (pl.lit, rlc, c, lc, in, out, outb, oe);
+ }
+ else
+ {
+ invalidCode(); // wrong (long) code
+ }
}
if (out - outb != no)
- notEnoughData ();
+ notEnoughData ();
}
void
countFrequencies (Int64 freq[HUF_ENCSIZE],
- const unsigned short data[/*n*/],
- int n)
+ const unsigned short data[/*n*/],
+ int n)
{
for (int i = 0; i < HUF_ENCSIZE; ++i)
- freq[i] = 0;
+ freq[i] = 0;
for (int i = 0; i < n; ++i)
- ++freq[data[i]];
+ ++freq[data[i]];
}
const unsigned char *b = (const unsigned char *) buf;
return ( b[0] & 0x000000ff) |
- ((b[1] << 8) & 0x0000ff00) |
- ((b[2] << 16) & 0x00ff0000) |
- ((b[3] << 24) & 0xff000000);
+ ((b[1] << 8) & 0x0000ff00) |
+ ((b[2] << 16) & 0x00ff0000) |
+ ((b[3] << 24) & 0xff000000);
}
} // namespace
int
hufCompress (const unsigned short raw[],
- int nRaw,
- char compressed[])
+ int nRaw,
+ char compressed[])
{
if (nRaw == 0)
- return 0;
+ return 0;
AutoArray <Int64, HUF_ENCSIZE> freq;
countFrequencies (freq, raw, nRaw);
- int im, iM;
+ int im = 0;
+ int iM = 0;
hufBuildEncTable (freq, &im, &iM);
char *tableStart = compressed + 20;
void
hufUncompress (const char compressed[],
- int nCompressed,
- unsigned short raw[],
- int nRaw)
+ int nCompressed,
+ unsigned short raw[],
+ int nRaw)
{
if (nCompressed == 0)
{
- if (nRaw != 0)
- notEnoughData();
+ if (nRaw != 0)
+ notEnoughData();
- return;
+ return;
}
int im = readUInt (compressed);
int nBits = readUInt (compressed + 12);
if (im < 0 || im >= HUF_ENCSIZE || iM < 0 || iM >= HUF_ENCSIZE)
- invalidTableSize();
+ invalidTableSize();
const char *ptr = compressed + 20;
- AutoArray <Int64, HUF_ENCSIZE> freq;
- AutoArray <HufDec, HUF_DECSIZE> hdec;
-
- hufClearDecTable (hdec);
-
- hufUnpackEncTable (&ptr, nCompressed - (ptr - compressed), im, iM, freq);
+ //
+ // Fast decoder needs at least 2x64-bits of compressed data, and
+ // needs to be run-able on this platform. Otherwise, fall back
+ // to the original decoder
+ //
- try
+ if (FastHufDecoder::enabled() && nBits > 128)
{
- if (nBits > 8 * (nCompressed - (ptr - compressed)))
- invalidNBits();
-
- hufBuildDecTable (freq, im, iM, hdec);
- hufDecode (freq, hdec, ptr, nBits, iM, nRaw, raw);
+ FastHufDecoder fhd (ptr, nCompressed - (ptr - compressed), im, iM, iM);
+ fhd.decode ((unsigned char*)ptr, nBits, raw, nRaw);
}
- catch (...)
+ else
{
- hufFreeDecTable (hdec);
- throw;
- }
+ AutoArray <Int64, HUF_ENCSIZE> freq;
+ AutoArray <HufDec, HUF_DECSIZE> hdec;
+
+ hufClearDecTable (hdec);
- hufFreeDecTable (hdec);
+ hufUnpackEncTable (&ptr,
+ nCompressed - (ptr - compressed),
+ im,
+ iM,
+ freq);
+
+ try
+ {
+ if (nBits > 8 * (nCompressed - (ptr - compressed)))
+ invalidNBits();
+
+ hufBuildDecTable (freq, im, iM, hdec);
+ hufDecode (freq, hdec, ptr, nBits, iM, nRaw, raw);
+ }
+ catch (...)
+ {
+ hufFreeDecTable (hdec);
+ throw;
+ }
+
+ hufFreeDecTable (hdec);
+ }
}
-} // namespace Imf
+OPENEXR_IMF_INTERNAL_NAMESPACE_SOURCE_EXIT
//
// Copyright (c) 2002, Industrial Light & Magic, a division of Lucas
// Digital Ltd. LLC
-//
+//
// All rights reserved.
-//
+//
// Redistribution and use in source and binary forms, with or without
// modification, are permitted provided that the following conditions are
// met:
// distribution.
// * Neither the name of Industrial Light & Magic nor the names of
// its contributors may be used to endorse or promote products derived
-// from this software without specific prior written permission.
-//
+// from this software without specific prior written permission.
+//
// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
#ifndef INCLUDED_IMF_HUF_H
#define INCLUDED_IMF_HUF_H
+#include "ImfExport.h"
+#include "ImfNamespace.h"
//-----------------------------------------------------------------------------
//
//
//-----------------------------------------------------------------------------
-namespace Imf {
+OPENEXR_IMF_INTERNAL_NAMESPACE_HEADER_ENTER
+IMF_EXPORT
int
hufCompress (const unsigned short raw[/*nRaw*/],
- int nRaw,
- char compressed[/*2 * nRaw + 65536*/]);
-
+ int nRaw,
+ char compressed[/*2 * nRaw + 65536*/]);
+IMF_EXPORT
void
hufUncompress (const char compressed[/*nCompressed*/],
- int nCompressed,
- unsigned short raw[/*nRaw*/],
- int nRaw);
+ int nCompressed,
+ unsigned short raw[/*nRaw*/],
+ int nRaw);
-} // namespace Imf
+OPENEXR_IMF_INTERNAL_NAMESPACE_HEADER_EXIT
#endif
//
// Copyright (c) 2004, Industrial Light & Magic, a division of Lucas
// Digital Ltd. LLC
-//
+//
// All rights reserved.
-//
+//
// Redistribution and use in source and binary forms, with or without
// modification, are permitted provided that the following conditions are
// met:
// distribution.
// * Neither the name of Industrial Light & Magic nor the names of
// its contributors may be used to endorse or promote products derived
-// from this software without specific prior written permission.
-//
+// from this software without specific prior written permission.
+//
// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
#include <ImfIO.h>
#include "Iex.h"
+#include "ImfNamespace.h"
-namespace Imf {
+OPENEXR_IMF_INTERNAL_NAMESPACE_SOURCE_ENTER
IStream::IStream (const char fileName[]): _fileName (fileName)
char *
-IStream::readMemoryMapped (int)
+IStream::readMemoryMapped (int n)
{
- throw Iex::InputExc ("Attempt to perform a memory-mapped read "
- "on a file that is not memory mapped.");
+ throw IEX_NAMESPACE::InputExc ("Attempt to perform a memory-mapped read "
+ "on a file that is not memory mapped.");
return 0;
}
}
-} // namespace Imf
+OPENEXR_IMF_INTERNAL_NAMESPACE_SOURCE_EXIT
//
// Copyright (c) 2002, Industrial Light & Magic, a division of Lucas
// Digital Ltd. LLC
-//
+//
// All rights reserved.
-//
+//
// Redistribution and use in source and binary forms, with or without
// modification, are permitted provided that the following conditions are
// met:
// distribution.
// * Neither the name of Industrial Light & Magic nor the names of
// its contributors may be used to endorse or promote products derived
-// from this software without specific prior written permission.
-//
+// from this software without specific prior written permission.
+//
// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
//
//-----------------------------------------------------------------------------
-#include <ImfInt64.h>
+#include "ImfInt64.h"
+#include "ImfNamespace.h"
+#include "ImfExport.h"
+
#include <string>
-namespace Imf {
+
+OPENEXR_IMF_INTERNAL_NAMESPACE_HEADER_ENTER
//-----------------------------------------------------------
// class IStream -- an abstract base class for input streams.
// Destructor
//-----------
+ IMF_EXPORT
virtual ~IStream ();
-
-
+
+
//-------------------------------------------------
// Does this input stream support memory-mapped IO?
//
// into a buffer supplied by the caller.
//-------------------------------------------------
+ IMF_EXPORT
virtual bool isMemoryMapped () const;
//------------------------------------------------------
virtual bool read (char c[/*n*/], int n) = 0;
-
-
+
+
//---------------------------------------------------
// Read from a memory-mapped stream:
//
// returned pointer remains valid until the stream
// is closed. If there are less than n byte left to
// read in the stream or if the stream is not memory-
- // mapped, readMemoryMapped(n) throws an exception.
+ // mapped, readMemoryMapped(n) throws an exception.
//---------------------------------------------------
+ IMF_EXPORT
virtual char * readMemoryMapped (int n);
// Clear error conditions after an operation has failed.
//------------------------------------------------------
+ IMF_EXPORT
virtual void clear ();
// Get the name of the file associated with this stream.
//------------------------------------------------------
+ IMF_EXPORT
const char * fileName () const;
protected:
+ IMF_EXPORT
IStream (const char fileName[]);
private:
// Destructor
//-----------
+ IMF_EXPORT
virtual ~OStream ();
-
+
//----------------------------------------------------------
// Write to the stream:
// Get the name of the file associated with this stream.
//------------------------------------------------------
+ IMF_EXPORT
const char * fileName () const;
protected:
+ IMF_EXPORT
OStream (const char fileName[]);
private:
static void
writeChars (OStream &os, const char c[/*n*/], int n)
{
- os.write (c, n);
+ os.write (c, n);
}
static bool
readChars (IStream &is, char c[/*n*/], int n)
{
- return is.read (c, n);
+ return is.read (c, n);
}
};
static void
writeChars (char *&op, const char c[/*n*/], int n)
{
- while (n--)
- *op++ = *c++;
+ while (n--)
+ *op++ = *c++;
}
static bool
readChars (const char *&ip, char c[/*n*/], int n)
{
- while (n--)
- *c++ = *ip++;
+ while (n--)
+ *c++ = *ip++;
- return true;
+ return true;
}
};
-
-} // namespace Imf
+OPENEXR_IMF_INTERNAL_NAMESPACE_HEADER_EXIT
#endif
//
// Copyright (c) 2004, Industrial Light & Magic, a division of Lucas
// Digital Ltd. LLC
-//
+//
// All rights reserved.
-//
+//
// Redistribution and use in source and binary forms, with or without
// modification, are permitted provided that the following conditions are
// met:
// distribution.
// * Neither the name of Industrial Light & Magic nor the names of
// its contributors may be used to endorse or promote products derived
-// from this software without specific prior written permission.
-//
+// from this software without specific prior written permission.
+//
// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
//
//-----------------------------------------------------------------------------
-#include <ImfInputFile.h>
-#include <ImfScanLineInputFile.h>
-#include <ImfTiledInputFile.h>
-#include <ImfChannelList.h>
-#include <ImfMisc.h>
-#include <ImfStdIO.h>
-#include <ImfVersion.h>
+#include "ImfInputFile.h"
+#include "ImfScanLineInputFile.h"
+#include "ImfTiledInputFile.h"
+#include "ImfChannelList.h"
+#include "ImfMisc.h"
+#include "ImfStdIO.h"
+#include "ImfVersion.h"
+#include "ImfPartType.h"
+#include "ImfInputPartData.h"
+#include "ImfMultiPartInputFile.h"
+
+#include <ImfCompositeDeepScanLine.h>
+#include <ImfDeepScanLineInputFile.h>
+
#include "ImathFun.h"
#include "IlmThreadMutex.h"
#include "Iex.h"
#include "half.h"
+
#include <fstream>
#include <algorithm>
+#include "ImfNamespace.h"
-namespace Imf {
+OPENEXR_IMF_INTERNAL_NAMESPACE_SOURCE_ENTER
-using Imath::Box2i;
-using Imath::divp;
-using Imath::modp;
-using IlmThread::Mutex;
-using IlmThread::Lock;
+using IMATH_NAMESPACE::Box2i;
+using IMATH_NAMESPACE::divp;
+using IMATH_NAMESPACE::modp;
+using ILMTHREAD_NAMESPACE::Mutex;
+using ILMTHREAD_NAMESPACE::Lock;
//
// needed between calls to readPixels
//
-struct InputFile::Data: public Mutex
+struct InputFile::Data : public Mutex
{
Header header;
int version;
- IStream * is;
- bool deleteStream;
+ bool isTiled;
TiledInputFile * tFile;
ScanLineInputFile * sFile;
+ DeepScanLineInputFile * dsFile;
LineOrder lineOrder; // the file's lineorder
int minY; // data window's min y coord
int maxY; // data window's max x coord
-
- FrameBuffer tFileBuffer;
+
+ FrameBuffer tFileBuffer;
FrameBuffer * cachedBuffer;
-
+ CompositeDeepScanLine * compositor; // for loading deep files
+
int cachedTileY;
int offset;
-
+
int numThreads;
- Data (bool del, int numThreads);
+ int partNumber;
+ InputPartData* part;
+
+ bool multiPartBackwardSupport;
+ MultiPartInputFile* multiPartFile;
+ InputStreamMutex * _streamData;
+ bool _deleteStream;
+
+ Data (int numThreads);
~Data ();
void deleteCachedBuffer();
};
-InputFile::Data::Data (bool del, int numThreads):
- is (0),
- deleteStream (del),
+InputFile::Data::Data (int numThreads):
+ isTiled (false),
tFile (0),
sFile (0),
+ dsFile(0),
cachedBuffer (0),
+ compositor(0),
cachedTileY (-1),
- numThreads (numThreads)
+ numThreads (numThreads),
+ partNumber (-1),
+ part(NULL),
+ multiPartBackwardSupport (false),
+ multiPartFile (0),
+ _streamData(0),
+ _deleteStream(false)
+
{
// empty
}
InputFile::Data::~Data ()
{
- delete tFile;
- delete sFile;
-
- if (deleteStream)
- delete is;
+ if (tFile)
+ delete tFile;
+ if (sFile)
+ delete sFile;
+ if (dsFile)
+ delete dsFile;
+ if (compositor)
+ delete compositor;
deleteCachedBuffer();
+
+ if (multiPartBackwardSupport && multiPartFile)
+ delete multiPartFile;
}
-void
+void
InputFile::Data::deleteCachedBuffer()
{
//
if (cachedBuffer)
{
- for (FrameBuffer::Iterator k = cachedBuffer->begin();
- k != cachedBuffer->end();
- ++k)
- {
- Slice &s = k.slice();
+ for (FrameBuffer::Iterator k = cachedBuffer->begin();
+ k != cachedBuffer->end();
+ ++k)
+ {
+ Slice &s = k.slice();
- switch (s.type)
- {
- case UINT:
+ switch (s.type)
+ {
+ case OPENEXR_IMF_INTERNAL_NAMESPACE::UINT:
- delete [] (((unsigned int *)s.base) + offset);
- break;
+ delete [] (((unsigned int *)s.base) + offset);
+ break;
- case HALF:
+ case OPENEXR_IMF_INTERNAL_NAMESPACE::HALF:
- delete [] ((half *)s.base + offset);
- break;
+ delete [] ((half *)s.base + offset);
+ break;
- case FLOAT:
+ case OPENEXR_IMF_INTERNAL_NAMESPACE::FLOAT:
- delete [] (((float *)s.base) + offset);
- break;
- }
- }
+ delete [] (((float *)s.base) + offset);
+ break;
+ case NUM_PIXELTYPES :
+ throw(IEX_NAMESPACE::ArgExc("Invalid pixel type"));
+ }
+ }
- //
- // delete the cached frame buffer
- //
+ //
+ // delete the cached frame buffer
+ //
- delete cachedBuffer;
- cachedBuffer = 0;
+ delete cachedBuffer;
+ cachedBuffer = 0;
}
}
if (minY < ifd->minY || maxY > ifd->maxY)
{
- throw Iex::ArgExc ("Tried to read scan line outside "
- "the image file's data window.");
+ throw IEX_NAMESPACE::ArgExc ("Tried to read scan line outside "
+ "the image file's data window.");
}
//
//
Box2i levelRange = ifd->tFile->dataWindowForLevel(0);
-
+
//
// Read the tiles into our temporary framebuffer and copy them into
// the user's buffer
char *fromPtr, *toPtr;
int size = pixelTypeSize (toSlice.type);
- int xStart = levelRange.min.x;
- int yStart = minYThisRow;
+ int xStart = levelRange.min.x;
+ int yStart = minYThisRow;
- while (modp (xStart, toSlice.xSampling) != 0)
- ++xStart;
+ while (modp (xStart, toSlice.xSampling) != 0)
+ ++xStart;
- while (modp (yStart, toSlice.ySampling) != 0)
- ++yStart;
+ while (modp (yStart, toSlice.ySampling) != 0)
+ ++yStart;
for (int y = yStart;
- y <= maxYThisRow;
- y += toSlice.ySampling)
+ y <= maxYThisRow;
+ y += toSlice.ySampling)
{
- //
+ //
// Set the pointers to the start of the y scanline in
// this row of tiles
- //
-
+ //
+
fromPtr = fromSlice.base +
(y - tileRange.min.y) * fromSlice.yStride +
xStart * fromSlice.xStride;
divp (y, toSlice.ySampling) * toSlice.yStride +
divp (xStart, toSlice.xSampling) * toSlice.xStride;
- //
+ //
// Copy all pixels for the scanline in this row of tiles
- //
+ //
for (int x = xStart;
- x <= levelRange.max.x;
- x += toSlice.xSampling)
+ x <= levelRange.max.x;
+ x += toSlice.xSampling)
{
- for (size_t i = 0; i < size; ++i)
- toPtr[i] = fromPtr[i];
+ for (int i = 0; i < size; ++i)
+ toPtr[i] = fromPtr[i];
- fromPtr += fromSlice.xStride * toSlice.xSampling;
- toPtr += toSlice.xStride;
+ fromPtr += fromSlice.xStride * toSlice.xSampling;
+ toPtr += toSlice.xStride;
}
}
}
InputFile::InputFile (const char fileName[], int numThreads):
- _data (new Data (true, numThreads))
+ _data (new Data (numThreads))
{
+ _data->_streamData = NULL;
+ _data->_deleteStream=true;
+
+ OPENEXR_IMF_INTERNAL_NAMESPACE::IStream* is = 0;
try
{
- _data->is = new StdIFStream (fileName);
- initialize();
+ is = new StdIFStream (fileName);
+ readMagicNumberAndVersionField(*is, _data->version);
+
+ //
+ // compatibility to read multipart file.
+ //
+ if (isMultiPart(_data->version))
+ {
+ compatibilityInitialize(*is);
+ }
+ else
+ {
+ _data->_streamData = new InputStreamMutex();
+ _data->_streamData->is = is;
+ _data->header.readFrom (*_data->_streamData->is, _data->version);
+
+ // fix type attribute in single part regular image types
+ // (may be wrong if an old version of OpenEXR converts
+ // a tiled image to scanline or vice versa)
+ if(!isNonImage(_data->version) &&
+ !isMultiPart(_data->version) &&
+ _data->header.hasType())
+ {
+ _data->header.setType(isTiled(_data->version) ? TILEDIMAGE : SCANLINEIMAGE);
+ }
+
+ _data->header.sanityCheck (isTiled (_data->version));
+
+ initialize();
+ }
}
- catch (Iex::BaseExc &e)
+ catch (IEX_NAMESPACE::BaseExc &e)
{
- delete _data;
+ if (is) delete is;
+
+ if ( _data && !_data->multiPartBackwardSupport && _data->_streamData)
+ {
+ delete _data->_streamData;
+ _data->_streamData=NULL;
+ }
+
+ if (_data) delete _data;
+ _data=NULL;
REPLACE_EXC (e, "Cannot read image file "
- "\"" << fileName << "\". " << e);
+ "\"" << fileName << "\". " << e.what());
throw;
}
catch (...)
{
- delete _data;
+ if (is) delete is;
+ if (_data && !_data->multiPartBackwardSupport && _data->_streamData)
+ {
+ delete _data->_streamData;
+ }
+ if (_data) delete _data;
+
throw;
}
}
-InputFile::InputFile (IStream &is, int numThreads):
- _data (new Data (false, numThreads))
+InputFile::InputFile (OPENEXR_IMF_INTERNAL_NAMESPACE::IStream &is, int numThreads):
+ _data (new Data (numThreads))
{
+ _data->_streamData=NULL;
+ _data->_deleteStream=false;
try
{
- _data->is = &is;
- initialize();
+ readMagicNumberAndVersionField(is, _data->version);
+
+ //
+ // Backward compatibility to read multpart file.
+ //
+ if (isMultiPart(_data->version))
+ {
+ compatibilityInitialize(is);
+ }
+ else
+ {
+ _data->_streamData = new InputStreamMutex();
+ _data->_streamData->is = &is;
+ _data->header.readFrom (*_data->_streamData->is, _data->version);
+
+ // fix type attribute in single part regular image types
+ // (may be wrong if an old version of OpenEXR converts
+ // a tiled image to scanline or vice versa)
+ if(!isNonImage(_data->version) &&
+ !isMultiPart(_data->version) &&
+ _data->header.hasType())
+ {
+ _data->header.setType(isTiled(_data->version) ? TILEDIMAGE : SCANLINEIMAGE);
+ }
+
+ _data->header.sanityCheck (isTiled (_data->version));
+
+ initialize();
+ }
}
- catch (Iex::BaseExc &e)
+ catch (IEX_NAMESPACE::BaseExc &e)
{
- delete _data;
+ if (_data && !_data->multiPartBackwardSupport && _data->_streamData) delete _data->_streamData;
+ if (_data) delete _data;
+ _data=NULL;
REPLACE_EXC (e, "Cannot read image file "
- "\"" << is.fileName() << "\". " << e);
+ "\"" << is.fileName() << "\". " << e.what());
throw;
}
catch (...)
{
- delete _data;
+ if (_data && !_data->multiPartBackwardSupport && _data->_streamData) delete _data->_streamData;
+ if (_data) delete _data;
+ _data=NULL;
throw;
}
}
-void
-InputFile::initialize ()
+InputFile::InputFile (InputPartData* part) :
+ _data (new Data (part->numThreads))
{
- _data->header.readFrom (*_data->is, _data->version);
- _data->header.sanityCheck (isTiled (_data->version));
+ _data->_deleteStream=false;
+ multiPartInitialize (part);
+}
- if (isTiled (_data->version))
- {
- _data->lineOrder = _data->header.lineOrder();
+
+void
+InputFile::compatibilityInitialize (OPENEXR_IMF_INTERNAL_NAMESPACE::IStream& is)
+{
+ is.seekg(0);
//
- // Save the dataWindow information
+ // Construct a MultiPartInputFile, initialize InputFile
+ // with the part 0 data.
+ // (TODO) may want to have a way to set the reconstruction flag.
//
+ _data->multiPartBackwardSupport = true;
+ _data->multiPartFile = new MultiPartInputFile(is, _data->numThreads);
+ InputPartData* part = _data->multiPartFile->getPart(0);
+
+ multiPartInitialize (part);
+}
+
+
+void
+InputFile::multiPartInitialize (InputPartData* part)
+{
+ _data->_streamData = part->mutex;
+ _data->version = part->version;
+ _data->header = part->header;
+ _data->partNumber = part->partNumber;
+ _data->part = part;
+
+ initialize();
+}
- const Box2i &dataWindow = _data->header.dataWindow();
- _data->minY = dataWindow.min.y;
- _data->maxY = dataWindow.max.y;
- _data->tFile = new TiledInputFile (_data->header,
- _data->is,
- _data->version,
- _data->numThreads);
+void
+InputFile::initialize ()
+{
+ if (!_data->part)
+ {
+ if(_data->header.hasType() && _data->header.type()==DEEPSCANLINE)
+ {
+ _data->isTiled=false;
+ const Box2i &dataWindow = _data->header.dataWindow();
+ _data->minY = dataWindow.min.y;
+ _data->maxY = dataWindow.max.y;
+
+ _data->dsFile = new DeepScanLineInputFile (_data->header,
+ _data->_streamData->is,
+ _data->version,
+ _data->numThreads);
+ _data->compositor = new CompositeDeepScanLine;
+ _data->compositor->addSource(_data->dsFile);
+ }
+
+ else if (isTiled (_data->version))
+ {
+ _data->isTiled = true;
+ _data->lineOrder = _data->header.lineOrder();
+
+ //
+ // Save the dataWindow information
+ //
+
+ const Box2i &dataWindow = _data->header.dataWindow();
+ _data->minY = dataWindow.min.y;
+ _data->maxY = dataWindow.max.y;
+
+ _data->tFile = new TiledInputFile (_data->header,
+ _data->_streamData->is,
+ _data->version,
+ _data->numThreads);
+ }
+
+ else if(!_data->header.hasType() || _data->header.type()==SCANLINEIMAGE)
+ {
+ _data->sFile = new ScanLineInputFile (_data->header,
+ _data->_streamData->is,
+ _data->numThreads);
+ }else{
+ // type set but not recognised
+
+ THROW(IEX_NAMESPACE::ArgExc, "InputFile cannot handle parts of type " << _data->header.type());
+ }
}
else
{
- _data->sFile = new ScanLineInputFile (_data->header,
- _data->is,
- _data->numThreads);
+ if(_data->header.hasType() && _data->header.type()==DEEPSCANLINE)
+ {
+ _data->isTiled=false;
+ const Box2i &dataWindow = _data->header.dataWindow();
+ _data->minY = dataWindow.min.y;
+ _data->maxY = dataWindow.max.y;
+
+ _data->dsFile = new DeepScanLineInputFile (_data->part);
+ _data->compositor = new CompositeDeepScanLine;
+ _data->compositor->addSource(_data->dsFile);
+ }
+ else if (isTiled (_data->header.type()))
+ {
+ _data->isTiled = true;
+ _data->lineOrder = _data->header.lineOrder();
+
+ //
+ // Save the dataWindow information
+ //
+
+ const Box2i &dataWindow = _data->header.dataWindow();
+ _data->minY = dataWindow.min.y;
+ _data->maxY = dataWindow.max.y;
+
+ _data->tFile = new TiledInputFile (_data->part);
+ }
+ else if(!_data->header.hasType() || _data->header.type()==SCANLINEIMAGE)
+ {
+ _data->sFile = new ScanLineInputFile (_data->part);
+ }else{
+ THROW(IEX_NAMESPACE::ArgExc, "InputFile cannot handle parts of type " << _data->header.type());
+
+ }
}
}
-
+#include <iostream>
InputFile::~InputFile ()
{
- delete _data;
-}
+ if (_data->_deleteStream)
+ delete _data->_streamData->is;
+ // unless this file was opened via the multipart API,
+ // delete the streamData object too
+ if (_data->partNumber==-1 && _data->_streamData)
+ delete _data->_streamData;
+
+ if (_data) delete _data;
+}
const char *
InputFile::fileName () const
{
- return _data->is->fileName();
+ return _data->_streamData->is->fileName();
}
void
InputFile::setFrameBuffer (const FrameBuffer &frameBuffer)
{
- if (isTiled (_data->version))
+ if (_data->isTiled)
{
- Lock lock (*_data);
+ Lock lock (*_data);
- //
+ //
// We must invalidate the cached buffer if the new frame
- // buffer has a different set of channels than the old
- // frame buffer, or if the type of a channel has changed.
- //
+ // buffer has a different set of channels than the old
+ // frame buffer, or if the type of a channel has changed.
+ //
- const FrameBuffer &oldFrameBuffer = _data->tFileBuffer;
+ const FrameBuffer &oldFrameBuffer = _data->tFileBuffer;
- FrameBuffer::ConstIterator i = oldFrameBuffer.begin();
- FrameBuffer::ConstIterator j = frameBuffer.begin();
+ FrameBuffer::ConstIterator i = oldFrameBuffer.begin();
+ FrameBuffer::ConstIterator j = frameBuffer.begin();
- while (i != oldFrameBuffer.end() && j != frameBuffer.end())
- {
- if (strcmp (i.name(), j.name()) || i.slice().type != j.slice().type)
- break;
+ while (i != oldFrameBuffer.end() && j != frameBuffer.end())
+ {
+ if (strcmp (i.name(), j.name()) || i.slice().type != j.slice().type)
+ break;
- ++i;
- ++j;
- }
+ ++i;
+ ++j;
+ }
- if (i != oldFrameBuffer.end() || j != frameBuffer.end())
+ if (i != oldFrameBuffer.end() || j != frameBuffer.end())
{
- //
- // Invalidate the cached buffer.
- //
+ //
+ // Invalidate the cached buffer.
+ //
_data->deleteCachedBuffer ();
- _data->cachedTileY = -1;
-
- //
- // Create new a cached frame buffer. It can hold a single
- // row of tiles. The cached buffer can be reused for each
- // row of tiles because we set the yTileCoords parameter of
- // each Slice to true.
- //
-
- const Box2i &dataWindow = _data->header.dataWindow();
- _data->cachedBuffer = new FrameBuffer();
- _data->offset = dataWindow.min.x;
-
- int tileRowSize = (dataWindow.max.x - dataWindow.min.x + 1) *
- _data->tFile->tileYSize();
-
- for (FrameBuffer::ConstIterator k = frameBuffer.begin();
- k != frameBuffer.end();
- ++k)
- {
- Slice s = k.slice();
-
- switch (s.type)
- {
- case UINT:
-
- _data->cachedBuffer->insert
- (k.name(),
- Slice (UINT,
- (char *)(new unsigned int[tileRowSize] -
- _data->offset),
- sizeof (unsigned int),
- sizeof (unsigned int) *
- _data->tFile->levelWidth(0),
- 1, 1,
- s.fillValue,
- false, true));
- break;
-
- case HALF:
-
- _data->cachedBuffer->insert
- (k.name(),
- Slice (HALF,
- (char *)(new half[tileRowSize] -
- _data->offset),
- sizeof (half),
- sizeof (half) *
- _data->tFile->levelWidth(0),
- 1, 1,
- s.fillValue,
- false, true));
- break;
-
- case FLOAT:
-
- _data->cachedBuffer->insert
- (k.name(),
- Slice (FLOAT,
- (char *)(new float[tileRowSize] -
- _data->offset),
- sizeof(float),
- sizeof(float) *
- _data->tFile->levelWidth(0),
- 1, 1,
- s.fillValue,
- false, true));
- break;
-
- default:
-
- throw Iex::ArgExc ("Unknown pixel data type.");
- }
- }
-
- _data->tFile->setFrameBuffer (*_data->cachedBuffer);
+ _data->cachedTileY = -1;
+
+ //
+ // Create new a cached frame buffer. It can hold a single
+ // row of tiles. The cached buffer can be reused for each
+ // row of tiles because we set the yTileCoords parameter of
+ // each Slice to true.
+ //
+
+ const Box2i &dataWindow = _data->header.dataWindow();
+ _data->cachedBuffer = new FrameBuffer();
+ _data->offset = dataWindow.min.x;
+
+ int tileRowSize = (dataWindow.max.x - dataWindow.min.x + 1) *
+ _data->tFile->tileYSize();
+
+ for (FrameBuffer::ConstIterator k = frameBuffer.begin();
+ k != frameBuffer.end();
+ ++k)
+ {
+ Slice s = k.slice();
+
+ switch (s.type)
+ {
+ case OPENEXR_IMF_INTERNAL_NAMESPACE::UINT:
+
+ _data->cachedBuffer->insert
+ (k.name(),
+ Slice (UINT,
+ (char *)(new unsigned int[tileRowSize] -
+ _data->offset),
+ sizeof (unsigned int),
+ sizeof (unsigned int) *
+ _data->tFile->levelWidth(0),
+ 1, 1,
+ s.fillValue,
+ false, true));
+ break;
+
+ case OPENEXR_IMF_INTERNAL_NAMESPACE::HALF:
+
+ _data->cachedBuffer->insert
+ (k.name(),
+ Slice (HALF,
+ (char *)(new half[tileRowSize] -
+ _data->offset),
+ sizeof (half),
+ sizeof (half) *
+ _data->tFile->levelWidth(0),
+ 1, 1,
+ s.fillValue,
+ false, true));
+ break;
+
+ case OPENEXR_IMF_INTERNAL_NAMESPACE::FLOAT:
+
+ _data->cachedBuffer->insert
+ (k.name(),
+ Slice (OPENEXR_IMF_INTERNAL_NAMESPACE::FLOAT,
+ (char *)(new float[tileRowSize] -
+ _data->offset),
+ sizeof(float),
+ sizeof(float) *
+ _data->tFile->levelWidth(0),
+ 1, 1,
+ s.fillValue,
+ false, true));
+ break;
+
+ default:
+
+ throw IEX_NAMESPACE::ArgExc ("Unknown pixel data type.");
+ }
+ }
+
+ _data->tFile->setFrameBuffer (*_data->cachedBuffer);
}
- _data->tFileBuffer = frameBuffer;
+ _data->tFileBuffer = frameBuffer;
}
- else
+ else if(_data->compositor)
{
- _data->sFile->setFrameBuffer (frameBuffer);
+ _data->compositor->setFrameBuffer(frameBuffer);
+ }else {
+ _data->sFile->setFrameBuffer(frameBuffer);
+ _data->tFileBuffer = frameBuffer;
}
}
const FrameBuffer &
InputFile::frameBuffer () const
{
- if (isTiled (_data->version))
+ if(_data->compositor)
+ {
+ return _data->compositor->frameBuffer();
+ }
+ else if(_data->isTiled)
{
- Lock lock (*_data);
- return _data->tFileBuffer;
+ Lock lock (*_data);
+ return _data->tFileBuffer;
}
else
{
- return _data->sFile->frameBuffer();
+ return _data->sFile->frameBuffer();
}
}
bool
InputFile::isComplete () const
{
- if (isTiled (_data->version))
- return _data->tFile->isComplete();
+ if (_data->dsFile)
+ return _data->dsFile->isComplete();
+ else if (_data->isTiled)
+ return _data->tFile->isComplete();
else
- return _data->sFile->isComplete();
+ return _data->sFile->isComplete();
+}
+
+bool
+InputFile::isOptimizationEnabled() const
+{
+ if(_data->sFile)
+ {
+ return _data->sFile->isOptimizationEnabled();
+ }else{
+ return false;
+ }
}
void
InputFile::readPixels (int scanLine1, int scanLine2)
{
- if (isTiled (_data->version))
+ if (_data->compositor)
+ {
+ _data->compositor->readPixels(scanLine1,scanLine2);
+ }
+ else if (_data->isTiled)
{
- Lock lock (*_data);
+ Lock lock (*_data);
bufferedReadPixels (_data, scanLine1, scanLine2);
}
else
void
InputFile::rawPixelData (int firstScanLine,
- const char *&pixelData,
- int &pixelDataSize)
+ const char *&pixelData,
+ int &pixelDataSize)
{
try
{
- if (isTiled (_data->version))
- {
- throw Iex::ArgExc ("Tried to read a raw scanline "
- "from a tiled image.");
- }
-
+ if (_data->dsFile)
+ {
+ throw IEX_NAMESPACE::ArgExc ("Tried to read a raw scanline "
+ "from a deep image.");
+ }
+
+ else if (_data->isTiled)
+ {
+ throw IEX_NAMESPACE::ArgExc ("Tried to read a raw scanline "
+ "from a tiled image.");
+ }
+
_data->sFile->rawPixelData (firstScanLine, pixelData, pixelDataSize);
}
- catch (Iex::BaseExc &e)
+ catch (IEX_NAMESPACE::BaseExc &e)
{
- REPLACE_EXC (e, "Error reading pixel data from image "
- "file \"" << fileName() << "\". " << e);
- throw;
+ REPLACE_EXC (e, "Error reading pixel data from image "
+ "file \"" << fileName() << "\". " << e.what());
+ throw;
}
}
+
+
void
-InputFile::rawTileData (int &dx, int &dy,
- int &lx, int &ly,
- const char *&pixelData,
- int &pixelDataSize)
+InputFile::rawPixelDataToBuffer (int scanLine,
+ char *pixelData,
+ int &pixelDataSize) const
{
try
{
- if (!isTiled (_data->version))
+ if (_data->dsFile)
+ {
+ throw IEX_NAMESPACE::ArgExc ("Tried to read a raw scanline "
+ "from a deep image.");
+ }
+
+ else if (_data->isTiled)
+ {
+ throw IEX_NAMESPACE::ArgExc ("Tried to read a raw scanline "
+ "from a tiled image.");
+ }
+
+ _data->sFile->rawPixelDataToBuffer(scanLine, pixelData, pixelDataSize);
+ }
+ catch (IEX_NAMESPACE::BaseExc &e)
{
- throw Iex::ArgExc ("Tried to read a raw tile "
- "from a scanline-based image.");
+ REPLACE_EXC (e, "Error reading pixel data from image "
+ "file \"" << fileName() << "\". " << e.what());
+ throw;
}
+}
+
+
+void
+InputFile::rawTileData (int &dx, int &dy,
+ int &lx, int &ly,
+ const char *&pixelData,
+ int &pixelDataSize)
+{
+ try
+ {
+ if (!_data->isTiled)
+ {
+ throw IEX_NAMESPACE::ArgExc ("Tried to read a raw tile "
+ "from a scanline-based image.");
+ }
+
_data->tFile->rawTileData (dx, dy, lx, ly, pixelData, pixelDataSize);
}
- catch (Iex::BaseExc &e)
+ catch (IEX_NAMESPACE::BaseExc &e)
{
- REPLACE_EXC (e, "Error reading tile data from image "
- "file \"" << fileName() << "\". " << e);
- throw;
+ REPLACE_EXC (e, "Error reading tile data from image "
+ "file \"" << fileName() << "\". " << e.what());
+ throw;
}
}
TiledInputFile*
InputFile::tFile()
{
- if (!isTiled (_data->version))
+ if (!_data->isTiled)
{
- throw Iex::ArgExc ("Cannot get a TiledInputFile pointer "
- "from an InputFile that is not tiled.");
+ throw IEX_NAMESPACE::ArgExc ("Cannot get a TiledInputFile pointer "
+ "from an InputFile that is not tiled.");
}
return _data->tFile;
}
-} // namespace Imf
+OPENEXR_IMF_INTERNAL_NAMESPACE_SOURCE_EXIT
//
// Copyright (c) 2004, Industrial Light & Magic, a division of Lucas
// Digital Ltd. LLC
-//
+//
// All rights reserved.
-//
+//
// Redistribution and use in source and binary forms, with or without
// modification, are permitted provided that the following conditions are
// met:
// distribution.
// * Neither the name of Industrial Light & Magic nor the names of
// its contributors may be used to endorse or promote products derived
-// from this software without specific prior written permission.
-//
+// from this software without specific prior written permission.
+//
// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
//
//-----------------------------------------------------------------------------
-#include <ImfHeader.h>
-#include <ImfFrameBuffer.h>
-#include <ImfTiledOutputFile.h>
-#include <string>
+#include "ImfHeader.h"
+#include "ImfFrameBuffer.h"
+#include "ImfTiledOutputFile.h"
+#include "ImfThreading.h"
+#include "ImfGenericInputFile.h"
+#include "ImfNamespace.h"
+#include "ImfForward.h"
+#include "ImfExport.h"
+
#include <fstream>
-#include <ImfThreading.h>
-namespace Imf {
-class TiledInputFile;
-class ScanLineInputFile;
+OPENEXR_IMF_INTERNAL_NAMESPACE_HEADER_ENTER
-class InputFile
+class InputFile : public GenericInputFile
{
public:
// used to read the file (see ImfThreading.h).
//-----------------------------------------------------------
+ IMF_EXPORT
InputFile (const char fileName[], int numThreads = globalThreadCount());
// used to read the file (see ImfThreading.h).
//-------------------------------------------------------------
- InputFile (IStream &is, int numThreads = globalThreadCount());
+ IMF_EXPORT
+ InputFile (OPENEXR_IMF_INTERNAL_NAMESPACE::IStream &is, int numThreads = globalThreadCount());
//-----------
// Destructor
//-----------
+ IMF_EXPORT
virtual ~InputFile ();
// Access to the file name
//------------------------
+ IMF_EXPORT
const char * fileName () const;
// Access to the file header
//--------------------------
+ IMF_EXPORT
const Header & header () const;
// Access to the file format version
//----------------------------------
+ IMF_EXPORT
int version () const;
// to readPixels().
//-----------------------------------------------------------
+ IMF_EXPORT
void setFrameBuffer (const FrameBuffer &frameBuffer);
// Access to the current frame buffer
//-----------------------------------
+ IMF_EXPORT
const FrameBuffer & frameBuffer () const;
// writing may have been aborted prematurely.)
//---------------------------------------------------------------
+ IMF_EXPORT
bool isComplete () const;
+
+ //---------------------------------------------------------------
+ // Check if SSE optimization is enabled
+ //
+ // Call after setFrameBuffer() to query whether optimized file decoding
+ // is available - decode times will be faster if returns true
+ //
+ // Optimization depends on:
+ // the file type (only scanline data is supported),
+ // the framebuffer channels (RGB/RGBA mono or stereo)
+ // the framebuffer channel types (all channels half-float format only)
+ // the file channels (RGB/RGBA mono or stereo)
+ // the file channel types (all channel half-float format only)
+ // whether SSE2 instruction support was detected at compile time
+ //
+ // Calling isOptimizationEnabled before setFrameBuffer will throw an exception
+ //
+ //---------------------------------------------------------------
+
+ IMF_EXPORT
+ bool isOptimizationEnabled () const;
+
+
+
//---------------------------------------------------------------
// Read pixel data:
//
//---------------------------------------------------------------
+ IMF_EXPORT
void readPixels (int scanLine1, int scanLine2);
+ IMF_EXPORT
void readPixels (int scanLine);
// used to implement OutputFile::copyPixels()).
//----------------------------------------------
+ IMF_EXPORT
void rawPixelData (int firstScanLine,
- const char *&pixelData,
- int &pixelDataSize);
+ const char *&pixelData,
+ int &pixelDataSize);
+
+
+ //----------------------------------------------
+ // Read a scanline's worth of raw pixel data
+ // from the file, without uncompressing it, and
+ // store in an external buffer, pixelData.
+ // pixelData should be pre-allocated with space
+ // for pixelDataSize chars.
+ //
+ // This function can be used to separate the
+ // reading of a raw scan line from the
+ // decompression of that scan line, for
+ // example to allow multiple scan lines to be
+ // decompressed in parallel by an application's
+ // own threads, where it is not convenient to
+ // use the threading within the library.
+ //----------------------------------------------
+
+ IMF_EXPORT
+ void rawPixelDataToBuffer (int scanLine,
+ char *pixelData,
+ int &pixelDataSize) const;
+
+
//--------------------------------------------------
// Read a tile of raw pixel data from the file,
// used to implement TiledOutputFile::copyPixels()).
//--------------------------------------------------
+ IMF_EXPORT
void rawTileData (int &dx, int &dy,
- int &lx, int &ly,
- const char *&pixelData,
- int &pixelDataSize);
+ int &lx, int &ly,
+ const char *&pixelData,
+ int &pixelDataSize);
struct Data;
-
+
private:
+ InputFile (InputPartData* part);
InputFile (const InputFile &); // not implemented
InputFile & operator = (const InputFile &); // not implemented
void initialize ();
+ void multiPartInitialize(InputPartData* part);
+ void compatibilityInitialize(OPENEXR_IMF_INTERNAL_NAMESPACE::IStream& is);
TiledInputFile * tFile ();
-
+
friend void TiledOutputFile::copyPixels (InputFile &);
-
+
Data * _data;
+
+
+ friend class MultiPartInputFile;
};
-} // namespace Imf
+OPENEXR_IMF_INTERNAL_NAMESPACE_HEADER_EXIT
#endif
--- /dev/null
+///////////////////////////////////////////////////////////////////////////
+//
+// Copyright (c) 2011, Industrial Light & Magic, a division of Lucas
+// Digital Ltd. LLC
+//
+// All rights reserved.
+//
+// Redistribution and use in source and binary forms, with or without
+// modification, are permitted provided that the following conditions are
+// met:
+// * Redistributions of source code must retain the above copyright
+// notice, this list of conditions and the following disclaimer.
+// * Redistributions in binary form must reproduce the above
+// copyright notice, this list of conditions and the following disclaimer
+// in the documentation and/or other materials provided with the
+// distribution.
+// * Neither the name of Industrial Light & Magic nor the names of
+// its contributors may be used to endorse or promote products derived
+// from this software without specific prior written permission.
+//
+// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+//
+///////////////////////////////////////////////////////////////////////////
+
+#include "ImfInputPart.h"
+#include "ImfNamespace.h"
+
+#include "ImfMultiPartInputFile.h"
+
+OPENEXR_IMF_INTERNAL_NAMESPACE_SOURCE_ENTER
+
+InputPart::InputPart(MultiPartInputFile& multiPartFile, int partNumber)
+{
+ file = multiPartFile.getInputPart<InputFile>(partNumber);
+}
+
+const char *
+InputPart::fileName () const
+{
+ return file->fileName();
+}
+
+const Header &
+InputPart::header () const
+{
+ return file->header();
+}
+
+int
+InputPart::version () const
+{
+ return file->version();
+}
+
+void
+InputPart::setFrameBuffer (const FrameBuffer &frameBuffer)
+{
+ file->setFrameBuffer(frameBuffer);
+}
+
+const FrameBuffer &
+InputPart::frameBuffer () const
+{
+ return file->frameBuffer();
+}
+
+bool
+InputPart::isComplete () const
+{
+ return file->isComplete();
+}
+
+bool
+InputPart::isOptimizationEnabled() const
+{
+ return file->isOptimizationEnabled();
+}
+
+void
+InputPart::readPixels (int scanLine1, int scanLine2)
+{
+ file->readPixels(scanLine1, scanLine2);
+}
+
+void
+InputPart::readPixels (int scanLine)
+{
+ file->readPixels(scanLine);
+}
+
+void
+InputPart::rawPixelData (int firstScanLine, const char *&pixelData, int &pixelDataSize)
+{
+ file->rawPixelData(firstScanLine, pixelData, pixelDataSize);
+}
+
+
+void
+InputPart::rawPixelDataToBuffer (int scanLine, char *pixelData, int &pixelDataSize) const
+{
+ file->rawPixelDataToBuffer(scanLine, pixelData, pixelDataSize);
+}
+
+
+void
+InputPart::rawTileData (int &dx, int &dy, int &lx, int &ly,
+ const char *&pixelData, int &pixelDataSize)
+{
+ file->rawTileData(dx, dy, lx, ly, pixelData, pixelDataSize);
+}
+
+OPENEXR_IMF_INTERNAL_NAMESPACE_SOURCE_EXIT
--- /dev/null
+///////////////////////////////////////////////////////////////////////////
+//
+// Copyright (c) 2011, Industrial Light & Magic, a division of Lucas
+// Digital Ltd. LLC
+//
+// All rights reserved.
+//
+// Redistribution and use in source and binary forms, with or without
+// modification, are permitted provided that the following conditions are
+// met:
+// * Redistributions of source code must retain the above copyright
+// notice, this list of conditions and the following disclaimer.
+// * Redistributions in binary form must reproduce the above
+// copyright notice, this list of conditions and the following disclaimer
+// in the documentation and/or other materials provided with the
+// distribution.
+// * Neither the name of Industrial Light & Magic nor the names of
+// its contributors may be used to endorse or promote products derived
+// from this software without specific prior written permission.
+//
+// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+//
+///////////////////////////////////////////////////////////////////////////
+
+#ifndef IMFINPUTPART_H_
+#define IMFINPUTPART_H_
+
+#include "ImfInputFile.h"
+#include "ImfOutputPart.h"
+#include "ImfForward.h"
+#include "ImfNamespace.h"
+#include "ImfExport.h"
+
+OPENEXR_IMF_INTERNAL_NAMESPACE_HEADER_ENTER
+
+//-------------------------------------------------------------------
+// class InputPart:
+//
+// Same interface as InputFile. Please refer to InputFile.
+//-------------------------------------------------------------------
+
+class InputPart
+{
+ public:
+ IMF_EXPORT
+ InputPart(MultiPartInputFile& multiPartFile, int partNumber);
+
+ IMF_EXPORT
+ const char * fileName () const;
+ IMF_EXPORT
+ const Header & header () const;
+ IMF_EXPORT
+ int version () const;
+ IMF_EXPORT
+ void setFrameBuffer (const FrameBuffer &frameBuffer);
+ IMF_EXPORT
+ const FrameBuffer & frameBuffer () const;
+ IMF_EXPORT
+ bool isComplete () const;
+ IMF_EXPORT
+ bool isOptimizationEnabled () const;
+ IMF_EXPORT
+ void readPixels (int scanLine1, int scanLine2);
+ IMF_EXPORT
+ void readPixels (int scanLine);
+ IMF_EXPORT
+ void rawPixelData (int firstScanLine,
+ const char *&pixelData,
+ int &pixelDataSize);
+
+
+ IMF_EXPORT
+ void rawPixelDataToBuffer (int scanLine,
+ char *pixelData,
+ int &pixelDataSize) const;
+
+
+ IMF_EXPORT
+ void rawTileData (int &dx, int &dy,
+ int &lx, int &ly,
+ const char *&pixelData,
+ int &pixelDataSize);
+
+ private:
+ InputFile* file;
+ // for internal use - give OutputFile and TiledOutputFile access to file for copyPixels
+ friend void OutputFile::copyPixels(InputPart&);
+ friend void TiledOutputFile::copyPixels(InputPart&);
+
+};
+
+OPENEXR_IMF_INTERNAL_NAMESPACE_HEADER_EXIT
+
+#endif /* IMFINPUTPART_H_ */
--- /dev/null
+///////////////////////////////////////////////////////////////////////////
+//
+// Copyright (c) 2011, Industrial Light & Magic, a division of Lucas
+// Digital Ltd. LLC
+//
+// All rights reserved.
+//
+// Redistribution and use in source and binary forms, with or without
+// modification, are permitted provided that the following conditions are
+// met:
+// * Redistributions of source code must retain the above copyright
+// notice, this list of conditions and the following disclaimer.
+// * Redistributions in binary form must reproduce the above
+// copyright notice, this list of conditions and the following disclaimer
+// in the documentation and/or other materials provided with the
+// distribution.
+// * Neither the name of Industrial Light & Magic nor the names of
+// its contributors may be used to endorse or promote products derived
+// from this software without specific prior written permission.
+//
+// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+//
+///////////////////////////////////////////////////////////////////////////
+
+#include "ImfInputPartData.h"
+#include "ImfNamespace.h"
+
+OPENEXR_IMF_INTERNAL_NAMESPACE_SOURCE_ENTER
+
+InputPartData::InputPartData(InputStreamMutex* mutex, const Header &header,
+ int partNumber, int numThreads, int version):
+ header(header),
+ numThreads(numThreads),
+ partNumber(partNumber),
+ version(version),
+ mutex(mutex),
+ completed(false)
+{
+}
+
+OPENEXR_IMF_INTERNAL_NAMESPACE_SOURCE_EXIT
--- /dev/null
+///////////////////////////////////////////////////////////////////////////
+//
+// Copyright (c) 2011, Industrial Light & Magic, a division of Lucas
+// Digital Ltd. LLC
+//
+// All rights reserved.
+//
+// Redistribution and use in source and binary forms, with or without
+// modification, are permitted provided that the following conditions are
+// met:
+// * Redistributions of source code must retain the above copyright
+// notice, this list of conditions and the following disclaimer.
+// * Redistributions in binary form must reproduce the above
+// copyright notice, this list of conditions and the following disclaimer
+// in the documentation and/or other materials provided with the
+// distribution.
+// * Neither the name of Industrial Light & Magic nor the names of
+// its contributors may be used to endorse or promote products derived
+// from this software without specific prior written permission.
+//
+// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+//
+///////////////////////////////////////////////////////////////////////////
+
+#ifndef IMFINPUTPARTDATA_H_
+#define IMFINPUTPARTDATA_H_
+
+#include <vector>
+
+#include "ImfInputStreamMutex.h"
+#include "ImfHeader.h"
+#include "ImfNamespace.h"
+
+OPENEXR_IMF_INTERNAL_NAMESPACE_HEADER_ENTER
+
+
+struct InputPartData
+{
+ Header header;
+ int numThreads;
+ int partNumber;
+ int version;
+ InputStreamMutex* mutex;
+ std::vector<Int64> chunkOffsets;
+ bool completed;
+
+ IMF_EXPORT
+ InputPartData(InputStreamMutex* mutex, const Header &header,
+ int partNumber, int numThreads, int version);
+
+};
+
+
+OPENEXR_IMF_INTERNAL_NAMESPACE_HEADER_EXIT
+
+
+
+
+
+#endif /* IMFINPUTPARTDATA_H_ */
--- /dev/null
+///////////////////////////////////////////////////////////////////////////
+//
+// Copyright (c) 2011, Industrial Light & Magic, a division of Lucas
+// Digital Ltd. LLC
+//
+// All rights reserved.
+//
+// Redistribution and use in source and binary forms, with or without
+// modification, are permitted provided that the following conditions are
+// met:
+// * Redistributions of source code must retain the above copyright
+// notice, this list of conditions and the following disclaimer.
+// * Redistributions in binary form must reproduce the above
+// copyright notice, this list of conditions and the following disclaimer
+// in the documentation and/or other materials provided with the
+// distribution.
+// * Neither the name of Industrial Light & Magic nor the names of
+// its contributors may be used to endorse or promote products derived
+// from this software without specific prior written permission.
+//
+// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+//
+///////////////////////////////////////////////////////////////////////////
+
+#ifndef IMFINPUTSTREAMMUTEX_H_
+#define IMFINPUTSTREAMMUTEX_H_
+
+#include "ImfIO.h"
+#include "IlmThreadMutex.h"
+#include "ImfNamespace.h"
+
+OPENEXR_IMF_INTERNAL_NAMESPACE_HEADER_ENTER
+
+using ILMTHREAD_NAMESPACE::Mutex;
+
+//
+// Used to wrap OPENEXR_IMF_INTERNAL_NAMESPACE::IStream as a Mutex.
+//
+struct InputStreamMutex : public Mutex
+{
+ OPENEXR_IMF_INTERNAL_NAMESPACE::IStream* is;
+ Int64 currentPosition;
+
+ InputStreamMutex()
+ {
+ is = 0;
+ currentPosition = 0;
+ }
+};
+
+
+OPENEXR_IMF_INTERNAL_NAMESPACE_HEADER_EXIT
+
+
+
+
+
+#endif /* IMFINPUTSTREAMMUTEX_H_ */
//
// Copyright (c) 2006, Industrial Light & Magic, a division of Lucas
// Digital Ltd. LLC
-//
+//
// All rights reserved.
-//
+//
// Redistribution and use in source and binary forms, with or without
// modification, are permitted provided that the following conditions are
// met:
// distribution.
// * Neither the name of Industrial Light & Magic nor the names of
// its contributors may be used to endorse or promote products derived
-// from this software without specific prior written permission.
-//
+// from this software without specific prior written permission.
+//
// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
//----------------------------------------------------------------------------
#include "ImathInt64.h"
+#include "ImfNamespace.h"
+
+OPENEXR_IMF_INTERNAL_NAMESPACE_HEADER_ENTER
+
+using IMATH_NAMESPACE::Int64;
+using IMATH_NAMESPACE::SInt64;
+
+OPENEXR_IMF_INTERNAL_NAMESPACE_HEADER_EXIT
-namespace Imf {
-using Imath::Int64;
-} // namespace Imf
-#endif
+#endif // INCLUDED_IMF_INT64_H
//
// Copyright (c) 2002, Industrial Light & Magic, a division of Lucas
// Digital Ltd. LLC
-//
+//
// All rights reserved.
-//
+//
// Redistribution and use in source and binary forms, with or without
// modification, are permitted provided that the following conditions are
// met:
// distribution.
// * Neither the name of Industrial Light & Magic nor the names of
// its contributors may be used to endorse or promote products derived
-// from this software without specific prior written permission.
-//
+// from this software without specific prior written permission.
+//
// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
#include <ImfIntAttribute.h>
-namespace Imf {
+OPENEXR_IMF_INTERNAL_NAMESPACE_SOURCE_ENTER
template <>
}
-} // namespace Imf
+OPENEXR_IMF_INTERNAL_NAMESPACE_SOURCE_EXIT
//
// Copyright (c) 2002, Industrial Light & Magic, a division of Lucas
// Digital Ltd. LLC
-//
+//
// All rights reserved.
-//
+//
// Redistribution and use in source and binary forms, with or without
// modification, are permitted provided that the following conditions are
// met:
// distribution.
// * Neither the name of Industrial Light & Magic nor the names of
// its contributors may be used to endorse or promote products derived
-// from this software without specific prior written permission.
-//
+// from this software without specific prior written permission.
+//
// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
//
//-----------------------------------------------------------------------------
-#include <ImfAttribute.h>
+#include "ImfAttribute.h"
+#include "ImfNamespace.h"
-
-namespace Imf {
+OPENEXR_IMF_INTERNAL_NAMESPACE_HEADER_ENTER
typedef TypedAttribute<int> IntAttribute;
-template <> const char *IntAttribute::staticTypeName ();
-
+template <> IMF_EXPORT const char *IntAttribute::staticTypeName ();
-} // namespace Imf
-// Metrowerks compiler wants the .cpp file inlined, too
-#ifdef __MWERKS__
-#include <ImfIntAttribute.cpp>
-#endif
+OPENEXR_IMF_INTERNAL_NAMESPACE_HEADER_EXIT
#endif
//
// Copyright (c) 2004, Industrial Light & Magic, a division of Lucas
// Digital Ltd. LLC
-//
+//
// All rights reserved.
-//
+//
// Redistribution and use in source and binary forms, with or without
// modification, are permitted provided that the following conditions are
// met:
// distribution.
// * Neither the name of Industrial Light & Magic nor the names of
// its contributors may be used to endorse or promote products derived
-// from this software without specific prior written permission.
-//
+// from this software without specific prior written permission.
+//
// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
#include <ImfKeyCode.h>
#include "Iex.h"
+#include "ImfNamespace.h"
-namespace Imf {
-
+OPENEXR_IMF_INTERNAL_NAMESPACE_SOURCE_ENTER
+
KeyCode::KeyCode (int filmMfcCode,
- int filmType,
- int prefix,
- int count,
- int perfOffset,
- int perfsPerFrame,
- int perfsPerCount)
+ int filmType,
+ int prefix,
+ int count,
+ int perfOffset,
+ int perfsPerFrame,
+ int perfsPerCount)
{
setFilmMfcCode (filmMfcCode);
setFilmType (filmType);
}
-int
+int
KeyCode::filmMfcCode () const
{
return _filmMfcCode;
}
-void
+void
KeyCode::setFilmMfcCode (int filmMfcCode)
{
if (filmMfcCode < 0 || filmMfcCode > 99)
- throw Iex::ArgExc ("Invalid key code film manufacturer code "
- "(must be between 0 and 99).");
+ throw IEX_NAMESPACE::ArgExc ("Invalid key code film manufacturer code "
+ "(must be between 0 and 99).");
_filmMfcCode = filmMfcCode;
}
-int
+int
KeyCode::filmType () const
{
return _filmType;
}
-void
+void
KeyCode::setFilmType (int filmType)
{
if (filmType < 0 || filmType > 99)
- throw Iex::ArgExc ("Invalid key code film type "
- "(must be between 0 and 99).");
+ throw IEX_NAMESPACE::ArgExc ("Invalid key code film type "
+ "(must be between 0 and 99).");
_filmType = filmType;
}
-int
+int
KeyCode::prefix () const
{
return _prefix;
}
-void
+void
KeyCode::setPrefix (int prefix)
{
if (prefix < 0 || prefix > 999999)
- throw Iex::ArgExc ("Invalid key code prefix "
- "(must be between 0 and 999999).");
+ throw IEX_NAMESPACE::ArgExc ("Invalid key code prefix "
+ "(must be between 0 and 999999).");
_prefix = prefix;
}
-int
+int
KeyCode::count () const
{
return _count;
}
-void
+void
KeyCode::setCount (int count)
{
if (count < 0 || count > 9999)
- throw Iex::ArgExc ("Invalid key code count "
- "(must be between 0 and 9999).");
+ throw IEX_NAMESPACE::ArgExc ("Invalid key code count "
+ "(must be between 0 and 9999).");
_count = count;
}
-int
+int
KeyCode::perfOffset () const
{
return _perfOffset;
}
-void
+void
KeyCode::setPerfOffset (int perfOffset)
{
if (perfOffset < 0 || perfOffset > 119)
- throw Iex::ArgExc ("Invalid key code perforation offset "
- "(must be between 0 and 119).");
+ throw IEX_NAMESPACE::ArgExc ("Invalid key code perforation offset "
+ "(must be between 0 and 119).");
_perfOffset = perfOffset;
}
-int
+int
KeyCode::perfsPerFrame () const
{
return _perfsPerFrame;
KeyCode::setPerfsPerFrame (int perfsPerFrame)
{
if (perfsPerFrame < 1 || perfsPerFrame > 15)
- throw Iex::ArgExc ("Invalid key code number of perforations per frame "
- "(must be between 1 and 15).");
+ throw IEX_NAMESPACE::ArgExc ("Invalid key code number of perforations per frame "
+ "(must be between 1 and 15).");
_perfsPerFrame = perfsPerFrame;
}
-int
+int
KeyCode::perfsPerCount () const
{
return _perfsPerCount;
KeyCode::setPerfsPerCount (int perfsPerCount)
{
if (perfsPerCount < 20 || perfsPerCount > 120)
- throw Iex::ArgExc ("Invalid key code number of perforations per count "
- "(must be between 20 and 120).");
+ throw IEX_NAMESPACE::ArgExc ("Invalid key code number of perforations per count "
+ "(must be between 20 and 120).");
_perfsPerCount = perfsPerCount;
}
-} // namespace Imf
+OPENEXR_IMF_INTERNAL_NAMESPACE_SOURCE_EXIT
//
// Copyright (c) 2004, Industrial Light & Magic, a division of Lucas
// Digital Ltd. LLC
-//
+//
// All rights reserved.
-//
+//
// Redistribution and use in source and binary forms, with or without
// modification, are permitted provided that the following conditions are
// met:
// distribution.
// * Neither the name of Industrial Light & Magic nor the names of
// its contributors may be used to endorse or promote products derived
-// from this software without specific prior written permission.
-//
+// from this software without specific prior written permission.
+//
// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
//-----------------------------------------------------------------------------
//
// class KeyCode
-//
+//
// A KeyCode object uniquely identifies a motion picture film frame.
// The following fields specifiy film manufacturer, film type, film
// roll and the frame's position within the roll:
// zero-frame reference mark
// range: 0 - 119
//
-// perfsPerFrame number of perforations per frame
+// perfsPerFrame number of perforations per frame
// range: 1 - 15
//
// typical values:
// 3, 4, or 8 for 35mm film
// 5, 8 or 15 for 65mm film
//
-// perfsPerCount number of perforations per count
+// perfsPerCount number of perforations per count
// range: 20 - 120
//
// typical values:
// Latent Image Identification Information
//
//-----------------------------------------------------------------------------
+#include "ImfNamespace.h"
+#include "ImfExport.h"
-namespace Imf {
-
+OPENEXR_IMF_INTERNAL_NAMESPACE_HEADER_ENTER
+
class KeyCode
{
public:
// Constructors and assignment operator
//-------------------------------------
+ IMF_EXPORT
KeyCode (int filmMfcCode = 0,
- int filmType = 0,
- int prefix = 0,
- int count = 0,
- int perfOffset = 0,
- int perfsPerFrame = 4,
- int perfsPerCount = 64);
-
+ int filmType = 0,
+ int prefix = 0,
+ int count = 0,
+ int perfOffset = 0,
+ int perfsPerFrame = 4,
+ int perfsPerCount = 64);
+
+ IMF_EXPORT
KeyCode (const KeyCode &other);
+ IMF_EXPORT
KeyCode & operator = (const KeyCode &other);
// Access to individual fields
//----------------------------
+ IMF_EXPORT
int filmMfcCode () const;
+ IMF_EXPORT
void setFilmMfcCode (int filmMfcCode);
+ IMF_EXPORT
int filmType () const;
+ IMF_EXPORT
void setFilmType (int filmType);
+ IMF_EXPORT
int prefix () const;
+ IMF_EXPORT
void setPrefix (int prefix);
+ IMF_EXPORT
int count () const;
+ IMF_EXPORT
void setCount (int count);
+ IMF_EXPORT
int perfOffset () const;
+ IMF_EXPORT
void setPerfOffset (int perfOffset);
+ IMF_EXPORT
int perfsPerFrame () const;
+ IMF_EXPORT
void setPerfsPerFrame (int perfsPerFrame);
+ IMF_EXPORT
int perfsPerCount () const;
+ IMF_EXPORT
void setPerfsPerCount (int perfsPerCount);
private:
};
-} // namespace Imf
+OPENEXR_IMF_INTERNAL_NAMESPACE_HEADER_EXIT
+
+
+
+
#endif
//
// Copyright (c) 2004, Industrial Light & Magic, a division of Lucas
// Digital Ltd. LLC
-//
+//
// All rights reserved.
-//
+//
// Redistribution and use in source and binary forms, with or without
// modification, are permitted provided that the following conditions are
// met:
// distribution.
// * Neither the name of Industrial Light & Magic nor the names of
// its contributors may be used to endorse or promote products derived
-// from this software without specific prior written permission.
-//
+// from this software without specific prior written permission.
+//
// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
#include <ImfKeyCodeAttribute.h>
-namespace Imf {
+OPENEXR_IMF_INTERNAL_NAMESPACE_SOURCE_ENTER
+using namespace OPENEXR_IMF_INTERNAL_NAMESPACE;
template <>
const char *
template <>
void
-KeyCodeAttribute::writeValueTo (OStream &os, int) const
+KeyCodeAttribute::writeValueTo (OPENEXR_IMF_INTERNAL_NAMESPACE::OStream &os, int version) const
{
Xdr::write <StreamIO> (os, _value.filmMfcCode());
Xdr::write <StreamIO> (os, _value.filmType());
template <>
void
-KeyCodeAttribute::readValueFrom (IStream &is, int, int)
+KeyCodeAttribute::readValueFrom (OPENEXR_IMF_INTERNAL_NAMESPACE::IStream &is, int size, int version)
{
int tmp;
}
-} // namespace Imf
+OPENEXR_IMF_INTERNAL_NAMESPACE_SOURCE_EXIT
//
// Copyright (c) 2004, Industrial Light & Magic, a division of Lucas
// Digital Ltd. LLC
-//
+//
// All rights reserved.
-//
+//
// Redistribution and use in source and binary forms, with or without
// modification, are permitted provided that the following conditions are
// met:
// distribution.
// * Neither the name of Industrial Light & Magic nor the names of
// its contributors may be used to endorse or promote products derived
-// from this software without specific prior written permission.
-//
+// from this software without specific prior written permission.
+//
// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
//
//-----------------------------------------------------------------------------
-#include <ImfAttribute.h>
-#include <ImfKeyCode.h>
+#include "ImfAttribute.h"
+#include "ImfKeyCode.h"
+#include "ImfExport.h"
-namespace Imf {
+OPENEXR_IMF_INTERNAL_NAMESPACE_HEADER_ENTER
-typedef TypedAttribute<KeyCode> KeyCodeAttribute;
+typedef TypedAttribute<OPENEXR_IMF_INTERNAL_NAMESPACE::KeyCode> KeyCodeAttribute;
template <>
+IMF_EXPORT
const char *KeyCodeAttribute::staticTypeName ();
template <>
-void KeyCodeAttribute::writeValueTo (OStream &, int) const;
+IMF_EXPORT
+void KeyCodeAttribute::writeValueTo (OPENEXR_IMF_INTERNAL_NAMESPACE::OStream &,
+ int) const;
template <>
-void KeyCodeAttribute::readValueFrom (IStream &, int, int);
+IMF_EXPORT
+void KeyCodeAttribute::readValueFrom (OPENEXR_IMF_INTERNAL_NAMESPACE::IStream &,
+ int, int);
-} // namespace Imf
-
-// Metrowerks compiler wants the .cpp file inlined, too
-#ifdef __MWERKS__
-#include <ImfKeyCodeAttribute.cpp>
-#endif
+OPENEXR_IMF_INTERNAL_NAMESPACE_HEADER_EXIT
#endif
//
// Copyright (c) 2004, Industrial Light & Magic, a division of Lucas
// Digital Ltd. LLC
-//
+//
// All rights reserved.
-//
+//
// Redistribution and use in source and binary forms, with or without
// modification, are permitted provided that the following conditions are
// met:
// distribution.
// * Neither the name of Industrial Light & Magic nor the names of
// its contributors may be used to endorse or promote products derived
-// from this software without specific prior written permission.
-//
+// from this software without specific prior written permission.
+//
// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
// enum LineOrder
//
//-----------------------------------------------------------------------------
+#include "ImfNamespace.h"
-namespace Imf {
+OPENEXR_IMF_INTERNAL_NAMESPACE_HEADER_ENTER
enum LineOrder
DECREASING_Y = 1, // first scan line has highest y coordinate
RANDOM_Y = 2, // only for tiled files; tiles are written
- // in random order
+ // in random order
NUM_LINEORDERS // number of different line orders
};
-} // namespace Imf
+OPENEXR_IMF_INTERNAL_NAMESPACE_HEADER_EXIT
+
+
+
+
#endif
//
// Copyright (c) 2002, Industrial Light & Magic, a division of Lucas
// Digital Ltd. LLC
-//
+//
// All rights reserved.
-//
+//
// Redistribution and use in source and binary forms, with or without
// modification, are permitted provided that the following conditions are
// met:
// distribution.
// * Neither the name of Industrial Light & Magic nor the names of
// its contributors may be used to endorse or promote products derived
-// from this software without specific prior written permission.
-//
+// from this software without specific prior written permission.
+//
// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
//
//-----------------------------------------------------------------------------
-#include <ImfLineOrderAttribute.h>
+#include "ImfLineOrderAttribute.h"
-namespace Imf {
+OPENEXR_IMF_INTERNAL_NAMESPACE_SOURCE_ENTER
+using namespace OPENEXR_IMF_INTERNAL_NAMESPACE;
template <>
const char *
template <>
void
-LineOrderAttribute::writeValueTo (OStream &os, int) const
+LineOrderAttribute::writeValueTo (OPENEXR_IMF_INTERNAL_NAMESPACE::OStream &os, int version) const
{
unsigned char tmp = _value;
Xdr::write <StreamIO> (os, tmp);
template <>
void
-LineOrderAttribute::readValueFrom (IStream &is, int, int)
+LineOrderAttribute::readValueFrom (OPENEXR_IMF_INTERNAL_NAMESPACE::IStream &is, int size, int version)
{
unsigned char tmp;
Xdr::read <StreamIO> (is, tmp);
}
-} // namespace Imf
+OPENEXR_IMF_INTERNAL_NAMESPACE_SOURCE_EXIT
//
// Copyright (c) 2002, Industrial Light & Magic, a division of Lucas
// Digital Ltd. LLC
-//
+//
// All rights reserved.
-//
+//
// Redistribution and use in source and binary forms, with or without
// modification, are permitted provided that the following conditions are
// met:
// distribution.
// * Neither the name of Industrial Light & Magic nor the names of
// its contributors may be used to endorse or promote products derived
-// from this software without specific prior written permission.
-//
+// from this software without specific prior written permission.
+//
// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
//
//-----------------------------------------------------------------------------
-#include <ImfAttribute.h>
-#include <ImfLineOrder.h>
+#include "ImfAttribute.h"
+#include "ImfLineOrder.h"
+#include "ImfExport.h"
+OPENEXR_IMF_INTERNAL_NAMESPACE_HEADER_ENTER
-namespace Imf {
+typedef TypedAttribute<OPENEXR_IMF_INTERNAL_NAMESPACE::LineOrder> LineOrderAttribute;
-typedef TypedAttribute<LineOrder> LineOrderAttribute;
-template <> const char *LineOrderAttribute::staticTypeName ();
-template <> void LineOrderAttribute::writeValueTo (OStream &, int) const;
-template <> void LineOrderAttribute::readValueFrom (IStream &, int, int);
+template <>
+IMF_EXPORT
+const char *LineOrderAttribute::staticTypeName ();
+template <>
+IMF_EXPORT
+void LineOrderAttribute::writeValueTo (OPENEXR_IMF_INTERNAL_NAMESPACE::OStream &,
+ int) const;
-} // namespace Imf
+template <>
+IMF_EXPORT
+void LineOrderAttribute::readValueFrom (OPENEXR_IMF_INTERNAL_NAMESPACE::IStream &,
+ int, int);
-// Metrowerks compiler wants the .cpp file inlined, too
-#ifdef __MWERKS__
-#include <ImfLineOrderAttribute.cpp>
-#endif
+
+OPENEXR_IMF_INTERNAL_NAMESPACE_HEADER_EXIT
#endif
//
// Copyright (c) 2002, Industrial Light & Magic, a division of Lucas
// Digital Ltd. LLC
-//
+//
// All rights reserved.
-//
+//
// Redistribution and use in source and binary forms, with or without
// modification, are permitted provided that the following conditions are
// met:
// distribution.
// * Neither the name of Industrial Light & Magic nor the names of
// its contributors may be used to endorse or promote products derived
-// from this software without specific prior written permission.
-//
+// from this software without specific prior written permission.
+//
// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
#include <ImfLut.h>
#include <math.h>
#include <assert.h>
+#include "ImfNamespace.h"
-namespace Imf {
+OPENEXR_IMF_INTERNAL_NAMESPACE_SOURCE_ENTER
void
{
while (nData)
{
- *data = _lut (*data);
- data += stride;
- nData -= 1;
+ *data = _lut (*data);
+ data += stride;
+ nData -= 1;
}
}
void
-HalfLut::apply (const Slice &data, const Imath::Box2i &dataWindow) const
+HalfLut::apply (const Slice &data, const IMATH_NAMESPACE::Box2i &dataWindow) const
{
assert (data.type == HALF);
assert (dataWindow.min.x % data.xSampling == 0);
assert ((dataWindow.max.y - dataWindow.min.y + 1) % data.ySampling == 0);
char *base = data.base + data.yStride *
- (dataWindow.min.y / data.ySampling);
+ (dataWindow.min.y / data.ySampling);
for (int y = dataWindow.min.y;
- y <= dataWindow.max.y;
- y += data.ySampling)
- {
- char *pixel = base + data.xStride *
- (dataWindow.min.x / data.xSampling);
-
- for (int x = dataWindow.min.x;
- x <= dataWindow.max.x;
- x += data.xSampling)
+ y <= dataWindow.max.y;
+ y += data.ySampling)
{
- *(half *)pixel = _lut (*(half *)pixel);
- pixel += data.xStride;
- }
-
- base += data.yStride;
+ char *pixel = base + data.xStride *
+ (dataWindow.min.x / data.xSampling);
+
+ for (int x = dataWindow.min.x;
+ x <= dataWindow.max.x;
+ x += data.xSampling)
+ {
+ *(half *)pixel = _lut (*(half *)pixel);
+ pixel += data.xStride;
+ }
+
+ base += data.yStride;
}
}
{
while (nData)
{
- if (_chn & WRITE_R)
- data->r = _lut (data->r);
+ if (_chn & WRITE_R)
+ data->r = _lut (data->r);
- if (_chn & WRITE_G)
- data->g = _lut (data->g);
+ if (_chn & WRITE_G)
+ data->g = _lut (data->g);
- if (_chn & WRITE_B)
- data->b = _lut (data->b);
+ if (_chn & WRITE_B)
+ data->b = _lut (data->b);
- if (_chn & WRITE_A)
- data->a = _lut (data->a);
+ if (_chn & WRITE_A)
+ data->a = _lut (data->a);
- data += stride;
- nData -= 1;
+ data += stride;
+ nData -= 1;
}
}
void
RgbaLut::apply (Rgba *base,
- int xStride, int yStride,
- const Imath::Box2i &dataWindow) const
+ int xStride, int yStride,
+ const IMATH_NAMESPACE::Box2i &dataWindow) const
{
base += dataWindow.min.y * yStride;
for (int y = dataWindow.min.y; y <= dataWindow.max.y; ++y)
{
- Rgba *pixel = base + dataWindow.min.x * xStride;
+ Rgba *pixel = base + dataWindow.min.x * xStride;
- for (int x = dataWindow.min.x; x <= dataWindow.max.x; ++x)
- {
- if (_chn & WRITE_R)
- pixel->r = _lut (pixel->r);
+ for (int x = dataWindow.min.x; x <= dataWindow.max.x; ++x)
+ {
+ if (_chn & WRITE_R)
+ pixel->r = _lut (pixel->r);
- if (_chn & WRITE_G)
- pixel->g = _lut (pixel->g);
+ if (_chn & WRITE_G)
+ pixel->g = _lut (pixel->g);
- if (_chn & WRITE_B)
- pixel->b = _lut (pixel->b);
+ if (_chn & WRITE_B)
+ pixel->b = _lut (pixel->b);
- if (_chn & WRITE_A)
- pixel->a = _lut (pixel->a);
+ if (_chn & WRITE_A)
+ pixel->a = _lut (pixel->a);
- pixel += xStride;
- }
+ pixel += xStride;
+ }
- base += yStride;
+ base += yStride;
}
}
if (x <= 0)
{
- return 0;
+ return 0;
}
else
{
- int12log = int (2000.5 + 200.0 * log (x / middleval) / log (2.0));
+ int12log = int (2000.5 + 200.0 * log (x / middleval) / log (2.0));
- if (int12log > 4095)
- int12log = 4095;
+ if (int12log > 4095)
+ int12log = 4095;
- if (int12log < 1)
- int12log = 1;
+ if (int12log < 1)
+ int12log = 1;
}
return middleval * pow (2.0, (int12log - 2000.0) / 200.0);
}
-} // namespace Imf
+OPENEXR_IMF_INTERNAL_NAMESPACE_SOURCE_EXIT
+
//
// Copyright (c) 2002, Industrial Light & Magic, a division of Lucas
// Digital Ltd. LLC
-//
+//
// All rights reserved.
-//
+//
// Redistribution and use in source and binary forms, with or without
// modification, are permitted provided that the following conditions are
// met:
// distribution.
// * Neither the name of Industrial Light & Magic nor the names of
// its contributors may be used to endorse or promote products derived
-// from this software without specific prior written permission.
-//
+// from this software without specific prior written permission.
+//
// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
//
//-----------------------------------------------------------------------------
-#include <ImfRgbaFile.h>
-#include <ImfFrameBuffer.h>
+#include "ImfRgbaFile.h"
+#include "ImfFrameBuffer.h"
#include "ImathBox.h"
#include "halfFunction.h"
+#include "ImfNamespace.h"
+#include "ImfExport.h"
-namespace Imf {
+OPENEXR_IMF_INTERNAL_NAMESPACE_HEADER_ENTER
//
// Lookup table for individual half channels.
// Apply the table to data[0], data[stride] ... data[(nData-1) * stride]
//----------------------------------------------------------------------
+ IMF_EXPORT
void apply (half *data,
- int nData,
- int stride = 1) const;
+ int nData,
+ int stride = 1) const;
//---------------------------------------------------------------
// Apply the table to a frame buffer slice (see ImfFrameBuffer.h)
//---------------------------------------------------------------
+ IMF_EXPORT
void apply (const Slice &data,
- const Imath::Box2i &dataWindow) const;
+ const IMATH_NAMESPACE::Box2i &dataWindow) const;
private:
// Apply the table to data[0], data[stride] ... data[(nData-1) * stride]
//----------------------------------------------------------------------
+ IMF_EXPORT
void apply (Rgba *data,
- int nData,
- int stride = 1) const;
+ int nData,
+ int stride = 1) const;
//-----------------------------------------------------------------------
// Apply the table to a frame buffer (see RgbaOutpuFile.setFrameBuffer())
//-----------------------------------------------------------------------
+ IMF_EXPORT
void apply (Rgba *base,
- int xStride,
- int yStride,
- const Imath::Box2i &dataWindow) const;
+ int xStride,
+ int yStride,
+ const IMATH_NAMESPACE::Box2i &dataWindow) const;
private:
// the center [2000] and that number is near 0.18.
//
+IMF_EXPORT
half round12log (half x);
template <class Function>
HalfLut::HalfLut (Function f):
_lut(f, -HALF_MAX, HALF_MAX, half (0),
- half::posInf(), half::negInf(), half::qNan())
+ half::posInf(), half::negInf(), half::qNan())
{
// empty
}
template <class Function>
RgbaLut::RgbaLut (Function f, RgbaChannels chn):
_lut(f, -HALF_MAX, HALF_MAX, half (0),
- half::posInf(), half::negInf(), half::qNan()),
+ half::posInf(), half::negInf(), half::qNan()),
_chn(chn)
{
// empty
}
-} // namespace Imf
+OPENEXR_IMF_INTERNAL_NAMESPACE_HEADER_EXIT
#endif
//
// Copyright (c) 2002, Industrial Light & Magic, a division of Lucas
// Digital Ltd. LLC
-//
+//
// All rights reserved.
-//
+//
// Redistribution and use in source and binary forms, with or without
// modification, are permitted provided that the following conditions are
// met:
// distribution.
// * Neither the name of Industrial Light & Magic nor the names of
// its contributors may be used to endorse or promote products derived
-// from this software without specific prior written permission.
-//
+// from this software without specific prior written permission.
+//
// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
#include <ImfMatrixAttribute.h>
-namespace Imf {
+OPENEXR_IMF_INTERNAL_NAMESPACE_SOURCE_ENTER
+
+
+using namespace OPENEXR_IMF_INTERNAL_NAMESPACE;
template <>
template <>
void
-M33fAttribute::writeValueTo (OStream &os, int) const
+M33fAttribute::writeValueTo (OPENEXR_IMF_INTERNAL_NAMESPACE::OStream &os, int version) const
{
Xdr::write <StreamIO> (os, _value[0][0]);
Xdr::write <StreamIO> (os, _value[0][1]);
template <>
void
-M33fAttribute::readValueFrom (IStream &is, int, int)
+M33fAttribute::readValueFrom (OPENEXR_IMF_INTERNAL_NAMESPACE::IStream &is, int size, int version)
{
Xdr::read <StreamIO> (is, _value[0][0]);
Xdr::read <StreamIO> (is, _value[0][1]);
template <>
void
-M33dAttribute::writeValueTo (OStream &os, int) const
+M33dAttribute::writeValueTo (OPENEXR_IMF_INTERNAL_NAMESPACE::OStream &os, int version) const
{
Xdr::write <StreamIO> (os, _value[0][0]);
Xdr::write <StreamIO> (os, _value[0][1]);
template <>
void
-M33dAttribute::readValueFrom (IStream &is, int, int)
+M33dAttribute::readValueFrom (OPENEXR_IMF_INTERNAL_NAMESPACE::IStream &is, int size, int version)
{
Xdr::read <StreamIO> (is, _value[0][0]);
Xdr::read <StreamIO> (is, _value[0][1]);
template <>
void
-M44fAttribute::writeValueTo (OStream &os, int) const
+M44fAttribute::writeValueTo (OPENEXR_IMF_INTERNAL_NAMESPACE::OStream &os, int version) const
{
Xdr::write <StreamIO> (os, _value[0][0]);
Xdr::write <StreamIO> (os, _value[0][1]);
template <>
void
-M44fAttribute::readValueFrom (IStream &is, int, int)
+M44fAttribute::readValueFrom (OPENEXR_IMF_INTERNAL_NAMESPACE::IStream &is, int size, int version)
{
Xdr::read <StreamIO> (is, _value[0][0]);
Xdr::read <StreamIO> (is, _value[0][1]);
template <>
void
-M44dAttribute::writeValueTo (OStream &os, int) const
+M44dAttribute::writeValueTo (OPENEXR_IMF_INTERNAL_NAMESPACE::OStream &os, int version) const
{
Xdr::write <StreamIO> (os, _value[0][0]);
Xdr::write <StreamIO> (os, _value[0][1]);
template <>
void
-M44dAttribute::readValueFrom (IStream &is, int, int)
+M44dAttribute::readValueFrom (OPENEXR_IMF_INTERNAL_NAMESPACE::IStream &is, int size, int version)
{
Xdr::read <StreamIO> (is, _value[0][0]);
Xdr::read <StreamIO> (is, _value[0][1]);
}
-} // namespace Imf
+OPENEXR_IMF_INTERNAL_NAMESPACE_SOURCE_EXIT
//
// Copyright (c) 2002, Industrial Light & Magic, a division of Lucas
// Digital Ltd. LLC
-//
+//
// All rights reserved.
-//
+//
// Redistribution and use in source and binary forms, with or without
// modification, are permitted provided that the following conditions are
// met:
// distribution.
// * Neither the name of Industrial Light & Magic nor the names of
// its contributors may be used to endorse or promote products derived
-// from this software without specific prior written permission.
-//
+// from this software without specific prior written permission.
+//
// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
//
//-----------------------------------------------------------------------------
-#include <ImfAttribute.h>
+#include "ImfAttribute.h"
#include "ImathMatrix.h"
+#include "ImfExport.h"
-namespace Imf {
+OPENEXR_IMF_INTERNAL_NAMESPACE_HEADER_ENTER
-typedef TypedAttribute<Imath::M33f> M33fAttribute;
-template <> const char *M33fAttribute::staticTypeName ();
-template <> void M33fAttribute::writeValueTo (OStream &, int) const;
-template <> void M33fAttribute::readValueFrom (IStream &, int, int);
+typedef TypedAttribute<IMATH_NAMESPACE::M33f> M33fAttribute;
+template <> IMF_EXPORT const char *M33fAttribute::staticTypeName ();
+template <> IMF_EXPORT void M33fAttribute::writeValueTo (OPENEXR_IMF_INTERNAL_NAMESPACE::OStream &, int) const;
+template <> IMF_EXPORT void M33fAttribute::readValueFrom (OPENEXR_IMF_INTERNAL_NAMESPACE::IStream &, int, int);
-typedef TypedAttribute<Imath::M33d> M33dAttribute;
-template <> const char *M33dAttribute::staticTypeName ();
-template <> void M33dAttribute::writeValueTo (OStream &, int) const;
-template <> void M33dAttribute::readValueFrom (IStream &, int, int);
+typedef TypedAttribute<IMATH_NAMESPACE::M33d> M33dAttribute;
+template <> IMF_EXPORT const char *M33dAttribute::staticTypeName ();
+template <> IMF_EXPORT void M33dAttribute::writeValueTo (OPENEXR_IMF_INTERNAL_NAMESPACE::OStream &, int) const;
+template <> IMF_EXPORT void M33dAttribute::readValueFrom (OPENEXR_IMF_INTERNAL_NAMESPACE::IStream &, int, int);
-typedef TypedAttribute<Imath::M44f> M44fAttribute;
-template <> const char *M44fAttribute::staticTypeName ();
-template <> void M44fAttribute::writeValueTo (OStream &, int) const;
-template <> void M44fAttribute::readValueFrom (IStream &, int, int);
+typedef TypedAttribute<IMATH_NAMESPACE::M44f> M44fAttribute;
+template <> IMF_EXPORT const char *M44fAttribute::staticTypeName ();
+template <> IMF_EXPORT void M44fAttribute::writeValueTo (OPENEXR_IMF_INTERNAL_NAMESPACE::OStream &, int) const;
+template <> IMF_EXPORT void M44fAttribute::readValueFrom (OPENEXR_IMF_INTERNAL_NAMESPACE::IStream &, int, int);
-typedef TypedAttribute<Imath::M44d> M44dAttribute;
-template <> const char *M44dAttribute::staticTypeName ();
-template <> void M44dAttribute::writeValueTo (OStream &, int) const;
-template <> void M44dAttribute::readValueFrom (IStream &, int, int);
+typedef TypedAttribute<IMATH_NAMESPACE::M44d> M44dAttribute;
+template <> IMF_EXPORT const char *M44dAttribute::staticTypeName ();
+template <> IMF_EXPORT void M44dAttribute::writeValueTo (OPENEXR_IMF_INTERNAL_NAMESPACE::OStream &, int) const;
+template <> IMF_EXPORT void M44dAttribute::readValueFrom (OPENEXR_IMF_INTERNAL_NAMESPACE::IStream &, int, int);
-} // namespace Imf
-
-// Metrowerks compiler wants the .cpp file inlined, too
-#ifdef __MWERKS__
-#include <ImfMatrixAttribute.cpp>
-#endif
+OPENEXR_IMF_INTERNAL_NAMESPACE_HEADER_EXIT
#endif
//
// Copyright (c) 2004, Industrial Light & Magic, a division of Lucas
// Digital Ltd. LLC
-//
+//
// All rights reserved.
-//
+//
// Redistribution and use in source and binary forms, with or without
// modification, are permitted provided that the following conditions are
// met:
// distribution.
// * Neither the name of Industrial Light & Magic nor the names of
// its contributors may be used to endorse or promote products derived
-// from this software without specific prior written permission.
-//
+// from this software without specific prior written permission.
+//
// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
#include <ImfMisc.h>
#include <ImfHeader.h>
+#include <ImfAttribute.h>
#include <ImfCompressor.h>
#include <ImfChannelList.h>
#include <ImfXdr.h>
#include <Iex.h>
#include <ImfStdIO.h>
#include <ImfConvert.h>
+#include <ImfPartType.h>
+#include <ImfTileDescription.h>
+#include "ImfNamespace.h"
-namespace Imf {
+OPENEXR_IMF_INTERNAL_NAMESPACE_SOURCE_ENTER
-using Imath::Box2i;
-using Imath::divp;
-using Imath::modp;
+using IMATH_NAMESPACE::Box2i;
+using IMATH_NAMESPACE::divp;
+using IMATH_NAMESPACE::modp;
using std::vector;
int
switch (type)
{
- case UINT:
+ case OPENEXR_IMF_INTERNAL_NAMESPACE::UINT:
+
+ size = Xdr::size <unsigned int> ();
+ break;
- size = Xdr::size <unsigned int> ();
- break;
+ case OPENEXR_IMF_INTERNAL_NAMESPACE::HALF:
- case HALF:
+ size = Xdr::size <half> ();
+ break;
- size = Xdr::size <half> ();
- break;
+ case OPENEXR_IMF_INTERNAL_NAMESPACE::FLOAT:
- case FLOAT:
-
- size = Xdr::size <float> ();
- break;
+ size = Xdr::size <float> ();
+ break;
default:
- throw Iex::ArgExc ("Unknown pixel type.");
+ throw IEX_NAMESPACE::ArgExc ("Unknown pixel type.");
}
return size;
size_t
bytesPerLineTable (const Header &header,
- vector<size_t> &bytesPerLine)
+ vector<size_t> &bytesPerLine)
{
const Box2i &dataWindow = header.dataWindow();
const ChannelList &channels = header.channels();
bytesPerLine.resize (dataWindow.max.y - dataWindow.min.y + 1);
for (ChannelList::ConstIterator c = channels.begin();
- c != channels.end();
- ++c)
+ c != channels.end();
+ ++c)
{
- int nBytes = pixelTypeSize (c.channel().type) *
- (dataWindow.max.x - dataWindow.min.x + 1) /
- c.channel().xSampling;
+ int nBytes = pixelTypeSize (c.channel().type) *
+ (dataWindow.max.x - dataWindow.min.x + 1) /
+ c.channel().xSampling;
- for (int y = dataWindow.min.y, i = 0; y <= dataWindow.max.y; ++y, ++i)
- if (modp (y, c.channel().ySampling) == 0)
- bytesPerLine[i] += nBytes;
+ for (int y = dataWindow.min.y, i = 0; y <= dataWindow.max.y; ++y, ++i)
+ if (modp (y, c.channel().ySampling) == 0)
+ bytesPerLine[i] += nBytes;
}
size_t maxBytesPerLine = 0;
for (int y = dataWindow.min.y, i = 0; y <= dataWindow.max.y; ++y, ++i)
- if (maxBytesPerLine < bytesPerLine[i])
- maxBytesPerLine = bytesPerLine[i];
+ if (maxBytesPerLine < bytesPerLine[i])
+ maxBytesPerLine = bytesPerLine[i];
return maxBytesPerLine;
}
+static int
+roundToNextMultiple(int n, int d)
+{
+ return ((n + d - 1) / d) * d;
+}
+
+static int
+roundToPrevMultiple(int n, int d)
+{
+ return (n / d) * d;
+}
+
+size_t
+bytesPerDeepLineTable (const Header &header,
+ int minY, int maxY,
+ const char* base,
+ int xStride,
+ int yStride,
+ vector<size_t> &bytesPerLine)
+{
+ const Box2i &dataWindow = header.dataWindow();
+ const ChannelList &channels = header.channels();
+
+ for (ChannelList::ConstIterator c = channels.begin();
+ c != channels.end();
+ ++c)
+ {
+ const int ySampling = abs(c.channel().ySampling);
+ const int xSampling = abs(c.channel().xSampling);
+ const int pixelSize = pixelTypeSize (c.channel().type);
+
+ // Here we transform from the domain over all pixels into the domain
+ // of actual samples. We want to sample points in [minY, maxY] where
+ // (y % ySampling) == 0. However, doing this by rejecting samples
+ // requires O(height*width) modulo computations, which were a
+ // significant bottleneck in the previous implementation of this
+ // function. For the low, low price of 4 divisions per channel, we
+ // can tighten the y & x ranges to the least and greatest roots of the
+ // sampling function and then stride by the sampling rate.
+ const int sampleMinY = roundToNextMultiple(minY, ySampling);
+ const int sampleMaxY = roundToPrevMultiple(maxY, ySampling);
+ const int sampleMinX = roundToNextMultiple(dataWindow.min.x, xSampling);
+ const int sampleMaxX = roundToPrevMultiple(dataWindow.max.x, xSampling);
+
+ for (int y = sampleMinY; y <= sampleMaxY; y+=ySampling)
+ {
+ int nBytes = 0;
+ for (int x = sampleMinX; x <= sampleMaxX; x += xSampling)
+ {
+ nBytes += pixelSize *
+ sampleCount(base, xStride, yStride, x, y);
+ }
+ bytesPerLine[y - dataWindow.min.y] += nBytes;
+ }
+ }
+
+ size_t maxBytesPerLine = 0;
+
+ for (int y = minY; y <= maxY; ++y)
+ if (maxBytesPerLine < bytesPerLine[y - dataWindow.min.y])
+ maxBytesPerLine = bytesPerLine[y - dataWindow.min.y];
+
+ return maxBytesPerLine;
+}
+
+
+size_t
+bytesPerDeepLineTable (const Header &header,
+ char* base,
+ int xStride,
+ int yStride,
+ vector<size_t> &bytesPerLine)
+{
+ return bytesPerDeepLineTable(header,
+ header.dataWindow().min.y,
+ header.dataWindow().max.y,
+ base,
+ xStride,
+ yStride,
+ bytesPerLine);
+}
+
void
offsetInLineBufferTable (const vector<size_t> &bytesPerLine,
- int linesInLineBuffer,
- vector<size_t> &offsetInLineBuffer)
+ int scanline1, int scanline2,
+ int linesInLineBuffer,
+ vector<size_t> &offsetInLineBuffer)
{
offsetInLineBuffer.resize (bytesPerLine.size());
size_t offset = 0;
- for (int i = 0; i < bytesPerLine.size(); ++i)
+ for (int i = scanline1; i <= scanline2; ++i)
{
- if (i % linesInLineBuffer == 0)
- offset = 0;
+ if (i % linesInLineBuffer == 0)
+ offset = 0;
- offsetInLineBuffer[i] = offset;
- offset += bytesPerLine[i];
+ offsetInLineBuffer[i] = offset;
+ offset += bytesPerLine[i];
}
}
+void
+offsetInLineBufferTable (const vector<size_t> &bytesPerLine,
+ int linesInLineBuffer,
+ vector<size_t> &offsetInLineBuffer)
+{
+ offsetInLineBufferTable (bytesPerLine,
+ 0, bytesPerLine.size() - 1,
+ linesInLineBuffer,
+ offsetInLineBuffer);
+}
+
+
int
lineBufferMinY (int y, int minY, int linesInLineBuffer)
{
void
copyIntoFrameBuffer (const char *& readPtr,
- char * writePtr,
- char * endPtr,
+ char * writePtr,
+ char * endPtr,
size_t xStride,
- bool fill,
- double fillValue,
+ bool fill,
+ double fillValue,
Compressor::Format format,
PixelType typeInFrameBuffer,
PixelType typeInFile)
switch (typeInFrameBuffer)
{
- case UINT:
-
+ case OPENEXR_IMF_INTERNAL_NAMESPACE::UINT:
+
{
unsigned int fillVal = (unsigned int) (fillValue);
}
break;
- case HALF:
+ case OPENEXR_IMF_INTERNAL_NAMESPACE::HALF:
{
half fillVal = half (fillValue);
}
break;
- case FLOAT:
+ case OPENEXR_IMF_INTERNAL_NAMESPACE::FLOAT:
{
float fillVal = float (fillValue);
default:
- throw Iex::ArgExc ("Unknown pixel data type.");
+ throw IEX_NAMESPACE::ArgExc ("Unknown pixel data type.");
}
}
else if (format == Compressor::XDR)
switch (typeInFrameBuffer)
{
- case UINT:
-
+ case OPENEXR_IMF_INTERNAL_NAMESPACE::UINT:
+
switch (typeInFile)
{
- case UINT:
+ case OPENEXR_IMF_INTERNAL_NAMESPACE::UINT:
while (writePtr <= endPtr)
{
}
break;
- case HALF:
+ case OPENEXR_IMF_INTERNAL_NAMESPACE::HALF:
while (writePtr <= endPtr)
{
}
break;
- case FLOAT:
+ case OPENEXR_IMF_INTERNAL_NAMESPACE::FLOAT:
while (writePtr <= endPtr)
{
writePtr += xStride;
}
break;
+
+ default:
+ throw IEX_NAMESPACE::ArgExc ("Unknown pixel data type.");
}
break;
- case HALF:
+ case OPENEXR_IMF_INTERNAL_NAMESPACE::HALF:
switch (typeInFile)
{
- case UINT:
+ case OPENEXR_IMF_INTERNAL_NAMESPACE::UINT:
while (writePtr <= endPtr)
{
writePtr += xStride;
}
break;
-
- case HALF:
+
+ case OPENEXR_IMF_INTERNAL_NAMESPACE::HALF:
while (writePtr <= endPtr)
{
}
break;
- case FLOAT:
+ case OPENEXR_IMF_INTERNAL_NAMESPACE::FLOAT:
while (writePtr <= endPtr)
{
writePtr += xStride;
}
break;
+ default:
+
+ throw IEX_NAMESPACE::ArgExc ("Unknown pixel data type.");
}
break;
- case FLOAT:
+ case OPENEXR_IMF_INTERNAL_NAMESPACE::FLOAT:
switch (typeInFile)
{
- case UINT:
+ case OPENEXR_IMF_INTERNAL_NAMESPACE::UINT:
while (writePtr <= endPtr)
{
}
break;
- case HALF:
+ case OPENEXR_IMF_INTERNAL_NAMESPACE::HALF:
while (writePtr <= endPtr)
{
}
break;
- case FLOAT:
+ case OPENEXR_IMF_INTERNAL_NAMESPACE::FLOAT:
while (writePtr <= endPtr)
{
writePtr += xStride;
}
break;
+ default:
+
+ throw IEX_NAMESPACE::ArgExc ("Unknown pixel data type.");
}
break;
default:
- throw Iex::ArgExc ("Unknown pixel data type.");
+ throw IEX_NAMESPACE::ArgExc ("Unknown pixel data type.");
}
}
else
switch (typeInFrameBuffer)
{
- case UINT:
-
+ case OPENEXR_IMF_INTERNAL_NAMESPACE::UINT:
+
switch (typeInFile)
{
- case UINT:
+ case OPENEXR_IMF_INTERNAL_NAMESPACE::UINT:
while (writePtr <= endPtr)
{
}
break;
- case HALF:
+ case OPENEXR_IMF_INTERNAL_NAMESPACE::HALF:
while (writePtr <= endPtr)
{
}
break;
- case FLOAT:
+ case OPENEXR_IMF_INTERNAL_NAMESPACE::FLOAT:
while (writePtr <= endPtr)
{
writePtr += xStride;
}
break;
+
+ default:
+
+ throw IEX_NAMESPACE::ArgExc ("Unknown pixel data type.");
}
break;
- case HALF:
+ case OPENEXR_IMF_INTERNAL_NAMESPACE::HALF:
switch (typeInFile)
{
- case UINT:
+ case OPENEXR_IMF_INTERNAL_NAMESPACE::UINT:
while (writePtr <= endPtr)
{
}
break;
- case HALF:
-
- while (writePtr <= endPtr)
- {
- *(half *) writePtr = *(half *)readPtr;
- readPtr += sizeof (half);
- writePtr += xStride;
+ case OPENEXR_IMF_INTERNAL_NAMESPACE::HALF:
+
+ // If we're tightly packed, just memcpy
+ if (xStride == sizeof(half)) {
+ int numBytes = endPtr-writePtr+sizeof(half);
+ memcpy(writePtr, readPtr, numBytes);
+ readPtr += numBytes;
+ writePtr += numBytes;
+ } else {
+ while (writePtr <= endPtr)
+ {
+ *(half *) writePtr = *(half *)readPtr;
+ readPtr += sizeof (half);
+ writePtr += xStride;
+ }
}
break;
- case FLOAT:
+ case OPENEXR_IMF_INTERNAL_NAMESPACE::FLOAT:
while (writePtr <= endPtr)
{
writePtr += xStride;
}
break;
+ default:
+
+ throw IEX_NAMESPACE::ArgExc ("Unknown pixel data type.");
}
break;
- case FLOAT:
+ case OPENEXR_IMF_INTERNAL_NAMESPACE::FLOAT:
switch (typeInFile)
{
- case UINT:
+ case OPENEXR_IMF_INTERNAL_NAMESPACE::UINT:
while (writePtr <= endPtr)
{
}
break;
- case HALF:
+ case OPENEXR_IMF_INTERNAL_NAMESPACE::HALF:
while (writePtr <= endPtr)
{
}
break;
- case FLOAT:
+ case OPENEXR_IMF_INTERNAL_NAMESPACE::FLOAT:
while (writePtr <= endPtr)
{
writePtr += xStride;
}
break;
+ default:
+
+ throw IEX_NAMESPACE::ArgExc ("Unknown pixel data type.");
+ }
+ break;
+
+ default:
+
+ throw IEX_NAMESPACE::ArgExc ("Unknown pixel data type.");
+ }
+ }
+}
+
+void
+copyIntoDeepFrameBuffer (const char *& readPtr,
+ char * base,
+ const char* sampleCountBase,
+ ptrdiff_t sampleCountXStride,
+ ptrdiff_t sampleCountYStride,
+ int y, int minX, int maxX,
+ int xOffsetForSampleCount,
+ int yOffsetForSampleCount,
+ int xOffsetForData,
+ int yOffsetForData,
+ ptrdiff_t sampleStride,
+ ptrdiff_t xPointerStride,
+ ptrdiff_t yPointerStride,
+ bool fill,
+ double fillValue,
+ Compressor::Format format,
+ PixelType typeInFrameBuffer,
+ PixelType typeInFile)
+{
+ //
+ // Copy a horizontal row of pixels from an input
+ // file's line or tile buffer to a frame buffer.
+ //
+
+ if (fill)
+ {
+ //
+ // The file contains no data for this channel.
+ // Store a default value in the frame buffer.
+ //
+
+ switch (typeInFrameBuffer)
+ {
+ case OPENEXR_IMF_INTERNAL_NAMESPACE::UINT:
+
+ {
+ unsigned int fillVal = (unsigned int) (fillValue);
+
+ for (int x = minX; x <= maxX; x++)
+ {
+ char* writePtr = *(char **)(base+(y-yOffsetForData)*yPointerStride + (x-xOffsetForData)*xPointerStride);
+ if(writePtr)
+ {
+ int count = sampleCount(sampleCountBase,
+ sampleCountXStride,
+ sampleCountYStride,
+ x - xOffsetForSampleCount,
+ y - yOffsetForSampleCount);
+ for (int i = 0; i < count; i++)
+ {
+ *(unsigned int *) writePtr = fillVal;
+ writePtr += sampleStride;
+ }
+ }
+ }
+ }
+ break;
+
+ case OPENEXR_IMF_INTERNAL_NAMESPACE::HALF:
+
+ {
+ half fillVal = half (fillValue);
+
+ for (int x = minX; x <= maxX; x++)
+ {
+ char* writePtr = *(char **)(base+(y-yOffsetForData)*yPointerStride + (x-xOffsetForData)*xPointerStride);
+
+ if(writePtr)
+ {
+ int count = sampleCount(sampleCountBase,
+ sampleCountXStride,
+ sampleCountYStride,
+ x - xOffsetForSampleCount,
+ y - yOffsetForSampleCount);
+ for (int i = 0; i < count; i++)
+ {
+ *(half *) writePtr = fillVal;
+ writePtr += sampleStride;
+ }
+ }
+ }
+ }
+ break;
+
+ case OPENEXR_IMF_INTERNAL_NAMESPACE::FLOAT:
+
+ {
+ float fillVal = float (fillValue);
+
+ for (int x = minX; x <= maxX; x++)
+ {
+ char* writePtr = *(char **)(base+(y-yOffsetForData)*yPointerStride + (x-xOffsetForData)*xPointerStride);
+
+ if(writePtr)
+ {
+ int count = sampleCount(sampleCountBase,
+ sampleCountXStride,
+ sampleCountYStride,
+ x - xOffsetForSampleCount,
+ y - yOffsetForSampleCount);
+ for (int i = 0; i < count; i++)
+ {
+ *(float *) writePtr = fillVal;
+ writePtr += sampleStride;
+ }
+ }
+ }
+ }
+ break;
+
+ default:
+
+ throw IEX_NAMESPACE::ArgExc ("Unknown pixel data type.");
+ }
+ }
+ else if (format == Compressor::XDR)
+ {
+ //
+ // The the line or tile buffer is in XDR format.
+ //
+ // Convert the pixels from the file's machine-
+ // independent representation, and store the
+ // results in the frame buffer.
+ //
+
+ switch (typeInFrameBuffer)
+ {
+ case OPENEXR_IMF_INTERNAL_NAMESPACE::UINT:
+
+ switch (typeInFile)
+ {
+ case OPENEXR_IMF_INTERNAL_NAMESPACE::UINT:
+
+ for (int x = minX; x <= maxX; x++)
+ {
+ char* writePtr = *(char **)(base+(y-yOffsetForData)*yPointerStride + (x-xOffsetForData)*xPointerStride);
+
+ int count = sampleCount(sampleCountBase,
+ sampleCountXStride,
+ sampleCountYStride,
+ x - xOffsetForSampleCount,
+ y - yOffsetForSampleCount);
+ if(writePtr)
+ {
+
+ for (int i = 0; i < count; i++)
+ {
+ Xdr::read <CharPtrIO> (readPtr, *(unsigned int *) writePtr);
+ writePtr += sampleStride;
+ }
+ }else{
+ Xdr::skip <CharPtrIO> (readPtr,count*Xdr::size<unsigned int>());
+ }
+ }
+ break;
+
+ case OPENEXR_IMF_INTERNAL_NAMESPACE::HALF:
+
+ for (int x = minX; x <= maxX; x++)
+ {
+ char* writePtr = *(char **)(base+(y-yOffsetForData)*yPointerStride + (x-xOffsetForData)*xPointerStride);
+
+ int count = sampleCount(sampleCountBase,
+ sampleCountXStride,
+ sampleCountYStride,
+ x - xOffsetForSampleCount,
+ y - yOffsetForSampleCount);
+ if(writePtr)
+ {
+
+ for (int i = 0; i < count; i++)
+ {
+ half h;
+ Xdr::read <CharPtrIO> (readPtr, h);
+ *(unsigned int *) writePtr = halfToUint (h);
+ writePtr += sampleStride;
+ }
+ }else{
+ Xdr::skip <CharPtrIO> (readPtr,count*Xdr::size<half>());
+ }
+ }
+ break;
+
+ case OPENEXR_IMF_INTERNAL_NAMESPACE::FLOAT:
+
+ for (int x = minX; x <= maxX; x++)
+ {
+ char* writePtr = *(char **)(base+(y-yOffsetForData)*yPointerStride + (x-xOffsetForData)*xPointerStride);
+
+ int count = sampleCount(sampleCountBase,
+ sampleCountXStride,
+ sampleCountYStride,
+ x - xOffsetForSampleCount,
+ y - yOffsetForSampleCount);
+
+ if(writePtr)
+ {
+ for (int i = 0; i < count; i++)
+ {
+ float f;
+ Xdr::read <CharPtrIO> (readPtr, f);
+ *(unsigned int *)writePtr = floatToUint (f);
+ writePtr += sampleStride;
+ }
+ }else{
+ Xdr::skip <CharPtrIO> (readPtr,count*Xdr::size<float>());
+ }
+
+ }
+ break;
+ default:
+ throw IEX_NAMESPACE::ArgExc ("Unknown pixel data type.");
+ }
+ break;
+
+ case OPENEXR_IMF_INTERNAL_NAMESPACE::HALF:
+
+ switch (typeInFile)
+ {
+ case OPENEXR_IMF_INTERNAL_NAMESPACE::UINT:
+
+ for (int x = minX; x <= maxX; x++)
+ {
+ char* writePtr = *(char **)(base+(y-yOffsetForData)*yPointerStride + (x-xOffsetForData)*xPointerStride);
+
+ int count = sampleCount(sampleCountBase,
+ sampleCountXStride,
+ sampleCountYStride,
+ x - xOffsetForSampleCount,
+ y - yOffsetForSampleCount);
+ if(writePtr)
+ {
+
+ for (int i = 0; i < count; i++)
+ {
+ unsigned int ui;
+ Xdr::read <CharPtrIO> (readPtr, ui);
+ *(half *) writePtr = uintToHalf (ui);
+ writePtr += sampleStride;
+ }
+ }else{
+ Xdr::skip <CharPtrIO> (readPtr,count*Xdr::size<unsigned int>());
+ }
+ }
+ break;
+
+ case OPENEXR_IMF_INTERNAL_NAMESPACE::HALF:
+
+ for (int x = minX; x <= maxX; x++)
+ {
+ char* writePtr = *(char **)(base+(y-yOffsetForData)*yPointerStride + (x-xOffsetForData)*xPointerStride);
+
+ int count = sampleCount(sampleCountBase,
+ sampleCountXStride,
+ sampleCountYStride,
+ x - xOffsetForSampleCount,
+ y - yOffsetForSampleCount);
+ if(writePtr)
+ {
+
+ for (int i = 0; i < count; i++)
+ {
+ Xdr::read <CharPtrIO> (readPtr, *(half *) writePtr);
+ writePtr += sampleStride;
+ }
+ }else{
+ Xdr::skip <CharPtrIO> (readPtr,count*Xdr::size<half>());
+ }
+ }
+ break;
+
+ case OPENEXR_IMF_INTERNAL_NAMESPACE::FLOAT:
+
+ for (int x = minX; x <= maxX; x++)
+ {
+ char* writePtr = *(char **) (base+(y-yOffsetForData)*yPointerStride + (x-xOffsetForData)*xPointerStride);
+
+ int count = sampleCount(sampleCountBase,
+ sampleCountXStride,
+ sampleCountYStride,
+ x - xOffsetForSampleCount,
+ y - yOffsetForSampleCount);
+ if(writePtr)
+ {
+ for (int i = 0; i < count; i++)
+ {
+ float f;
+ Xdr::read <CharPtrIO> (readPtr, f);
+ *(half *) writePtr = floatToHalf (f);
+ writePtr += sampleStride;
+ }
+ }else{
+ Xdr::skip <CharPtrIO> (readPtr,count*Xdr::size<float>());
+ }
+ }
+ break;
+ default:
+
+ throw IEX_NAMESPACE::ArgExc ("Unknown pixel data type.");
+ }
+ break;
+
+ case OPENEXR_IMF_INTERNAL_NAMESPACE::FLOAT:
+
+ switch (typeInFile)
+ {
+ case OPENEXR_IMF_INTERNAL_NAMESPACE::UINT:
+
+ for (int x = minX; x <= maxX; x++)
+ {
+ char* writePtr = *(char **)(base+(y-yOffsetForData)*yPointerStride + (x-xOffsetForData)*xPointerStride);
+
+ int count = sampleCount(sampleCountBase,
+ sampleCountXStride,
+ sampleCountYStride,
+ x - xOffsetForSampleCount,
+ y - yOffsetForSampleCount);
+ if(writePtr)
+ {
+ for (int i = 0; i < count; i++)
+ {
+ unsigned int ui;
+ Xdr::read <CharPtrIO> (readPtr, ui);
+ *(float *) writePtr = float (ui);
+ writePtr += sampleStride;
+ }
+ }else{
+ Xdr::skip <CharPtrIO> (readPtr,count*Xdr::size<unsigned int>());
+ }
+ }
+ break;
+
+ case OPENEXR_IMF_INTERNAL_NAMESPACE::HALF:
+
+ for (int x = minX; x <= maxX; x++)
+ {
+ char* writePtr = *(char **)(base+(y-yOffsetForData)*yPointerStride + (x-xOffsetForData)*xPointerStride);
+
+ int count = sampleCount(sampleCountBase,
+ sampleCountXStride,
+ sampleCountYStride,
+ x - xOffsetForSampleCount,
+ y - yOffsetForSampleCount);
+ if(writePtr)
+ {
+
+ for (int i = 0; i < count; i++)
+ {
+ half h;
+ Xdr::read <CharPtrIO> (readPtr, h);
+ *(float *) writePtr = float (h);
+ writePtr += sampleStride;
+ }
+
+ }else{
+ Xdr::skip <CharPtrIO> (readPtr,count*Xdr::size<half>());
+ }
+ }
+ break;
+
+ case OPENEXR_IMF_INTERNAL_NAMESPACE::FLOAT:
+
+ for (int x = minX; x <= maxX; x++)
+ {
+ char* writePtr = *(char **)(base+(y-yOffsetForData)*yPointerStride + (x-xOffsetForData)*xPointerStride);
+
+ int count = sampleCount(sampleCountBase,
+ sampleCountXStride,
+ sampleCountYStride,
+ x - xOffsetForSampleCount,
+ y - yOffsetForSampleCount);
+ if(writePtr)
+ {
+
+ for (int i = 0; i < count; i++)
+ {
+ Xdr::read <CharPtrIO> (readPtr, *(float *) writePtr);
+ writePtr += sampleStride;
+ }
+ } else{
+ Xdr::skip <CharPtrIO> (readPtr,count*Xdr::size<float>());
+ }
+
+ }
+ break;
+ default:
+
+ throw IEX_NAMESPACE::ArgExc ("Unknown pixel data type.");
+ }
+ break;
+
+ default:
+
+ throw IEX_NAMESPACE::ArgExc ("Unknown pixel data type.");
+ }
+ }
+ else
+ {
+ //
+ // The the line or tile buffer is in NATIVE format.
+ // Copy the results into the frame buffer.
+ //
+
+ switch (typeInFrameBuffer)
+ {
+ case OPENEXR_IMF_INTERNAL_NAMESPACE::UINT:
+
+ switch (typeInFile)
+ {
+ case OPENEXR_IMF_INTERNAL_NAMESPACE::UINT:
+
+ for (int x = minX; x <= maxX; x++)
+ {
+ char* writePtr = *(char **)(base+(y-yOffsetForData)*yPointerStride + (x-xOffsetForData)*xPointerStride);
+
+ int count = sampleCount(sampleCountBase,
+ sampleCountXStride,
+ sampleCountYStride,
+ x - xOffsetForSampleCount,
+ y - yOffsetForSampleCount);
+
+ if(writePtr)
+ {
+ for (int i = 0; i < count; i++)
+ {
+ for (size_t i = 0; i < sizeof (unsigned int); ++i)
+ writePtr[i] = readPtr[i];
+
+ readPtr += sizeof (unsigned int);
+ writePtr += sampleStride;
+ }
+ }else{
+ readPtr+=sizeof(unsigned int)*count;
+ }
+ }
+ break;
+
+ case OPENEXR_IMF_INTERNAL_NAMESPACE::HALF:
+
+ for (int x = minX; x <= maxX; x++)
+ {
+ char* writePtr = *(char **)(base+(y-yOffsetForData)*yPointerStride + (x-xOffsetForData)*xPointerStride);
+
+ int count = sampleCount(sampleCountBase,
+ sampleCountXStride,
+ sampleCountYStride,
+ x - xOffsetForSampleCount,
+ y - yOffsetForSampleCount);
+
+ if(writePtr)
+ {
+ for (int i = 0; i < count; i++)
+ {
+ half h = *(half *) readPtr;
+ *(unsigned int *) writePtr = halfToUint (h);
+ readPtr += sizeof (half);
+ writePtr += sampleStride;
+ }
+ }else{
+ readPtr+=sizeof(half)*count;
+ }
+ }
+ break;
+
+ case OPENEXR_IMF_INTERNAL_NAMESPACE::FLOAT:
+
+ for (int x = minX; x <= maxX; x++)
+ {
+ char* writePtr = *(char **)(base+(y-yOffsetForData)*yPointerStride + (x-xOffsetForData)*xPointerStride);
+
+ int count = sampleCount(sampleCountBase,
+ sampleCountXStride,
+ sampleCountYStride,
+ x - xOffsetForSampleCount,
+ y - yOffsetForSampleCount);
+
+ if(writePtr)
+ {
+
+ for (int i = 0; i < count; i++)
+ {
+ float f;
+
+ for (size_t i = 0; i < sizeof (float); ++i)
+ ((char *)&f)[i] = readPtr[i];
+
+ *(unsigned int *)writePtr = floatToUint (f);
+ readPtr += sizeof (float);
+ writePtr += sampleStride;
+ }
+ }else{
+ readPtr+=sizeof(float)*count;
+ }
+ }
+ break;
+ default:
+
+ throw IEX_NAMESPACE::ArgExc ("Unknown pixel data type.");
+ }
+ break;
+
+ case OPENEXR_IMF_INTERNAL_NAMESPACE::HALF:
+
+ switch (typeInFile)
+ {
+ case OPENEXR_IMF_INTERNAL_NAMESPACE::UINT:
+
+ for (int x = minX; x <= maxX; x++)
+ {
+ char* writePtr = *(char **)(base+(y-yOffsetForData)*yPointerStride + (x-xOffsetForData)*xPointerStride);
+
+ int count = sampleCount(sampleCountBase,
+ sampleCountXStride,
+ sampleCountYStride,
+ x - xOffsetForSampleCount,
+ y - yOffsetForSampleCount);
+
+ if(writePtr)
+ {
+ for (int i = 0; i < count; i++)
+ {
+ unsigned int ui;
+
+ for (size_t i = 0; i < sizeof (unsigned int); ++i)
+ ((char *)&ui)[i] = readPtr[i];
+
+ *(half *) writePtr = uintToHalf (ui);
+ readPtr += sizeof (unsigned int);
+ writePtr += sampleStride;
+ }
+ }else{
+ readPtr+=sizeof(unsigned int)*count;
+ }
+ }
+ break;
+
+ case OPENEXR_IMF_INTERNAL_NAMESPACE::HALF:
+
+ for (int x = minX; x <= maxX; x++)
+ {
+ char* writePtr = *(char **)(base+(y-yOffsetForData)*yPointerStride + (x-xOffsetForData)*xPointerStride);
+
+ int count = sampleCount(sampleCountBase,
+ sampleCountXStride,
+ sampleCountYStride,
+ x - xOffsetForSampleCount,
+ y - yOffsetForSampleCount);
+
+ if(writePtr)
+ {
+ for (int i = 0; i < count; i++)
+ {
+ *(half *) writePtr = *(half *)readPtr;
+ readPtr += sizeof (half);
+ writePtr += sampleStride;
+ }
+ }else{
+ readPtr+=sizeof(half)*count;
+ }
+ }
+ break;
+
+ case OPENEXR_IMF_INTERNAL_NAMESPACE::FLOAT:
+
+ for (int x = minX; x <= maxX; x++)
+ {
+ char* writePtr = *(char **)(base+(y-yOffsetForData)*yPointerStride + (x-xOffsetForData)*xPointerStride);
+
+ int count = sampleCount(sampleCountBase,
+ sampleCountXStride,
+ sampleCountYStride,
+ x - xOffsetForSampleCount,
+ y - yOffsetForSampleCount);
+
+ if(writePtr)
+ {
+ for (int i = 0; i < count; i++)
+ {
+ float f;
+
+ for (size_t i = 0; i < sizeof (float); ++i)
+ ((char *)&f)[i] = readPtr[i];
+
+ *(half *) writePtr = floatToHalf (f);
+ readPtr += sizeof (float);
+ writePtr += sampleStride;
+ }
+ }else{
+ readPtr+=sizeof(float)*count;
+ }
+ }
+ break;
+ default:
+
+ throw IEX_NAMESPACE::ArgExc ("Unknown pixel data type.");
+ }
+ break;
+
+ case OPENEXR_IMF_INTERNAL_NAMESPACE::FLOAT:
+
+ switch (typeInFile)
+ {
+ case OPENEXR_IMF_INTERNAL_NAMESPACE::UINT:
+
+ for (int x = minX; x <= maxX; x++)
+ {
+ char* writePtr = *(char **)(base+(y-yOffsetForData)*yPointerStride + (x-xOffsetForData)*xPointerStride);
+
+ int count = sampleCount(sampleCountBase,
+ sampleCountXStride,
+ sampleCountYStride,
+ x - xOffsetForSampleCount,
+ y - yOffsetForSampleCount);
+
+ if(writePtr)
+ {
+ for (int i = 0; i < count; i++)
+ {
+ unsigned int ui;
+
+ for (size_t i = 0; i < sizeof (unsigned int); ++i)
+ ((char *)&ui)[i] = readPtr[i];
+
+ *(float *) writePtr = float (ui);
+ readPtr += sizeof (unsigned int);
+ writePtr += sampleStride;
+ }
+ }else{
+ readPtr+=sizeof(unsigned int)*count;
+ }
+ }
+ break;
+
+ case OPENEXR_IMF_INTERNAL_NAMESPACE::HALF:
+
+ for (int x = minX; x <= maxX; x++)
+ {
+ char* writePtr = *(char **)(base+(y-yOffsetForData)*yPointerStride + (x-xOffsetForData)*xPointerStride);
+
+ int count = sampleCount(sampleCountBase,
+ sampleCountXStride,
+ sampleCountYStride,
+ x - xOffsetForSampleCount,
+ y - yOffsetForSampleCount);
+
+ if(writePtr)
+ {
+ for (int i = 0; i < count; i++)
+ {
+ half h = *(half *) readPtr;
+ *(float *) writePtr = float (h);
+ readPtr += sizeof (half);
+ writePtr += sampleStride;
+ }
+ }else{
+ readPtr+=sizeof(half)*count;
+ }
+ }
+ break;
+
+ case OPENEXR_IMF_INTERNAL_NAMESPACE::FLOAT:
+
+ for (int x = minX; x <= maxX; x++)
+ {
+ char* writePtr = *(char **)(base+(y-yOffsetForData)*yPointerStride + (x-xOffsetForData)*xPointerStride);
+
+ int count = sampleCount(sampleCountBase,
+ sampleCountXStride,
+ sampleCountYStride,
+ x - xOffsetForSampleCount,
+ y - yOffsetForSampleCount);
+
+ if(writePtr)
+ {
+ for (int i = 0; i < count; i++)
+ {
+ for (size_t i = 0; i < sizeof (float); ++i)
+ writePtr[i] = readPtr[i];
+
+ readPtr += sizeof (float);
+ writePtr += sampleStride;
+ }
+ }else{
+ readPtr+=sizeof(float)*count;
+ }
+ }
+ break;
+ default:
+
+ throw IEX_NAMESPACE::ArgExc ("Unknown pixel data type.");
}
break;
default:
- throw Iex::ArgExc ("Unknown pixel data type.");
+ throw IEX_NAMESPACE::ArgExc ("Unknown pixel data type.");
}
}
}
void
skipChannel (const char *& readPtr,
PixelType typeInFile,
- size_t xSize)
+ size_t xSize)
{
switch (typeInFile)
{
- case UINT:
-
+ case OPENEXR_IMF_INTERNAL_NAMESPACE::UINT:
+
Xdr::skip <CharPtrIO> (readPtr, Xdr::size <unsigned int> () * xSize);
break;
- case HALF:
+ case OPENEXR_IMF_INTERNAL_NAMESPACE::HALF:
Xdr::skip <CharPtrIO> (readPtr, Xdr::size <half> () * xSize);
break;
- case FLOAT:
+ case OPENEXR_IMF_INTERNAL_NAMESPACE::FLOAT:
Xdr::skip <CharPtrIO> (readPtr, Xdr::size <float> () * xSize);
break;
default:
- throw Iex::ArgExc ("Unknown pixel data type.");
+ throw IEX_NAMESPACE::ArgExc ("Unknown pixel data type.");
}
}
void
convertInPlace (char *& writePtr,
const char *& readPtr,
- PixelType type,
+ PixelType type,
size_t numPixels)
{
switch (type)
{
- case UINT:
-
- for (int j = 0; j < numPixels; ++j)
+ case OPENEXR_IMF_INTERNAL_NAMESPACE::UINT:
+
+ for (size_t j = 0; j < numPixels; ++j)
{
Xdr::write <CharPtrIO> (writePtr, *(const unsigned int *) readPtr);
readPtr += sizeof(unsigned int);
}
break;
-
- case HALF:
-
- for (int j = 0; j < numPixels; ++j)
- {
+
+ case OPENEXR_IMF_INTERNAL_NAMESPACE::HALF:
+
+ for (size_t j = 0; j < numPixels; ++j)
+ {
Xdr::write <CharPtrIO> (writePtr, *(const half *) readPtr);
readPtr += sizeof(half);
}
break;
-
- case FLOAT:
-
- for (int j = 0; j < numPixels; ++j)
+
+ case OPENEXR_IMF_INTERNAL_NAMESPACE::FLOAT:
+
+ for (size_t j = 0; j < numPixels; ++j)
{
Xdr::write <CharPtrIO> (writePtr, *(const float *) readPtr);
readPtr += sizeof(float);
}
break;
-
+
default:
-
- throw Iex::ArgExc ("Unknown pixel data type.");
+
+ throw IEX_NAMESPACE::ArgExc ("Unknown pixel data type.");
}
}
void
copyFromFrameBuffer (char *& writePtr,
- const char *& readPtr,
+ const char *& readPtr,
const char * endPtr,
- size_t xStride,
+ size_t xStride,
Compressor::Format format,
- PixelType type)
+ PixelType type)
{
//
// Copy a horizontal row of pixels from a frame
switch (type)
{
- case UINT:
+ case OPENEXR_IMF_INTERNAL_NAMESPACE::UINT:
while (readPtr <= endPtr)
{
}
break;
- case HALF:
+ case OPENEXR_IMF_INTERNAL_NAMESPACE::HALF:
while (readPtr <= endPtr)
{
}
break;
- case FLOAT:
+ case OPENEXR_IMF_INTERNAL_NAMESPACE::FLOAT:
while (readPtr <= endPtr)
{
default:
- throw Iex::ArgExc ("Unknown pixel data type.");
+ throw IEX_NAMESPACE::ArgExc ("Unknown pixel data type.");
}
}
else
switch (type)
{
- case UINT:
+ case OPENEXR_IMF_INTERNAL_NAMESPACE::UINT:
while (readPtr <= endPtr)
{
}
break;
- case HALF:
+ case OPENEXR_IMF_INTERNAL_NAMESPACE::HALF:
while (readPtr <= endPtr)
{
}
break;
- case FLOAT:
+ case OPENEXR_IMF_INTERNAL_NAMESPACE::FLOAT:
while (readPtr <= endPtr)
{
readPtr += xStride;
}
break;
+
+ default:
+
+ throw IEX_NAMESPACE::ArgExc ("Unknown pixel data type.");
+ }
+ }
+}
+
+void
+copyFromDeepFrameBuffer (char *& writePtr,
+ const char * base,
+ char* sampleCountBase,
+ ptrdiff_t sampleCountXStride,
+ ptrdiff_t sampleCountYStride,
+ int y, int xMin, int xMax,
+ int xOffsetForSampleCount,
+ int yOffsetForSampleCount,
+ int xOffsetForData,
+ int yOffsetForData,
+ ptrdiff_t sampleStride,
+ ptrdiff_t dataXStride,
+ ptrdiff_t dataYStride,
+ Compressor::Format format,
+ PixelType type)
+{
+ //
+ // Copy a horizontal row of pixels from a frame
+ // buffer to an output file's line or tile buffer.
+ //
+
+ if (format == Compressor::XDR)
+ {
+ //
+ // The the line or tile buffer is in XDR format.
+ //
+
+ switch (type)
+ {
+ case OPENEXR_IMF_INTERNAL_NAMESPACE::UINT:
+
+ for (int x = xMin; x <= xMax; x++)
+ {
+ unsigned int count =
+ sampleCount(sampleCountBase,
+ sampleCountXStride,
+ sampleCountYStride,
+ x - xOffsetForSampleCount,
+ y - yOffsetForSampleCount);
+ const char* ptr = base + (y-yOffsetForData) * dataYStride + (x-xOffsetForData) * dataXStride;
+ const char* readPtr = ((const char**) ptr)[0];
+ for (unsigned int i = 0; i < count; i++)
+ {
+ Xdr::write <CharPtrIO> (writePtr,
+ *(const unsigned int *) readPtr);
+ readPtr += sampleStride;
+ }
+ }
+ break;
+
+ case OPENEXR_IMF_INTERNAL_NAMESPACE::HALF:
+
+ for (int x = xMin; x <= xMax; x++)
+ {
+ unsigned int count =
+ sampleCount(sampleCountBase,
+ sampleCountXStride,
+ sampleCountYStride,
+ x - xOffsetForSampleCount,
+ y - yOffsetForSampleCount);
+ const char* ptr = base + (y-yOffsetForData) * dataYStride + (x-xOffsetForData) * dataXStride;
+ const char* readPtr = ((const char**) ptr)[0];
+ for (unsigned int i = 0; i < count; i++)
+ {
+ Xdr::write <CharPtrIO> (writePtr, *(const half *) readPtr);
+ readPtr += sampleStride;
+ }
+ }
+ break;
+
+ case OPENEXR_IMF_INTERNAL_NAMESPACE::FLOAT:
+
+ for (int x = xMin; x <= xMax; x++)
+ {
+ unsigned int count =
+ sampleCount(sampleCountBase,
+ sampleCountXStride,
+ sampleCountYStride,
+ x - xOffsetForSampleCount,
+ y - yOffsetForSampleCount);
+ const char* ptr = base + (y-yOffsetForData) * dataYStride + (x-xOffsetForData) * dataXStride;
+
+ const char* readPtr = ((const char**) ptr)[0];
+ for (unsigned int i = 0; i < count; i++)
+ {
+ Xdr::write <CharPtrIO> (writePtr, *(const float *) readPtr);
+ readPtr += sampleStride;
+ }
+ }
+ break;
default:
- throw Iex::ArgExc ("Unknown pixel data type.");
+ throw IEX_NAMESPACE::ArgExc ("Unknown pixel data type.");
+ }
+ }
+ else
+ {
+ //
+ // The the line or tile buffer is in NATIVE format.
+ //
+
+ switch (type)
+ {
+ case OPENEXR_IMF_INTERNAL_NAMESPACE::UINT:
+
+ for (int x = xMin; x <= xMax; x++)
+ {
+ unsigned int count =
+ sampleCount(sampleCountBase,
+ sampleCountXStride,
+ sampleCountYStride,
+ x - xOffsetForSampleCount,
+ y - yOffsetForSampleCount);
+
+ const char* ptr = base + (y-yOffsetForData) * dataYStride + (x-xOffsetForData) * dataXStride;
+ const char* readPtr = ((const char**) ptr)[0];
+ for (unsigned int i = 0; i < count; i++)
+ {
+ for (size_t j = 0; j < sizeof (unsigned int); ++j)
+ *writePtr++ = readPtr[j];
+
+ readPtr += sampleStride;
+ }
+ }
+ break;
+
+ case OPENEXR_IMF_INTERNAL_NAMESPACE::HALF:
+
+ for (int x = xMin; x <= xMax; x++)
+ {
+ unsigned int count =
+ sampleCount(sampleCountBase,
+ sampleCountXStride,
+ sampleCountYStride,
+ x - xOffsetForSampleCount,
+ y - yOffsetForSampleCount);
+ const char* ptr = base + (y-yOffsetForData) * dataYStride + (x-xOffsetForData) * dataXStride;
+ const char* readPtr = ((const char**) ptr)[0];
+ for (unsigned int i = 0; i < count; i++)
+ {
+ *(half *) writePtr = *(const half *) readPtr;
+ writePtr += sizeof (half);
+ readPtr += sampleStride;
+ }
+ }
+ break;
+
+ case OPENEXR_IMF_INTERNAL_NAMESPACE::FLOAT:
+
+ for (int x = xMin; x <= xMax; x++)
+ {
+ unsigned int count =
+ sampleCount(sampleCountBase,
+ sampleCountXStride,
+ sampleCountYStride,
+ x - xOffsetForSampleCount,
+ y - yOffsetForSampleCount);
+
+ const char* ptr = base + (y-yOffsetForData) * dataYStride + (x-xOffsetForData) * dataXStride;
+ const char* readPtr = ((const char**) ptr)[0];
+ for (unsigned int i = 0; i < count; i++)
+ {
+ for (size_t j = 0; j < sizeof (float); ++j)
+ *writePtr++ = readPtr[j];
+
+ readPtr += sampleStride;
+ }
+ }
+ break;
+
+ default:
+
+ throw IEX_NAMESPACE::ArgExc ("Unknown pixel data type.");
}
}
}
void
fillChannelWithZeroes (char *& writePtr,
- Compressor::Format format,
- PixelType type,
- size_t xSize)
+ Compressor::Format format,
+ PixelType type,
+ size_t xSize)
{
if (format == Compressor::XDR)
{
switch (type)
{
- case UINT:
+ case OPENEXR_IMF_INTERNAL_NAMESPACE::UINT:
- for (int j = 0; j < xSize; ++j)
+ for (size_t j = 0; j < xSize; ++j)
Xdr::write <CharPtrIO> (writePtr, (unsigned int) 0);
break;
- case HALF:
+ case OPENEXR_IMF_INTERNAL_NAMESPACE::HALF:
- for (int j = 0; j < xSize; ++j)
+ for (size_t j = 0; j < xSize; ++j)
Xdr::write <CharPtrIO> (writePtr, (half) 0);
break;
- case FLOAT:
+ case OPENEXR_IMF_INTERNAL_NAMESPACE::FLOAT:
- for (int j = 0; j < xSize; ++j)
+ for (size_t j = 0; j < xSize; ++j)
Xdr::write <CharPtrIO> (writePtr, (float) 0);
break;
-
+
default:
- throw Iex::ArgExc ("Unknown pixel data type.");
+ throw IEX_NAMESPACE::ArgExc ("Unknown pixel data type.");
}
}
else
switch (type)
{
- case UINT:
+ case OPENEXR_IMF_INTERNAL_NAMESPACE::UINT:
- for (int j = 0; j < xSize; ++j)
+ for (size_t j = 0; j < xSize; ++j)
{
static const unsigned int ui = 0;
}
break;
- case HALF:
+ case OPENEXR_IMF_INTERNAL_NAMESPACE::HALF:
- for (int j = 0; j < xSize; ++j)
+ for (size_t j = 0; j < xSize; ++j)
{
*(half *) writePtr = half (0);
writePtr += sizeof (half);
}
break;
- case FLOAT:
+ case OPENEXR_IMF_INTERNAL_NAMESPACE::FLOAT:
- for (int j = 0; j < xSize; ++j)
+ for (size_t j = 0; j < xSize; ++j)
{
static const float f = 0;
*writePtr++ = ((char *) &f)[i];
}
break;
-
+
default:
- throw Iex::ArgExc ("Unknown pixel data type.");
+ throw IEX_NAMESPACE::ArgExc ("Unknown pixel data type.");
}
}
}
-} // namespace Imf
+bool
+usesLongNames (const Header &header)
+{
+ //
+ // If an OpenEXR file contains any attribute names, attribute type names
+ // or channel names longer than 31 characters, then the file cannot be
+ // read by older versions of the IlmImf library (up to OpenEXR 1.6.1).
+ // Before writing the file header, we check if the header contains
+ // any names longer than 31 characters; if it does, then we set the
+ // LONG_NAMES_FLAG in the file version number. Older versions of the
+ // IlmImf library will refuse to read files that have the LONG_NAMES_FLAG
+ // set. Without the flag, older versions of the library would mis-
+ // interpret the file as broken.
+ //
+
+ for (Header::ConstIterator i = header.begin();
+ i != header.end();
+ ++i)
+ {
+ if (strlen (i.name()) >= 32 || strlen (i.attribute().typeName()) >= 32)
+ return true;
+ }
+
+ const ChannelList &channels = header.channels();
+
+ for (ChannelList::ConstIterator i = channels.begin();
+ i != channels.end();
+ ++i)
+ {
+ if (strlen (i.name()) >= 32)
+ return true;
+ }
+
+ return false;
+}
+
+int
+getScanlineChunkOffsetTableSize(const Header& header)
+{
+ const Box2i &dataWindow = header.dataWindow();
+
+ vector<size_t> bytesPerLine;
+ size_t maxBytesPerLine = bytesPerLineTable (header,
+ bytesPerLine);
+
+ Compressor* compressor = newCompressor(header.compression(),
+ maxBytesPerLine,
+ header);
+
+ int linesInBuffer = numLinesInBuffer (compressor);
+
+ int lineOffsetSize = (dataWindow.max.y - dataWindow.min.y +
+ linesInBuffer) / linesInBuffer;
+
+ delete compressor;
+
+ return lineOffsetSize;
+}
+
+//
+// Located in ImfTiledMisc.cpp
+//
+int
+getTiledChunkOffsetTableSize(const Header& header);
+
+int
+getChunkOffsetTableSize(const Header& header,bool ignore_attribute)
+{
+ if(!ignore_attribute && header.hasChunkCount())
+ {
+ return header.chunkCount();
+ }
+
+ if(header.hasType() && !isSupportedType(header.type()))
+ {
+ throw IEX_NAMESPACE::ArgExc ("unsupported header type to "
+ "get chunk offset table size");
+ }
+ if (isTiled(header.type()) == false)
+ return getScanlineChunkOffsetTableSize(header);
+ else
+ return getTiledChunkOffsetTableSize(header);
+
+}
+
+
+OPENEXR_IMF_INTERNAL_NAMESPACE_SOURCE_EXIT
//
// Copyright (c) 2002, Industrial Light & Magic, a division of Lucas
// Digital Ltd. LLC
-//
+//
// All rights reserved.
-//
+//
// Redistribution and use in source and binary forms, with or without
// modification, are permitted provided that the following conditions are
// met:
// distribution.
// * Neither the name of Industrial Light & Magic nor the names of
// its contributors may be used to endorse or promote products derived
-// from this software without specific prior written permission.
-//
+// from this software without specific prior written permission.
+//
// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
//
//-----------------------------------------------------------------------------
-#include <ImfPixelType.h>
+#include "ImfPixelType.h"
+#include "ImfCompressor.h"
+#include "ImfArray.h"
+#include "ImfNamespace.h"
+#include "ImfExport.h"
+#include "ImfForward.h"
+
+#include <cstddef>
#include <vector>
-#include <ImfCompressor.h>
-namespace Imf {
-class Header;
+OPENEXR_IMF_INTERNAL_NAMESPACE_HEADER_ENTER
+
//
// Return the size of a single value of the indicated type,
// in the machine's native format.
//
+IMF_EXPORT
int pixelTypeSize (PixelType type);
// interval [2, 6].
//
+IMF_EXPORT
int numSamples (int s, int a, int b);
// the pixel data are tightly packed).
//
+IMF_EXPORT
size_t bytesPerLineTable (const Header &header,
- std::vector<size_t> &bytesPerLine);
+ std::vector<size_t> &bytesPerLine);
+
+
+//
+// Get the sample count for pixel (x, y) using the array base
+// pointer, xStride and yStride.
+//
+
+inline
+int&
+sampleCount(char* base, int xStride, int yStride, int x, int y)
+{
+ char* ptr = base + y * yStride + x * xStride;
+ int* intPtr = (int*) ptr;
+
+ return *intPtr;
+}
+
+
+inline
+const int&
+sampleCount(const char* base, int xStride, int yStride, int x, int y)
+{
+ const char* ptr = base + y * yStride + x * xStride;
+ int* intPtr = (int*) ptr;
+
+ return *intPtr;
+}
+
+//
+// Build a table that lists, for each scanline in a DEEP file's
+// data window, how many bytes are required to store all
+// pixels in all channels in scanlines ranged in [minY, maxY]
+// (assuming that the pixel data are tightly packed).
+//
+
+IMF_EXPORT
+size_t bytesPerDeepLineTable (const Header &header,
+ int minY, int maxY,
+ const char* base,
+ int xStride,
+ int yStride,
+ std::vector<size_t> &bytesPerLine);
+
+
+//
+// Build a table that lists, for each scanline in a DEEP file's
+// data window, how many bytes are required to store all
+// pixels in all channels in every scanline (assuming that
+// the pixel data are tightly packed).
+//
+
+IMF_EXPORT
+size_t bytesPerDeepLineTable (const Header &header,
+ char* base,
+ int xStride,
+ int yStride,
+ std::vector<size_t> &bytesPerLine);
+
//
// For scanline-based files, pixels are read or written in
// in multi-scanline blocks. Internally, class OutputFile
// and class ScanLineInputFile store a block of scan lines
// in a "line buffer". Function offsetInLineBufferTable()
-// builds a table that lists, for each scan line in a file's
-// data window, the location of the pixel data for the scanline
-// relative to the beginning of the line buffer.
+// builds a table that lists, scanlines within range
+// [scanline1, scanline2], the location of the pixel data
+// for the scanline relative to the beginning of the line buffer,
+// where scanline1 = 0 represents the first line in the DATA WINDOW.
+// The one without specifying the range will make scanline1 = 0
+// and scanline2 = bytesPerLine.size().
//
+IMF_EXPORT
+void offsetInLineBufferTable (const std::vector<size_t> &bytesPerLine,
+ int scanline1, int scanline2,
+ int linesInLineBuffer,
+ std::vector<size_t> &offsetInLineBuffer);
+
+IMF_EXPORT
void offsetInLineBufferTable (const std::vector<size_t> &bytesPerLine,
- int linesInLineBuffer,
- std::vector<size_t> &offsetInLineBuffer);
+ int linesInLineBuffer,
+ std::vector<size_t> &offsetInLineBuffer);
//
// For a scanline-based file, compute the range of scanlines
// (minY is the minimum y coordinate of the file's data window.)
//
-int lineBufferMinY (int y, int minY, int linesInLineBuffer);
-int lineBufferMaxY (int y, int minY, int linesInLineBuffer);
+IMF_EXPORT int lineBufferMinY (int y, int minY, int linesInLineBuffer);
+IMF_EXPORT int lineBufferMaxY (int y, int minY, int linesInLineBuffer);
//
// If compressor is 0, return Compressor::XDR.
//
+IMF_EXPORT
Compressor::Format defaultFormat (Compressor *compressor);
// or uncompress at once. If compressor is 0, return 1.
//
+IMF_EXPORT
int numLinesInBuffer (Compressor *compressor);
// typeInFile the pixel data type in the input file's channel
//
+IMF_EXPORT
void copyIntoFrameBuffer (const char *&readPtr,
- char *writePtr,
+ char *writePtr,
char *endPtr,
- size_t xStride,
- bool fill,
+ size_t xStride,
+ bool fill,
double fillValue,
- Compressor::Format format,
+ Compressor::Format format,
PixelType typeInFrameBuffer,
PixelType typeInFile);
+
+//
+// Copy a single channel of a horizontal row of pixels from an
+// input file's internal line buffer or tile buffer into a
+// frame buffer slice. If necessary, perform on-the-fly data
+// type conversion.
+//
+// readPtr initially points to the beginning of the
+// data in the line or tile buffer. readPtr
+// is advanced as the pixel data are copied;
+// when copyIntoFrameBuffer() returns,
+// readPtr points just past the end of the
+// copied data.
+//
+// base point to each pixel in the framebuffer
+//
+// sampleCountBase, provide the number of samples in each pixel
+// sampleCountXStride,
+// sampleCountYStride
+//
+// y the scanline to copy. The coordinate is
+// relative to the datawindow.min.y.
+//
+// minX, maxX used to indicate which pixels in the scanline
+// will be copied.
+//
+// xOffsetForSampleCount, used to offset the sample count array
+// yOffsetForSampleCount, and the base array.
+// xOffsetForData,
+// yOffsetForData
+//
+// xStride the xStride for the frame buffer slice
+//
+// format indicates if the line or tile buffer is
+// in NATIVE or XDR format.
+//
+// typeInFrameBuffer the pixel data type of the frame buffer slice
+//
+// typeInFile the pixel data type in the input file's channel
+//
+
+IMF_EXPORT
+void copyIntoDeepFrameBuffer (const char *& readPtr,
+ char * base,
+ const char* sampleCountBase,
+ ptrdiff_t sampleCountXStride,
+ ptrdiff_t sampleCountYStride,
+ int y, int minX, int maxX,
+ int xOffsetForSampleCount,
+ int yOffsetForSampleCount,
+ int xOffsetForData,
+ int yOffsetForData,
+ ptrdiff_t xStride,
+ ptrdiff_t xPointerStride,
+ ptrdiff_t yPointerStride,
+ bool fill,
+ double fillValue,
+ Compressor::Format format,
+ PixelType typeInFrameBuffer,
+ PixelType typeInFile);
+
+
//
// Given a pointer into a an input file's line buffer or tile buffer,
// skip over the data for xSize pixels of type typeInFile.
// skipped data.
//
+IMF_EXPORT
void skipChannel (const char *&readPtr,
- PixelType typeInFile,
- size_t xSize);
+ PixelType typeInFile,
+ size_t xSize);
//
// Convert an array of pixel data from the machine's native
// type the pixel data type
//
// numPixels number of pixels in the input and output arrays
-//
+//
+IMF_EXPORT
void convertInPlace (char *&toPtr,
- const char *&fromPtr,
- PixelType type,
+ const char *&fromPtr,
+ PixelType type,
size_t numPixels);
//
// data type conversion)
//
+IMF_EXPORT
void copyFromFrameBuffer (char *&writePtr,
- const char *&readPtr,
+ const char *&readPtr,
const char *endPtr,
- size_t xStride,
+ size_t xStride,
Compressor::Format format,
- PixelType type);
+ PixelType type);
+
+//
+// Copy a single channel of a horizontal row of pixels from a
+// a frame buffer in a deep data file into an output file's
+// internal line buffer or tile buffer.
+//
+// writePtr initially points to the beginning of the
+// data in the line or tile buffer. writePtr
+// is advanced as the pixel data are copied;
+// when copyFromDeepFrameBuffer() returns,
+// writePtr points just past the end of the
+// copied data.
+//
+// base the start pointer of each pixel in this channel.
+// It points to the real data in FrameBuffer.
+// It is different for different channels.
+// dataWindowMinX and dataWindowMinY are involved in
+// locating for base.
+//
+// sampleCountBase, used to locate the position to get
+// sampleCountXStride, the number of samples for each pixel.
+// sampleCountYStride Used to determine how far we should
+// read based on the pointer provided by base.
+//
+// y the scanline to copy. If we are dealing
+// with a tiled deep file, then probably a portion
+// of the scanline is copied.
+//
+// xMin, xMax used to indicate which pixels in the scanline
+// will be copied.
+//
+// xOffsetForSampleCount, used to offset the sample count array
+// yOffsetForSampleCount, and the base array.
+// xOffsetForData,
+// yOffsetForData
+//
+// xStride the xStride for the frame buffer slice
+//
+// format indicates if the line or tile buffer is
+// in NATIVE or XDR format.
+//
+// type the pixel data type in the frame buffer
+// and in the output file's channel (function
+// copyFromFrameBuffer() doesn't do on-the-fly
+// data type conversion)
+//
+
+IMF_EXPORT
+void copyFromDeepFrameBuffer (char *& writePtr,
+ const char * base,
+ char* sampleCountBase,
+ ptrdiff_t sampleCountXStride,
+ ptrdiff_t sampleCountYStride,
+ int y, int xMin, int xMax,
+ int xOffsetForSampleCount,
+ int yOffsetForSampleCount,
+ int xOffsetForData,
+ int yOffsetForData,
+ ptrdiff_t sampleStride,
+ ptrdiff_t xStrideForData,
+ ptrdiff_t yStrideForData,
+ Compressor::Format format,
+ PixelType type);
//
// Fill part of an output file's line buffer or tile buffer with
// xSize number of pixels to be filled with zeroes.
//
+IMF_EXPORT
void fillChannelWithZeroes (char *&writePtr,
- Compressor::Format format,
- PixelType type,
- size_t xSize);
+ Compressor::Format format,
+ PixelType type,
+ size_t xSize);
+
+IMF_EXPORT
+bool usesLongNames (const Header &header);
+
+
+//
+// compute size of chunk offset table - if ignore_attribute set to true
+// will compute from the image size and layout, rather than the attribute
+// The default behaviour is to read the attribute
+//
+
+IMF_EXPORT
+int getChunkOffsetTableSize(const Header& header,bool ignore_attribute=false);
+
+OPENEXR_IMF_INTERNAL_NAMESPACE_HEADER_EXIT
-} // namespace Imf
#endif
--- /dev/null
+///////////////////////////////////////////////////////////////////////////
+//
+// Copyright (c) 2011, Industrial Light & Magic, a division of Lucas
+// Digital Ltd. LLC
+//
+// All rights reserved.
+//
+// Redistribution and use in source and binary forms, with or without
+// modification, are permitted provided that the following conditions are
+// met:
+// * Redistributions of source code must retain the above copyright
+// notice, this list of conditions and the following disclaimer.
+// * Redistributions in binary form must reproduce the above
+// copyright notice, this list of conditions and the following disclaimer
+// in the documentation and/or other materials provided with the
+// distribution.
+// * Neither the name of Industrial Light & Magic nor the names of
+// its contributors may be used to endorse or promote products derived
+// from this software without specific prior written permission.
+//
+// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+//
+///////////////////////////////////////////////////////////////////////////
+
+#include "ImfMultiPartInputFile.h"
+
+#include "ImfTimeCodeAttribute.h"
+#include "ImfChromaticitiesAttribute.h"
+#include "ImfBoxAttribute.h"
+#include "ImfFloatAttribute.h"
+#include "ImfStdIO.h"
+#include "ImfTileOffsets.h"
+#include "ImfMisc.h"
+#include "ImfTiledMisc.h"
+#include "ImfInputStreamMutex.h"
+#include "ImfInputPartData.h"
+#include "ImfPartType.h"
+#include "ImfInputFile.h"
+#include "ImfScanLineInputFile.h"
+#include "ImfTiledInputFile.h"
+#include "ImfDeepScanLineInputFile.h"
+#include "ImfDeepTiledInputFile.h"
+#include "ImfVersion.h"
+
+#include <OpenEXRConfig.h>
+#include <IlmThread.h>
+#include <IlmThreadMutex.h>
+
+#include <Iex.h>
+#include <map>
+#include <set>
+
+OPENEXR_IMF_INTERNAL_NAMESPACE_SOURCE_ENTER
+
+using ILMTHREAD_NAMESPACE::Mutex;
+using ILMTHREAD_NAMESPACE::Lock;
+using IMATH_NAMESPACE::Box2i;
+
+using std::vector;
+using std::map;
+using std::set;
+using std::string;
+
+namespace
+{
+ // Controls whether we error out in the event of shared attribute
+ // inconsistency in the input file
+ static const bool strictSharedAttribute = true;
+}
+
+struct MultiPartInputFile::Data: public InputStreamMutex
+{
+ int version; // Version of this file.
+ bool deleteStream; // If we should delete the stream during destruction.
+ vector<InputPartData*> parts; // Data to initialize Output files.
+ int numThreads; // Number of threads
+ bool reconstructChunkOffsetTable; // If we should reconstruct
+ // the offset table if it's broken.
+ std::map<int,GenericInputFile*> _inputFiles;
+ std::vector<Header> _headers;
+
+
+ void chunkOffsetReconstruction(OPENEXR_IMF_INTERNAL_NAMESPACE::IStream& is, const std::vector<InputPartData*>& parts);
+
+ void readChunkOffsetTables(bool reconstructChunkOffsetTable);
+
+ bool checkSharedAttributesValues(const Header & src,
+ const Header & dst,
+ std::vector<std::string> & conflictingAttributes) const;
+
+ TileOffsets* createTileOffsets(const Header& header);
+
+ InputPartData* getPart(int partNumber);
+
+ Data (bool deleteStream, int numThreads, bool reconstructChunkOffsetTable):
+ InputStreamMutex(),
+ deleteStream (deleteStream),
+ numThreads (numThreads),
+ reconstructChunkOffsetTable(reconstructChunkOffsetTable)
+ {
+ }
+
+ ~Data()
+ {
+ if (deleteStream) delete is;
+
+ for (size_t i = 0; i < parts.size(); i++)
+ delete parts[i];
+ }
+
+ template <class T>
+ T* createInputPartT(int partNumber)
+ {
+
+ }
+};
+
+MultiPartInputFile::MultiPartInputFile(const char fileName[],
+ int numThreads,
+ bool reconstructChunkOffsetTable):
+ _data(new Data(true, numThreads, reconstructChunkOffsetTable))
+{
+ try
+ {
+ _data->is = new StdIFStream (fileName);
+ initialize();
+ }
+ catch (IEX_NAMESPACE::BaseExc &e)
+ {
+ delete _data;
+
+ REPLACE_EXC (e, "Cannot read image file "
+ "\"" << fileName << "\". " << e.what());
+ throw;
+ }
+ catch (...)
+ {
+ delete _data;
+ throw;
+ }
+}
+
+MultiPartInputFile::MultiPartInputFile (OPENEXR_IMF_INTERNAL_NAMESPACE::IStream& is,
+ int numThreads,
+ bool reconstructChunkOffsetTable):
+ _data(new Data(false, numThreads, reconstructChunkOffsetTable))
+{
+ try
+ {
+ _data->is = &is;
+ initialize();
+ }
+ catch (IEX_NAMESPACE::BaseExc &e)
+ {
+ delete _data;
+
+ REPLACE_EXC (e, "Cannot read image file "
+ "\"" << is.fileName() << "\". " << e.what());
+ throw;
+ }
+ catch (...)
+ {
+ delete _data;
+ throw;
+ }
+}
+
+template<class T>
+T*
+MultiPartInputFile::getInputPart(int partNumber)
+{
+ Lock lock(*_data);
+ if (_data->_inputFiles.find(partNumber) == _data->_inputFiles.end())
+ {
+ T* file = new T(_data->getPart(partNumber));
+ _data->_inputFiles.insert(std::make_pair(partNumber, (GenericInputFile*) file));
+ return file;
+ }
+ else return (T*) _data->_inputFiles[partNumber];
+}
+
+
+template InputFile* MultiPartInputFile::getInputPart<InputFile>(int);
+template TiledInputFile* MultiPartInputFile::getInputPart<TiledInputFile>(int);
+template DeepScanLineInputFile* MultiPartInputFile::getInputPart<DeepScanLineInputFile>(int);
+template DeepTiledInputFile* MultiPartInputFile::getInputPart<DeepTiledInputFile>(int);
+
+InputPartData*
+MultiPartInputFile::getPart(int partNumber)
+{
+ return _data->getPart(partNumber);
+}
+
+
+
+const Header &
+ MultiPartInputFile::header(int n) const
+{
+ return _data->_headers[n];
+}
+
+
+
+MultiPartInputFile::~MultiPartInputFile()
+{
+ for (map<int, GenericInputFile*>::iterator it = _data->_inputFiles.begin();
+ it != _data->_inputFiles.end(); it++)
+ {
+ delete it->second;
+ }
+
+ delete _data;
+}
+
+
+bool
+MultiPartInputFile::Data::checkSharedAttributesValues(const Header & src,
+ const Header & dst,
+ vector<string> & conflictingAttributes) const
+{
+ conflictingAttributes.clear();
+
+ bool conflict = false;
+
+ //
+ // Display Window
+ //
+ if (src.displayWindow() != dst.displayWindow())
+ {
+ conflict = true;
+ conflictingAttributes.push_back ("displayWindow");
+ }
+
+
+ //
+ // Pixel Aspect Ratio
+ //
+ if (src.pixelAspectRatio() != dst.pixelAspectRatio())
+ {
+ conflict = true;
+ conflictingAttributes.push_back ("pixelAspectRatio");
+ }
+
+
+ //
+ // Timecode
+ //
+ const TimeCodeAttribute * srcTimeCode = src.findTypedAttribute<
+ TimeCodeAttribute> (TimeCodeAttribute::staticTypeName());
+ const TimeCodeAttribute * dstTimeCode = dst.findTypedAttribute<
+ TimeCodeAttribute> (TimeCodeAttribute::staticTypeName());
+
+ if (dstTimeCode)
+ {
+ if ( (srcTimeCode && (srcTimeCode->value() != dstTimeCode->value())) ||
+ (!srcTimeCode))
+ {
+ conflict = true;
+ conflictingAttributes.push_back (TimeCodeAttribute::staticTypeName());
+ }
+ }
+
+ //
+ // Chromaticities
+ //
+ const ChromaticitiesAttribute * srcChrom = src.findTypedAttribute<
+ ChromaticitiesAttribute> (ChromaticitiesAttribute::staticTypeName());
+ const ChromaticitiesAttribute * dstChrom = dst.findTypedAttribute<
+ ChromaticitiesAttribute> (ChromaticitiesAttribute::staticTypeName());
+
+ if (dstChrom)
+ {
+ if ( (srcChrom && (srcChrom->value() != dstChrom->value())) ||
+ (!srcChrom))
+ {
+ conflict = true;
+ conflictingAttributes.push_back (ChromaticitiesAttribute::staticTypeName());
+ }
+ }
+
+
+ return conflict;
+}
+
+
+void
+MultiPartInputFile::initialize()
+{
+ readMagicNumberAndVersionField(*_data->is, _data->version);
+
+ bool multipart = isMultiPart(_data->version);
+ bool tiled = isTiled(_data->version);
+
+ //
+ // Multipart files don't have and shouldn't have the tiled bit set.
+ //
+
+ if (tiled && multipart)
+ throw IEX_NAMESPACE::InputExc ("Multipart files cannot have the tiled bit set");
+
+
+ int pos = 0;
+ while (true)
+ {
+ Header header;
+ header.readFrom(*_data->is, _data->version);
+
+ //
+ // If we read nothing then we stop reading.
+ //
+
+ if (header.readsNothing())
+ {
+ pos++;
+ break;
+ }
+
+ _data->_headers.push_back(header);
+
+ if(multipart == false)
+ break;
+ }
+
+ //
+ // Perform usual check on headers.
+ //
+
+ for (size_t i = 0; i < _data->_headers.size(); i++)
+ {
+ //
+ // Silently invent a type if the file is a single part regular image.
+ //
+
+ if( _data->_headers[i].hasType() == false )
+ {
+ if(multipart)
+
+ throw IEX_NAMESPACE::ArgExc ("Every header in a multipart file should have a type");
+
+ _data->_headers[i].setType(tiled ? TILEDIMAGE : SCANLINEIMAGE);
+ }
+ else
+ {
+
+ //
+ // Silently fix the header type if it's wrong
+ // (happens when a regular Image file written by EXR_2.0 is rewritten by an older library,
+ // so doesn't effect deep image types)
+ //
+
+ if(!multipart && !isNonImage(_data->version))
+ {
+ _data->_headers[i].setType(tiled ? TILEDIMAGE : SCANLINEIMAGE);
+ }
+ }
+
+
+
+ if( _data->_headers[i].hasName() == false )
+ {
+ if(multipart)
+ throw IEX_NAMESPACE::ArgExc ("Every header in a multipart file should have a name");
+ }
+
+ if (isTiled(_data->_headers[i].type()))
+ _data->_headers[i].sanityCheck(true, multipart);
+ else
+ _data->_headers[i].sanityCheck(false, multipart);
+ }
+
+ //
+ // Check name uniqueness.
+ //
+
+ if (multipart)
+ {
+ set<string> names;
+ for (size_t i = 0; i < _data->_headers.size(); i++)
+ {
+
+ if (names.find(_data->_headers[i].name()) != names.end())
+ {
+ throw IEX_NAMESPACE::InputExc ("Header name " + _data->_headers[i].name() +
+ " is not a unique name.");
+ }
+ names.insert(_data->_headers[i].name());
+ }
+ }
+
+ //
+ // Check shared attributes compliance.
+ //
+
+ if (multipart && strictSharedAttribute)
+ {
+ for (size_t i = 1; i < _data->_headers.size(); i++)
+ {
+ vector <string> attrs;
+ if (_data->checkSharedAttributesValues (_data->_headers[0], _data->_headers[i], attrs))
+ {
+ string attrNames;
+ for (size_t j=0; j<attrs.size(); j++)
+ attrNames += " " + attrs[j];
+ throw IEX_NAMESPACE::InputExc ("Header name " + _data->_headers[i].name() +
+ " has non-conforming shared attributes: "+
+ attrNames);
+ }
+ }
+ }
+
+ //
+ // Create InputParts and read chunk offset tables.
+ //
+
+ for (size_t i = 0; i < _data->_headers.size(); i++)
+ _data->parts.push_back(
+ new InputPartData(_data, _data->_headers[i], i, _data->numThreads, _data->version));
+
+ _data->readChunkOffsetTables(_data->reconstructChunkOffsetTable);
+}
+
+TileOffsets*
+MultiPartInputFile::Data::createTileOffsets(const Header& header)
+{
+ //
+ // Get the dataWindow information
+ //
+
+ const Box2i &dataWindow = header.dataWindow();
+ int minX = dataWindow.min.x;
+ int maxX = dataWindow.max.x;
+ int minY = dataWindow.min.y;
+ int maxY = dataWindow.max.y;
+
+ //
+ // Precompute level and tile information
+ //
+
+ int* numXTiles;
+ int* numYTiles;
+ int numXLevels, numYLevels;
+ TileDescription tileDesc = header.tileDescription();
+ precalculateTileInfo (tileDesc,
+ minX, maxX,
+ minY, maxY,
+ numXTiles, numYTiles,
+ numXLevels, numYLevels);
+
+ TileOffsets* tileOffsets = new TileOffsets (tileDesc.mode,
+ numXLevels,
+ numYLevels,
+ numXTiles,
+ numYTiles);
+ delete [] numXTiles;
+ delete [] numYTiles;
+
+ return tileOffsets;
+}
+
+
+void
+MultiPartInputFile::Data::chunkOffsetReconstruction(OPENEXR_IMF_INTERNAL_NAMESPACE::IStream& is, const vector<InputPartData*>& parts)
+{
+ //
+ // Reconstruct broken chunk offset tables. Stop once we received any exception.
+ //
+
+ Int64 position = is.tellg();
+
+
+ //
+ // check we understand all the parts available: if not, we cannot continue
+ // exceptions thrown here should trickle back up to the constructor
+ //
+
+ for (size_t i = 0; i < parts.size(); i++)
+ {
+ Header& header=parts[i]->header;
+
+ //
+ // do we have a valid type entry?
+ // we only need them for true multipart files or single part non-image (deep) files
+ //
+ if(!header.hasType() && (isMultiPart(version) || isNonImage(version)))
+ {
+ throw IEX_NAMESPACE::ArgExc("cannot reconstruct incomplete file: part with missing type");
+ }
+ if(!isSupportedType(header.type()))
+ {
+ throw IEX_NAMESPACE::ArgExc("cannot reconstruct incomplete file: part with unknown type "+header.type());
+ }
+ }
+
+
+ // how many chunks should we read? We should stop when we reach the end
+ size_t total_chunks = 0;
+
+ // for tiled-based parts, array of (pointers to) tileOffsets objects
+ // to create mapping between tile coordinates and chunk table indices
+
+
+ vector<TileOffsets*> tileOffsets(parts.size());
+
+ // for scanline-based parts, number of scanlines in each part
+ vector<int> rowsizes(parts.size());
+
+ for(size_t i = 0 ; i < parts.size() ; i++)
+ {
+ total_chunks += parts[i]->chunkOffsets.size();
+ if (isTiled(parts[i]->header.type()))
+ {
+ tileOffsets[i] = createTileOffsets(parts[i]->header);
+ }else{
+ tileOffsets[i] = NULL;
+ // (TODO) fix this so that it doesn't need to be revised for future compression types.
+ switch(parts[i]->header.compression())
+ {
+ case DWAB_COMPRESSION :
+ rowsizes[i] = 256;
+ break;
+ case PIZ_COMPRESSION :
+ case B44_COMPRESSION :
+ case B44A_COMPRESSION :
+ case DWAA_COMPRESSION :
+ rowsizes[i]=32;
+ break;
+ case ZIP_COMPRESSION :
+ case PXR24_COMPRESSION :
+ rowsizes[i]=16;
+ break;
+ case ZIPS_COMPRESSION :
+ case RLE_COMPRESSION :
+ case NO_COMPRESSION :
+ rowsizes[i]=1;
+ break;
+ default :
+ throw(IEX_NAMESPACE::ArgExc("Unknown compression method in chunk offset reconstruction"));
+ }
+ }
+ }
+
+ try
+ {
+
+ //
+ //
+ //
+
+ Int64 chunk_start = position;
+ for (size_t i = 0; i < total_chunks ; i++)
+ {
+ //
+ // do we have a part number?
+ //
+
+ int partNumber = 0;
+ if(isMultiPart(version))
+ {
+ OPENEXR_IMF_INTERNAL_NAMESPACE::Xdr::read <OPENEXR_IMF_INTERNAL_NAMESPACE::StreamIO> (is, partNumber);
+ }
+
+
+
+ if(partNumber<0 || partNumber>int(parts.size()))
+ {
+ // bail here - bad part number
+ throw int();
+ }
+
+ Header& header = parts[partNumber]->header;
+
+ // size of chunk NOT including multipart field
+
+ Int64 size_of_chunk=0;
+
+ if (isTiled(header.type()))
+ {
+ //
+ //
+ //
+ int tilex,tiley,levelx,levely;
+ OPENEXR_IMF_INTERNAL_NAMESPACE::Xdr::read <OPENEXR_IMF_INTERNAL_NAMESPACE::StreamIO> (is, tilex);
+ OPENEXR_IMF_INTERNAL_NAMESPACE::Xdr::read <OPENEXR_IMF_INTERNAL_NAMESPACE::StreamIO> (is, tiley);
+ OPENEXR_IMF_INTERNAL_NAMESPACE::Xdr::read <OPENEXR_IMF_INTERNAL_NAMESPACE::StreamIO> (is, levelx);
+ OPENEXR_IMF_INTERNAL_NAMESPACE::Xdr::read <OPENEXR_IMF_INTERNAL_NAMESPACE::StreamIO> (is, levely);
+
+ //std::cout << "chunk_start for " << tilex <<',' << tiley << ',' << levelx << ' ' << levely << ':' << chunk_start << std::endl;
+
+
+ if(!tileOffsets[partNumber])
+ {
+ // this shouldn't actually happen - we should have allocated a valid
+ // tileOffsets for any part which isTiled
+ throw int();
+
+ }
+
+ if(!tileOffsets[partNumber]->isValidTile(tilex,tiley,levelx,levely))
+ {
+ //std::cout << "invalid tile : aborting\n";
+ throw int();
+ }
+
+ (*tileOffsets[partNumber])(tilex,tiley,levelx,levely)=chunk_start;
+
+ // compute chunk sizes - different procedure for deep tiles and regular
+ // ones
+ if(header.type()==DEEPTILE)
+ {
+ Int64 packed_offset;
+ Int64 packed_sample;
+ OPENEXR_IMF_INTERNAL_NAMESPACE::Xdr::read <OPENEXR_IMF_INTERNAL_NAMESPACE::StreamIO> (is, packed_offset);
+ OPENEXR_IMF_INTERNAL_NAMESPACE::Xdr::read <OPENEXR_IMF_INTERNAL_NAMESPACE::StreamIO> (is, packed_sample);
+
+ //add 40 byte header to packed sizes (tile coordinates, packed sizes, unpacked size)
+ size_of_chunk=packed_offset+packed_sample+40;
+ }
+ else
+ {
+
+ // regular image has 20 bytes of header, 4 byte chunksize;
+ int chunksize;
+ OPENEXR_IMF_INTERNAL_NAMESPACE::Xdr::read <OPENEXR_IMF_INTERNAL_NAMESPACE::StreamIO> (is, chunksize);
+ size_of_chunk=chunksize+20;
+ }
+ }
+ else
+ {
+ int y_coordinate;
+ OPENEXR_IMF_INTERNAL_NAMESPACE::Xdr::read <OPENEXR_IMF_INTERNAL_NAMESPACE::StreamIO> (is, y_coordinate);
+
+ y_coordinate -= header.dataWindow().min.y;
+ y_coordinate /= rowsizes[partNumber];
+
+ if(y_coordinate < 0 || y_coordinate >= int(parts[partNumber]->chunkOffsets.size()))
+ {
+ //std::cout << "aborting reconstruction: bad data " << y_coordinate << endl;
+ //bail to exception catcher: broken scanline
+ throw int();
+ }
+
+ parts[partNumber]->chunkOffsets[y_coordinate]=chunk_start;
+ //std::cout << "chunk_start for " << y_coordinate << ':' << chunk_start << std::endl;
+
+ if(header.type()==DEEPSCANLINE)
+ {
+ Int64 packed_offset;
+ Int64 packed_sample;
+ OPENEXR_IMF_INTERNAL_NAMESPACE::Xdr::read <OPENEXR_IMF_INTERNAL_NAMESPACE::StreamIO> (is, packed_offset);
+ OPENEXR_IMF_INTERNAL_NAMESPACE::Xdr::read <OPENEXR_IMF_INTERNAL_NAMESPACE::StreamIO> (is, packed_sample);
+
+
+ size_of_chunk=packed_offset+packed_sample+28;
+ }
+ else
+ {
+ int chunksize;
+ OPENEXR_IMF_INTERNAL_NAMESPACE::Xdr::read <OPENEXR_IMF_INTERNAL_NAMESPACE::StreamIO> (is, chunksize);
+ size_of_chunk=chunksize+8;
+ }
+
+ }
+
+ if(isMultiPart(version))
+ {
+ chunk_start+=4;
+ }
+
+ chunk_start+=size_of_chunk;
+
+ //std::cout << " next chunk +"<<size_of_chunk << " = " << chunk_start << std::endl;
+
+ is.seekg(chunk_start);
+
+ }
+
+ }
+ catch (...)
+ {
+ //
+ // Suppress all exceptions. This functions is
+ // called only to reconstruct the line offset
+ // table for incomplete files, and exceptions
+ // are likely.
+ //
+ }
+
+ // copy tiled part data back to chunk offsets
+
+ for(size_t partNumber=0;partNumber<parts.size();partNumber++)
+ {
+ if(tileOffsets[partNumber])
+ {
+ size_t pos=0;
+ vector<vector<vector <Int64> > > offsets = tileOffsets[partNumber]->getOffsets();
+ for (size_t l = 0; l < offsets.size(); l++)
+ for (size_t y = 0; y < offsets[l].size(); y++)
+ for (size_t x = 0; x < offsets[l][y].size(); x++)
+ {
+ parts[ partNumber ]->chunkOffsets[pos] = offsets[l][y][x];
+ pos++;
+ }
+ delete tileOffsets[partNumber];
+ }
+ }
+
+ is.clear();
+ is.seekg (position);
+}
+
+InputPartData*
+MultiPartInputFile::Data::getPart(int partNumber)
+{
+ if (partNumber < 0 || partNumber >= (int) parts.size())
+ throw IEX_NAMESPACE::ArgExc ("Part number is not in valid range.");
+ return parts[partNumber];
+}
+
+
+
+void
+MultiPartInputFile::Data::readChunkOffsetTables(bool reconstructChunkOffsetTable)
+{
+ bool brokenPartsExist = false;
+
+ for (size_t i = 0; i < parts.size(); i++)
+ {
+ int chunkOffsetTableSize = getChunkOffsetTableSize(parts[i]->header,false);
+ parts[i]->chunkOffsets.resize(chunkOffsetTableSize);
+
+ for (int j = 0; j < chunkOffsetTableSize; j++)
+ OPENEXR_IMF_INTERNAL_NAMESPACE::Xdr::read <OPENEXR_IMF_INTERNAL_NAMESPACE::StreamIO> (*is, parts[i]->chunkOffsets[j]);
+
+ //
+ // Check chunk offsets, reconstruct if broken.
+ // At first we assume the table is complete.
+ //
+ parts[i]->completed = true;
+ for (int j = 0; j < chunkOffsetTableSize; j++)
+ {
+ if (parts[i]->chunkOffsets[j] <= 0)
+ {
+ brokenPartsExist = true;
+ parts[i]->completed = false;
+ break;
+ }
+ }
+ }
+
+ if (brokenPartsExist && reconstructChunkOffsetTable)
+ chunkOffsetReconstruction(*is, parts);
+}
+
+int
+MultiPartInputFile::version() const
+{
+ return _data->version;
+}
+
+bool
+MultiPartInputFile::partComplete(int part) const
+{
+ return _data->parts[part]->completed;
+}
+
+int
+MultiPartInputFile::parts() const
+{
+ return int(_data->_headers.size());
+}
+
+
+OPENEXR_IMF_INTERNAL_NAMESPACE_SOURCE_EXIT
--- /dev/null
+///////////////////////////////////////////////////////////////////////////
+//
+// Copyright (c) 2011, Industrial Light & Magic, a division of Lucas
+// Digital Ltd. LLC
+//
+// All rights reserved.
+//
+// Redistribution and use in source and binary forms, with or without
+// modification, are permitted provided that the following conditions are
+// met:
+// * Redistributions of source code must retain the above copyright
+// notice, this list of conditions and the following disclaimer.
+// * Redistributions in binary form must reproduce the above
+// copyright notice, this list of conditions and the following disclaimer
+// in the documentation and/or other materials provided with the
+// distribution.
+// * Neither the name of Industrial Light & Magic nor the names of
+// its contributors may be used to endorse or promote products derived
+// from this software without specific prior written permission.
+//
+// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+//
+///////////////////////////////////////////////////////////////////////////
+
+#ifndef IMFMULTIPARTINPUTFILE_H_
+#define IMFMULTIPARTINPUTFILE_H_
+
+#include "ImfGenericInputFile.h"
+#include "ImfNamespace.h"
+#include "ImfForward.h"
+#include "ImfThreading.h"
+#include "ImfExport.h"
+
+OPENEXR_IMF_INTERNAL_NAMESPACE_HEADER_ENTER
+
+
+class MultiPartInputFile : public GenericInputFile
+{
+ public:
+ IMF_EXPORT
+ MultiPartInputFile(const char fileName[],
+ int numThreads = globalThreadCount(),
+ bool reconstructChunkOffsetTable = true);
+
+ IMF_EXPORT
+ MultiPartInputFile(IStream& is,
+ int numThreads = globalThreadCount(),
+ bool reconstructChunkOffsetTable = true);
+
+ IMF_EXPORT
+ virtual ~MultiPartInputFile();
+
+ // ----------------------
+ // Count of number of parts in file
+ // ---------------------
+ IMF_EXPORT
+ int parts() const;
+
+
+ //----------------------
+ // Access to the headers
+ //----------------------
+
+ IMF_EXPORT
+ const Header & header(int n) const;
+
+
+ //----------------------------------
+ // Access to the file format version
+ //----------------------------------
+
+ IMF_EXPORT
+ int version () const;
+
+
+ // =----------------------------------------
+ // Check whether the entire chunk offset
+ // table for the part is written correctly
+ // -----------------------------------------
+ IMF_EXPORT
+ bool partComplete(int part) const;
+
+
+ struct Data;
+
+
+ private:
+ Data* _data;
+
+ MultiPartInputFile(const MultiPartInputFile &); // not implemented
+
+
+ //
+ // used internally by 'Part' types to access individual parts of the multipart file
+ //
+ template<class T> T* getInputPart(int partNumber);
+ InputPartData* getPart(int);
+
+ void initialize();
+
+
+
+
+ friend class InputPart;
+ friend class ScanLineInputPart;
+ friend class TiledInputPart;
+ friend class DeepScanLineInputPart;
+ friend class DeepTiledInputPart;
+
+ //
+ // For backward compatibility.
+ //
+
+ friend class InputFile;
+ friend class TiledInputFile;
+ friend class ScanLineInputFile;
+ friend class DeepScanLineInputFile;
+ friend class DeepTiledInputFile;
+};
+
+
+OPENEXR_IMF_INTERNAL_NAMESPACE_HEADER_EXIT
+
+#endif /* IMFMULTIPARTINPUTFILE_H_ */
--- /dev/null
+///////////////////////////////////////////////////////////////////////////
+//
+// Copyright (c) 2011, Industrial Light & Magic, a division of Lucas
+// Digital Ltd. LLC
+//
+// All rights reserved.
+//
+// Redistribution and use in source and binary forms, with or without
+// modification, are permitted provided that the following conditions are
+// met:
+// * Redistributions of source code must retain the above copyright
+// notice, this list of conditions and the following disclaimer.
+// * Redistributions in binary form must reproduce the above
+// copyright notice, this list of conditions and the following disclaimer
+// in the documentation and/or other materials provided with the
+// distribution.
+// * Neither the name of Industrial Light & Magic nor the names of
+// its contributors may be used to endorse or promote products derived
+// from this software without specific prior written permission.
+//
+// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+//
+///////////////////////////////////////////////////////////////////////////
+
+#include "ImfMultiPartOutputFile.h"
+#include "ImfBoxAttribute.h"
+#include "ImfFloatAttribute.h"
+#include "ImfTimeCodeAttribute.h"
+#include "ImfChromaticitiesAttribute.h"
+#include "ImfOutputPartData.h"
+#include "ImfPartType.h"
+#include "ImfOutputFile.h"
+#include "ImfTiledOutputFile.h"
+#include "ImfThreading.h"
+#include "IlmThreadMutex.h"
+#include "ImfMisc.h"
+#include "ImfStdIO.h"
+#include "ImfDeepScanLineOutputFile.h"
+#include "ImfDeepTiledOutputFile.h"
+#include "ImfOutputStreamMutex.h"
+
+#include "ImfNamespace.h"
+#include <Iex.h>
+
+
+#include <set>
+
+
+OPENEXR_IMF_INTERNAL_NAMESPACE_SOURCE_ENTER
+
+using IMATH_NAMESPACE::Box2i;
+using ILMTHREAD_NAMESPACE::Lock;
+
+
+using std::vector;
+using std::map;
+using std::set;
+
+
+struct MultiPartOutputFile::Data: public OutputStreamMutex
+{
+ vector<OutputPartData*> parts; // Contains data to initialize Output files.
+ bool deleteStream; // If we should delete the stream when destruction.
+ int numThreads; // The number of threads.
+ std::map<int, GenericOutputFile*> _outputFiles;
+ std::vector<Header> _headers;
+
+
+ void headerNameUniquenessCheck (const std::vector<Header> &headers);
+
+ void writeHeadersToFile (const std::vector<Header> &headers);
+
+ void writeChunkTableOffsets (std::vector<OutputPartData*> &parts);
+
+
+ //-------------------------------------
+ // ensure that _headers is valid: called by constructors
+ //-------------------------------------
+ void do_header_sanity_checks(bool overrideSharedAttributes);
+
+ // ------------------------------------------------
+ // Given a source header, we copy over all the 'shared attributes' to
+ // the destination header and remove any conflicting ones.
+ // ------------------------------------------------
+ void overrideSharedAttributesValues (const Header & src,
+ Header & dst);
+
+ // ------------------------------------------------
+ // Given a source header, we check the destination header for any
+ // attributes that are part of the shared attribute set. For attributes
+ // present in both we check the values. For attribute present in
+ // destination but absent in source we return false.
+ // For attributes present in src but missing from dst we return false
+ // and add the attribute to dst.
+ // We return false for all other cases.
+ // If we return true then we also populate the conflictingAttributes
+ // vector with the names of the attributes that failed the above.
+ // ------------------------------------------------
+ bool checkSharedAttributesValues (const Header & src,
+ const Header & dst,
+ std::vector<std::string> & conflictingAttributes) const;
+ Data (bool deleteStream, int numThreads):
+ OutputStreamMutex(),
+ deleteStream (deleteStream),
+ numThreads (numThreads)
+ {
+ }
+
+
+ ~Data()
+ {
+ if (deleteStream) delete os;
+
+ for (size_t i = 0; i < parts.size(); i++)
+ delete parts[i];
+ }
+};
+
+void
+MultiPartOutputFile::Data::do_header_sanity_checks(bool overrideSharedAttributes)
+{
+ size_t parts = _headers.size();
+ if (parts == 0)
+ throw IEX_NAMESPACE::ArgExc ("Empty header list.");
+
+ bool isMultiPart = (parts > 1);
+
+ //
+ // Do part 0 checks first.
+ //
+
+ _headers[0].sanityCheck (_headers[0].hasTileDescription(), isMultiPart);
+
+
+ if (isMultiPart)
+ {
+ // multipart files must contain a chunkCount attribute
+ _headers[0].setChunkCount(getChunkOffsetTableSize(_headers[0],true));
+
+ for (size_t i = 1; i < parts; i++)
+ {
+ if (_headers[i].hasType() == false)
+ throw IEX_NAMESPACE::ArgExc ("Every header in a multipart file should have a type");
+
+
+ _headers[i].setChunkCount(getChunkOffsetTableSize(_headers[i],true));
+ _headers[i].sanityCheck (_headers[i].hasTileDescription(), isMultiPart);
+
+
+ if (overrideSharedAttributes)
+ overrideSharedAttributesValues(_headers[0],_headers[i]);
+ else
+ {
+ std::vector<std::string> conflictingAttributes;
+ bool valid =checkSharedAttributesValues (_headers[0],
+ _headers[i],
+ conflictingAttributes);
+ if (valid)
+ {
+ string excMsg("Conflicting attributes found for header :: ");
+ excMsg += _headers[i].name();
+ for (size_t i=0; i<conflictingAttributes.size(); i++)
+ excMsg += " '" + conflictingAttributes[i] + "' ";
+
+ THROW (IEX_NAMESPACE::ArgExc, excMsg);
+ }
+ }
+ }
+
+ headerNameUniquenessCheck(_headers);
+
+ }else{
+
+ // add chunk count offset to single part data (if not an image)
+
+ if (_headers[0].hasType() && isImage(_headers[0].type()) == false)
+ {
+ _headers[0].setChunkCount(getChunkOffsetTableSize(_headers[0],true));
+ }
+
+ }
+}
+
+
+MultiPartOutputFile::MultiPartOutputFile (const char fileName[],
+ const Header * headers,
+ int parts,
+ bool overrideSharedAttributes,
+ int numThreads)
+:
+ _data (new Data (true, numThreads))
+{
+ // grab headers
+ _data->_headers.resize(parts);
+
+ for(int i=0;i<parts;i++)
+ {
+ _data->_headers[i]=headers[i];
+ }
+ try
+ {
+
+ _data->do_header_sanity_checks(overrideSharedAttributes);
+
+ //
+ // Build parts and write headers and offset tables to file.
+ //
+
+ _data->os = new StdOFStream (fileName);
+ for (size_t i = 0; i < _data->_headers.size(); i++)
+ _data->parts.push_back( new OutputPartData(_data, _data->_headers[i], i, numThreads, parts>1 ) );
+
+ writeMagicNumberAndVersionField(*_data->os, &_data->_headers[0],_data->_headers.size());
+ _data->writeHeadersToFile(_data->_headers);
+ _data->writeChunkTableOffsets(_data->parts);
+ }
+ catch (IEX_NAMESPACE::BaseExc &e)
+ {
+ delete _data;
+
+ REPLACE_EXC (e, "Cannot open image file "
+ "\"" << fileName << "\". " << e.what());
+ throw;
+ }
+ catch (...)
+ {
+ delete _data;
+ throw;
+ }
+}
+
+MultiPartOutputFile::MultiPartOutputFile(OStream& os,
+ const Header* headers,
+ int parts,
+ bool overrideSharedAttributes,
+ int numThreads):
+ _data(new Data(false,numThreads))
+{
+ // grab headers
+ _data->_headers.resize(parts);
+ _data->os=&os;
+
+ for(int i=0;i<parts;i++)
+ {
+ _data->_headers[i]=headers[i];
+ }
+ try
+ {
+
+ _data->do_header_sanity_checks(overrideSharedAttributes);
+
+ //
+ // Build parts and write headers and offset tables to file.
+ //
+
+ for (size_t i = 0; i < _data->_headers.size(); i++)
+ _data->parts.push_back( new OutputPartData(_data, _data->_headers[i], i, numThreads, parts>1 ) );
+
+ writeMagicNumberAndVersionField(*_data->os, &_data->_headers[0],_data->_headers.size());
+ _data->writeHeadersToFile(_data->_headers);
+ _data->writeChunkTableOffsets(_data->parts);
+ }
+ catch (IEX_NAMESPACE::BaseExc &e)
+ {
+ delete _data;
+
+ REPLACE_EXC (e, "Cannot open image stream "
+ "\"" << os.fileName() << "\". " << e.what());
+ throw;
+ }
+ catch (...)
+ {
+ delete _data;
+ throw;
+ }
+}
+
+
+const Header &
+MultiPartOutputFile::header(int n) const
+{
+ if(n<0 || n>int(_data->_headers.size()))
+ {
+ throw IEX_NAMESPACE::ArgExc("MultiPartOutputFile::header called with invalid part number");
+ }
+ return _data->_headers[n];
+}
+
+int
+MultiPartOutputFile::parts() const
+{
+ return _data->_headers.size();
+}
+
+
+MultiPartOutputFile::~MultiPartOutputFile ()
+{
+ for (map<int, GenericOutputFile*>::iterator it = _data->_outputFiles.begin();
+ it != _data->_outputFiles.end(); it++)
+ {
+ delete it->second;
+ }
+
+ delete _data;
+}
+
+template <class T>
+T*
+MultiPartOutputFile::getOutputPart(int partNumber)
+{
+ Lock lock(*_data);
+ if (_data->_outputFiles.find(partNumber) == _data->_outputFiles.end())
+ {
+ T* file = new T(_data->parts[partNumber]);
+ _data->_outputFiles.insert(std::make_pair(partNumber, (GenericOutputFile*) file));
+ return file;
+ }
+ else return (T*) _data->_outputFiles[partNumber];
+}
+
+// instance above function for all four types
+template OutputFile* MultiPartOutputFile::getOutputPart<OutputFile>(int);
+template TiledOutputFile * MultiPartOutputFile::getOutputPart<TiledOutputFile>(int);
+template DeepScanLineOutputFile * MultiPartOutputFile::getOutputPart<DeepScanLineOutputFile> (int);
+template DeepTiledOutputFile * MultiPartOutputFile::getOutputPart<DeepTiledOutputFile> (int);
+
+
+
+void
+MultiPartOutputFile::Data::overrideSharedAttributesValues(const Header & src, Header & dst)
+{
+ //
+ // Display Window
+ //
+ const Box2iAttribute * displayWindow =
+ src.findTypedAttribute<Box2iAttribute> ("displayWindow");
+
+ if (displayWindow)
+ dst.insert ("displayWindow", *displayWindow);
+ else
+ dst.erase ("displayWindow");
+
+
+ //
+ // Pixel Aspect Ratio
+ //
+ const FloatAttribute * pixelAspectRatio =
+ src.findTypedAttribute<FloatAttribute> ("pixelAspectRatio");
+
+ if (pixelAspectRatio)
+ dst.insert ("pixelAspectRatio", *pixelAspectRatio);
+ else
+ dst.erase ("pixelAspectRatio");
+
+
+ //
+ // Timecode
+ //
+ const TimeCodeAttribute * timeCode =
+ src.findTypedAttribute<TimeCodeAttribute> ("timecode");
+
+ if (timeCode)
+ dst.insert ("timecode", *timeCode);
+ else
+ dst.erase ("timecode");
+
+
+ //
+ // Chromaticities
+ //
+ const ChromaticitiesAttribute * chromaticities =
+ src.findTypedAttribute<ChromaticitiesAttribute> ("chromaticities");
+
+ if (chromaticities)
+ dst.insert ("chromaticities", *chromaticities);
+ else
+ dst.erase ("chromaticities");
+
+}
+
+
+bool
+MultiPartOutputFile::Data::checkSharedAttributesValues(const Header & src,
+ const Header & dst,
+ vector<string> & conflictingAttributes) const
+{
+ bool conflict = false;
+
+ //
+ // Display Window
+ //
+ if (src.displayWindow() != dst.displayWindow())
+ {
+ conflict = true;
+ conflictingAttributes.push_back ("displayWindow");
+ }
+
+
+ //
+ // Pixel Aspect Ratio
+ //
+ if (src.pixelAspectRatio() != dst.pixelAspectRatio())
+ {
+ conflict = true;
+ conflictingAttributes.push_back ("pixelAspectRatio");
+ }
+
+
+ //
+ // Timecode
+ //
+ const TimeCodeAttribute * srcTimeCode = src.findTypedAttribute<
+ TimeCodeAttribute> (TimeCodeAttribute::staticTypeName());
+ const TimeCodeAttribute * dstTimeCode = dst.findTypedAttribute<
+ TimeCodeAttribute> (TimeCodeAttribute::staticTypeName());
+
+ if (dstTimeCode)
+ {
+ if ((srcTimeCode && (srcTimeCode->value() != dstTimeCode->value())) ||
+ (!srcTimeCode))
+ {
+ conflict = true;
+ conflictingAttributes.push_back (TimeCodeAttribute::staticTypeName());
+ }
+ }
+
+ //
+ // Chromaticities
+ //
+ const ChromaticitiesAttribute * srcChrom = src.findTypedAttribute<
+ ChromaticitiesAttribute> (ChromaticitiesAttribute::staticTypeName());
+ const ChromaticitiesAttribute * dstChrom = dst.findTypedAttribute<
+ ChromaticitiesAttribute> (ChromaticitiesAttribute::staticTypeName());
+
+ if (dstChrom)
+ {
+ if ( (srcChrom && (srcChrom->value() != dstChrom->value())) ||
+ (!srcChrom))
+ {
+ conflict = true;
+ conflictingAttributes.push_back (ChromaticitiesAttribute::staticTypeName());
+ }
+ }
+
+ return conflict;
+}
+
+
+void
+MultiPartOutputFile::Data::headerNameUniquenessCheck (const vector<Header> &headers)
+{
+ set<string> names;
+ for (size_t i = 0; i < headers.size(); i++)
+ {
+ if (names.find(headers[i].name()) != names.end())
+ throw IEX_NAMESPACE::ArgExc ("Each part should have a unique name.");
+ names.insert(headers[i].name());
+ }
+}
+
+void
+MultiPartOutputFile::Data::writeHeadersToFile (const vector<Header> &headers)
+{
+ for (size_t i = 0; i < headers.size(); i++)
+ {
+
+ // (TODO) consider deep files' preview images here.
+ if (headers[i].type() == TILEDIMAGE)
+ parts[i]->previewPosition = headers[i].writeTo(*os, true);
+ else
+ parts[i]->previewPosition = headers[i].writeTo(*os, false);
+ }
+
+ //
+ // If a multipart file, write zero-length attribute name to mark the end of all headers.
+ //
+
+ if (headers.size() !=1)
+ OPENEXR_IMF_INTERNAL_NAMESPACE::Xdr::write <OPENEXR_IMF_INTERNAL_NAMESPACE::StreamIO> (*os, "");
+}
+
+void
+MultiPartOutputFile::Data::writeChunkTableOffsets (vector<OutputPartData*> &parts)
+{
+ for (size_t i = 0; i < parts.size(); i++)
+ {
+ int chunkTableSize = getChunkOffsetTableSize(parts[i]->header,false);
+
+ Int64 pos = os->tellp();
+
+ if (pos == -1)
+ IEX_NAMESPACE::throwErrnoExc ("Cannot determine current file position (%T).");
+
+ parts[i]->chunkOffsetTablePosition = os->tellp();
+
+ //
+ // Fill in empty data for now. We'll write actual offsets during destruction.
+ //
+
+ for (int j = 0; j < chunkTableSize; j++)
+ {
+ Int64 empty = 0;
+ OPENEXR_IMF_INTERNAL_NAMESPACE::Xdr::write <OPENEXR_IMF_INTERNAL_NAMESPACE::StreamIO> (*os, empty);
+ }
+ }
+}
+
+
+OPENEXR_IMF_INTERNAL_NAMESPACE_SOURCE_EXIT
--- /dev/null
+///////////////////////////////////////////////////////////////////////////
+//
+// Copyright (c) 2011, Industrial Light & Magic, a division of Lucas
+// Digital Ltd. LLC
+//
+// Portions (c) 2012 Weta Digital Ltd
+//
+// All rights reserved.
+//
+// Redistribution and use in source and binary forms, with or without
+// modification, are permitted provided that the following conditions are
+// met:
+// * Redistributions of source code must retain the above copyright
+// notice, this list of conditions and the following disclaimer.
+// * Redistributions in binary form must reproduce the above
+// copyright notice, this list of conditions and the following disclaimer
+// in the documentation and/or other materials provided with the
+// distribution.
+// * Neither the name of Industrial Light & Magic nor the names of
+// its contributors may be used to endorse or promote products derived
+// from this software without specific prior written permission.
+//
+// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+//
+///////////////////////////////////////////////////////////////////////////
+
+#ifndef MULTIPARTOUTPUTFILE_H_
+#define MULTIPARTOUTPUTFILE_H_
+
+#include "ImfHeader.h"
+#include "ImfGenericOutputFile.h"
+#include "ImfForward.h"
+#include "ImfThreading.h"
+#include "ImfNamespace.h"
+#include "ImfExport.h"
+
+OPENEXR_IMF_INTERNAL_NAMESPACE_HEADER_ENTER
+
+
+//
+// Class responsible for handling the writing of multipart images.
+//
+// Note: Certain attributes are 'common' to all parts. Notably:
+// * Display Window
+// * Pixel Aspect Ratio
+// * Time Code
+// * Chromaticities
+// The first header forms the basis for the set of attributes that are shared
+// across the constituent parts.
+//
+// Parameters
+// headers - pointer to array of headers; one for each part of the image file
+// parts - count of number of parts
+// overrideSharedAttributes - toggle for the handling of shared attributes.
+// set false to check for inconsistencies, true
+// to copy the values over from the first header.
+// numThreads - number of threads that should be used in encoding the data.
+//
+
+class MultiPartOutputFile : public GenericOutputFile
+{
+ public:
+ IMF_EXPORT
+ MultiPartOutputFile(const char fileName[],
+ const Header * headers,
+ int parts,
+ bool overrideSharedAttributes = false,
+ int numThreads = globalThreadCount());
+
+ IMF_EXPORT
+ MultiPartOutputFile(OStream & os,
+ const Header * headers,
+ int parts,
+ bool overrideSharedAttributes = false,
+ int numThreads = globalThreadCount());
+
+ //
+ // return number of parts in file
+ //
+ IMF_EXPORT
+ int parts() const;
+
+ //
+ // return header for part n
+ // (note: may have additional attributes compared to that passed to constructor)
+ //
+ IMF_EXPORT
+ const Header & header(int n) const;
+
+ IMF_EXPORT
+ ~MultiPartOutputFile();
+
+ struct Data;
+
+ private:
+ Data* _data;
+
+ MultiPartOutputFile(const MultiPartOutputFile &); // not implemented
+
+ template<class T> T* getOutputPart(int partNumber);
+
+
+ friend class OutputPart;
+ friend class TiledOutputPart;
+ friend class DeepScanLineOutputPart;
+ friend class DeepTiledOutputPart;
+};
+
+
+OPENEXR_IMF_INTERNAL_NAMESPACE_HEADER_EXIT
+
+#endif /* MULTIPARTOUTPUTFILE_H_ */
///////////////////////////////////////////////////////////////////////////
//
// Copyright (c) 2007, Weta Digital Ltd
-//
+//
// All rights reserved.
-//
+//
// Redistribution and use in source and binary forms, with or without
// modification, are permitted provided that the following conditions are
// met:
// distribution.
// * Neither the name of Weta Digital nor the names of
// its contributors may be used to endorse or promote products derived
-// from this software without specific prior written permission.
-//
+// from this software without specific prior written permission.
+//
// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
#include <ImfMultiView.h>
using namespace std;
+#include "ImfNamespace.h"
+
+OPENEXR_IMF_INTERNAL_NAMESPACE_SOURCE_ENTER
-namespace Imf {
namespace {
StringVector
StringVector r;
while (name.size() > 0)
- {
- size_t s = name.find (c);
- string sec = name.substr (0, s);
+ {
+ size_t s = name.find (c);
+ string sec = name.substr (0, s);
- //
- // Strip spaces from beginning
- //
+ //
+ // Strip spaces from beginning
+ //
- while (sec.size() > 0 && sec[0] == ' ')
- sec.erase (0, 1);
+ while (sec.size() > 0 && sec[0] == ' ')
+ sec.erase (0, 1);
- //
- // Strip spaces from end
- //
+ //
+ // Strip spaces from end
+ //
- while (sec.size() > 0 && sec[sec.size() - 1] == ' ')
- sec.erase (sec.size() - 1);
+ while (sec.size() > 0 && sec[sec.size() - 1] == ' ')
+ sec.erase (sec.size() - 1);
- r.push_back (sec);
+ r.push_back (sec);
- //
- // Strip off name including ending 'c'
- //
+ //
+ // Strip off name including ending 'c'
+ //
- if (s == name.npos)
- name = "";
- else
- name = name.substr (s + 1);
- }
+ if (s == name.npos)
+ name = "";
+ else
+ name = name.substr (s + 1);
+ }
return r;
}
// otherwise, it's some other (valid) view
//
- for (int i = 0; i < multiView.size(); ++i)
+ for (size_t i = 0; i < multiView.size(); ++i)
{
- if (multiView[i] == view)
- return i;
+ if (multiView[i] == view)
+ return i;
}
return -1;
defaultViewName (const StringVector &multiView)
{
if (multiView.size() > 0)
- return multiView[0];
+ return multiView[0];
else
- return "";
+ return "";
}
string
viewFromChannelName (const string &channel,
- const StringVector &multiView)
+ const StringVector &multiView)
{
//
// Given the name of a channel, return the name of the view to
StringVector s = parseString (channel, '.');
if (s.size() == 0)
- return ""; // nothing in, nothing out
+ return ""; // nothing in, nothing out
if (s.size() == 1)
{
- //
- // Return default view name.
- // The rules say ALL channels with no periods
- // in the name belong to the default view.
- //
+ //
+ // Return default view name.
+ // The rules say ALL channels with no periods
+ // in the name belong to the default view.
+ //
- return multiView[0];
+ return multiView[0];
}
else
- {
- //
- // size >= 2 - the last part is the channel name,
- // the next-to-last part is the view name.
- // Check if that part of the name really is
- // a valid view and, if it is, return it.
- //
-
- const string &viewName = s[s.size() - 2];
-
- if (viewNum (viewName, multiView) >= 0)
- return viewName;
- else
- return ""; // not associated with any particular view
+ {
+ //
+ // size >= 2 - the last part is the channel name,
+ // the next-to-last part is the view name.
+ // Check if that part of the name really is
+ // a valid view and, if it is, return it.
+ //
+
+ const string &viewName = s[s.size() - 2];
+
+ if (viewNum (viewName, multiView) >= 0)
+ return viewName;
+ else
+ return ""; // not associated with any particular view
}
}
ChannelList
channelsInView (const string & viewName,
- const ChannelList & channelList,
- const StringVector & multiView)
+ const ChannelList & channelList,
+ const StringVector & multiView)
{
//
// Return a list of all channels belonging to view viewName.
ChannelList q;
for (ChannelList::ConstIterator i = channelList.begin();
- i != channelList.end();
- ++i)
+ i != channelList.end();
+ ++i)
{
- //
- // Get view name for this channel
- //
+ //
+ // Get view name for this channel
+ //
- string view = viewFromChannelName (i.name(), multiView);
+ string view = viewFromChannelName (i.name(), multiView);
- //
- // Insert channel into q if it's a member of view viewName
- //
+ //
+ // Insert channel into q if it's a member of view viewName
+ //
- if (view == viewName)
- q.insert (i.name(), i.channel());
+ if (view == viewName)
+ q.insert (i.name(), i.channel());
}
return q;
ChannelList
channelsInNoView (const ChannelList &channelList,
- const StringVector &multiView)
+ const StringVector &multiView)
{
//
// Return a list of channels not associated with any named view.
//
- return channelsInView ("", channelList, multiView);
+ return channelsInView ("", channelList, multiView);
}
bool
-areCounterparts (const string &channel1,
- const string &channel2,
- const StringVector &multiView)
+areCounterparts (const string &channel1,
+ const string &channel2,
+ const StringVector &multiView)
{
//
// Given two channels, return true if they are the same
//
StringVector chan1 = parseString (channel1);
- unsigned int size1 = chan1.size(); // number of SECTIONS in string
- // name (not string length)
+ size_t size1 = chan1.size(); // number of SECTIONS in string
+ // name (not string length)
StringVector chan2 = parseString (channel2);
- unsigned int size2 = chan2.size();
+ size_t size2 = chan2.size();
if (size1 == 0 || size2 == 0)
- return false;
-
+ return false;
+
//
// channel1 and channel2 can't be counterparts
// if either channel is in no view.
//
if (size1 > 1 && viewNum (chan1[size1 - 2], multiView) == -1)
- return false;
+ return false;
if (size2 > 1 && viewNum (chan2[size2 - 2], multiView) == -1)
- return false;
+ return false;
if (viewFromChannelName (channel1, multiView) ==
- viewFromChannelName (channel2, multiView))
+ viewFromChannelName (channel2, multiView))
{
- //
- // channel1 and channel2 are not counterparts
- // if they are in the same view.
- //
+ //
+ // channel1 and channel2 are not counterparts
+ // if they are in the same view.
+ //
- return false;
+ return false;
}
if (size1 == 1)
- {
- //
- // channel1 is a default channel - the channels will only be
- // counterparts if channel2 is of the form <view>.<channel1>
- //
+ {
+ //
+ // channel1 is a default channel - the channels will only be
+ // counterparts if channel2 is of the form <view>.<channel1>
+ //
- return size2 == 2 && chan1[0] == chan2[1];
+ return size2 == 2 && chan1[0] == chan2[1];
}
if (size2 == 1)
{
- //
- // channel2 is a default channel - the channels will only be
- // counterparts if channel1 is of the form <view>.<channel2>
- //
+ //
+ // channel2 is a default channel - the channels will only be
+ // counterparts if channel1 is of the form <view>.<channel2>
+ //
- return size1 == 2 && chan2[0] == chan1[1];
+ return size1 == 2 && chan2[0] == chan1[1];
}
//
//
if (size1 != size2)
- return false;
+ return false;
- for(int i = 0; i < size1; ++i)
+ for(size_t i = 0; i < size1; ++i)
{
- if (i != size1 - 2 && chan1[i] != chan2[i])
- return false;
+ if (i != size1 - 2 && chan1[i] != chan2[i])
+ return false;
}
return true;
ChannelList
channelInAllViews (const string &channelName,
- const ChannelList &channelList,
- const StringVector &multiView)
+ const ChannelList &channelList,
+ const StringVector &multiView)
{
//
// Given the name of a channel, return a
ChannelList q;
for (ChannelList::ConstIterator i=channelList.begin();
- i != channelList.end();
- ++i)
+ i != channelList.end();
+ ++i)
{
- if (i.name() == channelName ||
- areCounterparts (i.name(), channelName, multiView))
- {
- q.insert (i.name(), i.channel());
- }
+ if (i.name() == channelName ||
+ areCounterparts (i.name(), channelName, multiView))
+ {
+ q.insert (i.name(), i.channel());
+ }
}
return q;
string
channelInOtherView (const string &channelName,
- const ChannelList &channelList,
- const StringVector &multiView,
- const string &otherViewName)
+ const ChannelList &channelList,
+ const StringVector &multiView,
+ const string &otherViewName)
{
//
// Given the name of a channel in one view, return the
//
for (ChannelList::ConstIterator i=channelList.begin();
- i != channelList.end();
- ++i)
+ i != channelList.end();
+ ++i)
{
- if (viewFromChannelName (i.name(), multiView) == otherViewName &&
- areCounterparts (i.name(), channelName, multiView))
- {
- return i.name();
- }
+ if (viewFromChannelName (i.name(), multiView) == otherViewName &&
+ areCounterparts (i.name(), channelName, multiView))
+ {
+ return i.name();
+ }
}
return "";
string
insertViewName (const string &channel,
- const StringVector &multiView,
- int i)
+ const StringVector &multiView,
+ int i)
{
//
// Insert multiView[i] into the channel name if appropriate.
StringVector s = parseString (channel, '.');
if (s.size() == 0)
- return ""; // nothing in, nothing out
+ return ""; // nothing in, nothing out
if (s.size() == 1 && i == 0)
{
- //
- // Channel in the default view, with no periods in its name.
- // Do not insert view name.
- //
+ //
+ // Channel in the default view, with no periods in its name.
+ // Do not insert view name.
+ //
- return channel;
+ return channel;
}
//
string newName;
- for (int j = 0; j < s.size(); ++j)
+ for (size_t j = 0; j < s.size(); ++j)
{
- if (j < s.size() - 1)
- newName += s[j] + ".";
- else
- newName += multiView[i] + "." + s[j];
+ if (j < s.size() - 1)
+ newName += s[j] + ".";
+ else
+ newName += multiView[i] + "." + s[j];
}
return newName;
}
-} // namespace Imf
+string
+removeViewName(const string & channel,const string & view)
+{
+ StringVector s = parseString (channel, '.');
+
+ if (s.size() == 0)
+ return ""; // nothing in, nothing out
+
+ if (s.size() == 1)
+ {
+ //
+ // Channel in the default view, since no periods in its name.
+ // No viewname to remove
+ //
+
+ return channel;
+ }
+
+ string newName;
+ for( size_t j = 0 ; j < s.size() ; ++j)
+ {
+ // only add the penultimate string part
+ // if it doesn't match the view name
+ if(j+2!=s.size() || s[j]!=view)
+ {
+ newName += s[j];
+ if(j+1!=s.size())
+ {
+ newName += ".";
+ }
+ }
+ }
+
+ return newName;
+
+}
+
+OPENEXR_IMF_INTERNAL_NAMESPACE_SOURCE_EXIT
///////////////////////////////////////////////////////////////////////////
//
// Copyright (c) 2007, Weta Digital Ltd
-//
+//
// All rights reserved.
-//
+//
// Redistribution and use in source and binary forms, with or without
// modification, are permitted provided that the following conditions are
// met:
// distribution.
// * Neither the name of Weta Digital nor the names of
// its contributors may be used to endorse or promote products derived
-// from this software without specific prior written permission.
-//
+// from this software without specific prior written permission.
+//
// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
#ifndef INCLUDED_IMF_MULTIVIEW_H
#define INCLUDED_IMF_MULTIVIEW_H
-#include <ImfChannelList.h>
-#include <ImfStringVectorAttribute.h>
+#include "ImfChannelList.h"
+#include "ImfStringVectorAttribute.h"
+#include "ImfExport.h"
+#include "ImfNamespace.h"
//-----------------------------------------------------------------------------
//
//
//-----------------------------------------------------------------------------
-namespace Imf {
+OPENEXR_IMF_INTERNAL_NAMESPACE_HEADER_ENTER
//
// Return the name of the default view given a multi-view string vector,
// vector is empty, return "".
//
+IMF_EXPORT
std::string defaultViewName (const StringVector &multiView);
// is not a member of any named view.
//
+IMF_EXPORT
std::string viewFromChannelName (const std::string &channel,
const StringVector &multiView);
// belongs to no view or if both channels belong to the same view.)
//
+IMF_EXPORT
bool areCounterparts (const std::string &channel1,
const std::string &channel2,
const StringVector &multiView);
// Return a list of all channels belonging to view viewName.
//
+IMF_EXPORT
ChannelList channelsInView (const std::string &viewName,
const ChannelList &channelList,
const StringVector &multiView);
// Return a list of channels not associated with any view.
//
+IMF_EXPORT
ChannelList channelsInNoView (const ChannelList &channelList,
const StringVector &multiView);
// X.right.Y, X.centre.Y, etc.).
//
+IMF_EXPORT
ChannelList channelInAllViews (const std::string &channame,
const ChannelList &channelList,
const StringVector &multiView);
// exist.
//
+IMF_EXPORT
std::string channelInOtherView (const std::string &channel,
const ChannelList &channelList,
const StringVector &multiView,
// not insert the view name.
//
+IMF_EXPORT
std::string insertViewName (const std::string &channel,
- const StringVector &multiView,
- int i);
+ const StringVector &multiView,
+ int i);
+
+//
+// Given a channel name that does may include a view name, return
+// string without the view name. If the string does not contain
+// the view name, return the string unaltered.
+// (Will only remove the viewname if it is in the correct position
+// in the string)
+//
+
+IMF_EXPORT
+std::string removeViewName (const std::string &channel,
+ const std::string &view);
+
-} // namespace Imf
+OPENEXR_IMF_INTERNAL_NAMESPACE_HEADER_EXIT
#endif
//
// Copyright (c) 2002, Industrial Light & Magic, a division of Lucas
// Digital Ltd. LLC
-//
+//
// All rights reserved.
-//
+//
// Redistribution and use in source and binary forms, with or without
// modification, are permitted provided that the following conditions are
// met:
// distribution.
// * Neither the name of Industrial Light & Magic nor the names of
// its contributors may be used to endorse or promote products derived
-// from this software without specific prior written permission.
-//
+// from this software without specific prior written permission.
+//
// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
//-----------------------------------------------------------------------------
#include <string.h>
+#include "ImfNamespace.h"
+#include "ImfExport.h"
-namespace Imf {
+OPENEXR_IMF_INTERNAL_NAMESPACE_HEADER_ENTER
class Name
// Constructors
//-------------
+ IMF_EXPORT
Name ();
+ IMF_EXPORT
Name (const char text[]);
// Assignment operator
//--------------------
+ IMF_EXPORT
Name & operator = (const char text[]);
// Access to the string
//---------------------
+ IMF_EXPORT
const char * text () const {return _text;}
+ IMF_EXPORT
const char * operator * () const {return _text;}
//---------------
};
+IMF_EXPORT
bool operator == (const Name &x, const Name &y);
+IMF_EXPORT
bool operator != (const Name &x, const Name &y);
+IMF_EXPORT
bool operator < (const Name &x, const Name &y);
}
-} // namespace IMF
+OPENEXR_IMF_INTERNAL_NAMESPACE_HEADER_EXIT
+
+
+
#endif
--- /dev/null
+///////////////////////////////////////////////////////////////////////////
+//
+// Copyright (c) 2012, Industrial Light & Magic, a division of Lucas
+// Digital Ltd. LLC
+//
+// All rights reserved.
+//
+// Redistribution and use in source and binary forms, with or without
+// modification, are permitted provided that the following conditions are
+// met:
+// * Redistributions of source code must retain the above copyright
+// notice, this list of conditions and the following disclaimer.
+// * Redistributions in binary form must reproduce the above
+// copyright notice, this list of conditions and the following disclaimer
+// in the documentation and/or other materials provided with the
+// distribution.
+// * Neither the name of Industrial Light & Magic nor the names of
+// its contributors may be used to endorse or promote products derived
+// from this software without specific prior written permission.
+//
+// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+//
+///////////////////////////////////////////////////////////////////////////
+
+#ifndef INCLUDED_IMFNAMESPACE_H
+#define INCLUDED_IMFNAMESPACE_H
+
+//
+// The purpose of this file is to have all of the Imath symbols defined within
+// the OPENEXR_IMF_INTERNAL_NAMESPACE namespace rather than the standard Imath
+// namespace. Those symbols are made available to client code through the
+// OPENEXR_IMF_NAMESPACE in addition to the OPENEXR_IMF_INTERNAL_NAMESPACE.
+//
+// To ensure source code compatibility, the OPENEXR_IMF_NAMESPACE defaults to
+// Imath and then "using namespace OPENEXR_IMF_INTERNAL_NAMESPACE;" brings all
+// of the declarations from the OPENEXR_IMF_INTERNAL_NAMESPACE into the
+// OPENEXR_IMF_NAMESPACE.
+// This means that client code can continue to use syntax like
+// Imf::Header, but at link time it will resolve to a
+// mangled symbol based on the OPENEXR_IMF_INTERNAL_NAMESPACE.
+//
+// As an example, if one needed to build against a newer version of Imath and
+// have it run alongside an older version in the same application, it is now
+// possible to use an internal namespace to prevent collisions between the
+// older versions of Imath symbols and the newer ones. To do this, the
+// following could be defined at build time:
+//
+// OPENEXR_IMF_INTERNAL_NAMESPACE = Imf_v2
+//
+// This means that declarations inside Imath headers look like this (after
+// the preprocessor has done its work):
+//
+// namespace Imf_v2 {
+// ...
+// class declarations
+// ...
+// }
+//
+// namespace Imf {
+// using namespace IMF_NAMESPACE_v2;
+// }
+//
+
+//
+// Open Source version of this file pulls in the OpenEXRConfig.h file
+// for the configure time options.
+//
+#include "OpenEXRConfig.h"
+
+
+#ifndef OPENEXR_IMF_NAMESPACE
+#define OPENEXR_IMF_NAMESPACE Imf
+#endif
+
+#ifndef OPENEXR_IMF_INTERNAL_NAMESPACE
+#define OPENEXR_IMF_INTERNAL_NAMESPACE OPENEXR_IMF_NAMESPACE
+#endif
+
+//
+// We need to be sure that we import the internal namespace into the public one.
+// To do this, we use the small bit of code below which initially defines
+// OPENEXR_IMF_INTERNAL_NAMESPACE (so it can be referenced) and then defines
+// OPENEXR_IMF_NAMESPACE and pulls the internal symbols into the public
+// namespace.
+//
+
+namespace OPENEXR_IMF_INTERNAL_NAMESPACE {}
+namespace OPENEXR_IMF_NAMESPACE {
+ using namespace OPENEXR_IMF_INTERNAL_NAMESPACE;
+}
+
+//
+// There are identical pairs of HEADER/SOURCE ENTER/EXIT macros so that
+// future extension to the namespace mechanism is possible without changing
+// project source code.
+//
+
+#define OPENEXR_IMF_INTERNAL_NAMESPACE_HEADER_ENTER namespace OPENEXR_IMF_INTERNAL_NAMESPACE {
+#define OPENEXR_IMF_INTERNAL_NAMESPACE_HEADER_EXIT }
+
+#define OPENEXR_IMF_INTERNAL_NAMESPACE_SOURCE_ENTER namespace OPENEXR_IMF_INTERNAL_NAMESPACE {
+#define OPENEXR_IMF_INTERNAL_NAMESPACE_SOURCE_EXIT }
+
+
+#endif /* INCLUDED_IMFNAMESPACE_H */
//
// Copyright (c) 2004, Industrial Light & Magic, a division of Lucas
// Digital Ltd. LLC
-//
+//
// All rights reserved.
-//
+//
// Redistribution and use in source and binary forms, with or without
// modification, are permitted provided that the following conditions are
// met:
// distribution.
// * Neither the name of Industrial Light & Magic nor the names of
// its contributors may be used to endorse or promote products derived
-// from this software without specific prior written permission.
-//
+// from this software without specific prior written permission.
+//
// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
#include <ImfOpaqueAttribute.h>
#include "Iex.h"
#include <string.h>
+#include "ImfNamespace.h"
-namespace Imf {
+OPENEXR_IMF_INTERNAL_NAMESPACE_SOURCE_ENTER
OpaqueAttribute::OpaqueAttribute (const char typeName[]):
}
-Attribute *
+Attribute *
OpaqueAttribute::copy () const
{
return new OpaqueAttribute (*this);
}
-void
-OpaqueAttribute::writeValueTo (OStream &os, int) const
+void
+OpaqueAttribute::writeValueTo (OPENEXR_IMF_INTERNAL_NAMESPACE::OStream &os, int version) const
{
Xdr::write <StreamIO> (os, _data, _dataSize);
}
-void
-OpaqueAttribute::readValueFrom (IStream &is, int size, int)
+void
+OpaqueAttribute::readValueFrom (OPENEXR_IMF_INTERNAL_NAMESPACE::IStream &is, int size, int version)
{
_data.resizeErase (size);
_dataSize = size;
}
-void
+void
OpaqueAttribute::copyValueFrom (const Attribute &other)
{
const OpaqueAttribute *oa = dynamic_cast <const OpaqueAttribute *> (&other);
if (oa == 0 || strcmp (_typeName, oa->_typeName))
{
- THROW (Iex::TypeExc, "Cannot copy the value of an "
- "image file attribute of type "
- "\"" << other.typeName() << "\" "
- "to an attribute of type "
- "\"" << _typeName << "\".");
+ THROW (IEX_NAMESPACE::TypeExc, "Cannot copy the value of an "
+ "image file attribute of type "
+ "\"" << other.typeName() << "\" "
+ "to an attribute of type "
+ "\"" << _typeName << "\".");
}
_data.resizeErase (oa->_dataSize);
}
-} // namespace Imf
+OPENEXR_IMF_INTERNAL_NAMESPACE_SOURCE_EXIT
//
// Copyright (c) 2004, Industrial Light & Magic, a division of Lucas
// Digital Ltd. LLC
-//
+//
// All rights reserved.
-//
+//
// Redistribution and use in source and binary forms, with or without
// modification, are permitted provided that the following conditions are
// met:
// distribution.
// * Neither the name of Industrial Light & Magic nor the names of
// its contributors may be used to endorse or promote products derived
-// from this software without specific prior written permission.
-//
+// from this software without specific prior written permission.
+//
// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
//
//-----------------------------------------------------------------------------
-#include <ImfAttribute.h>
-#include <ImfArray.h>
+#include "ImfAttribute.h"
+#include "ImfArray.h"
+#include "ImfNamespace.h"
-namespace Imf {
+OPENEXR_IMF_INTERNAL_NAMESPACE_HEADER_ENTER
class OpaqueAttribute: public Attribute
// Constructors and destructor
//----------------------------
+ IMF_EXPORT
OpaqueAttribute (const char typeName[]);
+ IMF_EXPORT
OpaqueAttribute (const OpaqueAttribute &other);
+ IMF_EXPORT
virtual ~OpaqueAttribute ();
// Get this attribute's type name
//-------------------------------
+ IMF_EXPORT
virtual const char * typeName () const;
-
+
//------------------------------
// Make a copy of this attribute
//------------------------------
+ IMF_EXPORT
virtual Attribute * copy () const;
// I/O and copying
//----------------
- virtual void writeValueTo (OStream &os,
- int version) const;
+ IMF_EXPORT
+ virtual void writeValueTo (OPENEXR_IMF_INTERNAL_NAMESPACE::OStream &os,
+ int version) const;
- virtual void readValueFrom (IStream &is,
- int size,
- int version);
+ IMF_EXPORT
+ virtual void readValueFrom (OPENEXR_IMF_INTERNAL_NAMESPACE::IStream &is,
+ int size,
+ int version);
+ IMF_EXPORT
virtual void copyValueFrom (const Attribute &other);
};
-} // namespace Imf
-
-// Metrowerks compiler wants the .cpp file inlined, too
-#ifdef __MWERKS__
-#include <ImfOpaqueAttribute.cpp>
-#endif
+OPENEXR_IMF_INTERNAL_NAMESPACE_HEADER_EXIT
#endif
--- /dev/null
+///////////////////////////////////////////////////////////////////////////
+//
+// Copyright (c) 2012, Autodesk, Inc.
+//
+// All rights reserved.
+//
+// Implementation of IIF-specific file format and speed optimizations
+// provided by Innobec Technologies inc on behalf of Autodesk.
+//
+// Redistribution and use in source and binary forms, with or without
+// modification, are permitted provided that the following conditions are
+// met:
+// * Redistributions of source code must retain the above copyright
+// notice, this list of conditions and the following disclaimer.
+// * Redistributions in binary form must reproduce the above
+// copyright notice, this list of conditions and the following disclaimer
+// in the documentation and/or other materials provided with the
+// distribution.
+// * Neither the name of Industrial Light & Magic nor the names of
+// its contributors may be used to endorse or promote products derived
+// from this software without specific prior written permission.
+//
+// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+//
+///////////////////////////////////////////////////////////////////////////
+
+#pragma once
+
+#ifndef INCLUDED_IMF_OPTIMIZED_PIXEL_READING_H
+#define INCLUDED_IMF_OPTIMIZED_PIXEL_READING_H
+
+#include "ImfSimd.h"
+#include "ImfSystemSpecific.h"
+#include <iostream>
+#include "ImfChannelList.h"
+#include "ImfFrameBuffer.h"
+#include "ImfStringVectorAttribute.h"
+
+OPENEXR_IMF_INTERNAL_NAMESPACE_HEADER_ENTER
+
+class OptimizationMode
+{
+public:
+
+
+ bool _optimizable;
+ int _ySampling;
+ OptimizationMode() : _optimizable(false) {}
+
+};
+
+
+#ifdef IMF_HAVE_SSE2
+
+
+//------------------------------------------------------------------------
+// Test for SSE pointer alignemnt
+//------------------------------------------------------------------------
+EXR_FORCEINLINE
+bool
+isPointerSSEAligned (const void* EXR_RESTRICT pPointer)
+{
+ uintptr_t trailingBits = ((uintptr_t)pPointer) & 15;
+ return trailingBits == 0;
+}
+
+//------------------------------------------------------------------------
+// Load SSE from address into register
+//------------------------------------------------------------------------
+template<bool IS_ALIGNED>
+EXR_FORCEINLINE
+__m128i loadSSE (__m128i*& loadAddress)
+{
+ // throw exception :: this is not accepted
+ return _mm_loadu_si128 (loadAddress);
+}
+
+template<>
+EXR_FORCEINLINE
+__m128i loadSSE<false> (__m128i*& loadAddress)
+{
+ return _mm_loadu_si128 (loadAddress);
+}
+
+template<>
+EXR_FORCEINLINE
+__m128i loadSSE<true> (__m128i*& loadAddress)
+{
+ return _mm_load_si128 (loadAddress);
+}
+
+//------------------------------------------------------------------------
+// Store SSE from register into address
+//------------------------------------------------------------------------
+template<bool IS_ALIGNED>
+EXR_FORCEINLINE
+void storeSSE (__m128i*& storeAddress, __m128i& dataToStore)
+{
+
+}
+
+template<>
+EXR_FORCEINLINE
+void
+storeSSE<false> (__m128i*& storeAddress, __m128i& dataToStore)
+{
+ _mm_storeu_si128 (storeAddress, dataToStore);
+}
+
+template<>
+EXR_FORCEINLINE
+void
+storeSSE<true> (__m128i*& storeAddress, __m128i& dataToStore)
+{
+ _mm_stream_si128 (storeAddress, dataToStore);
+}
+
+
+
+//------------------------------------------------------------------------
+//
+// Write to RGBA
+//
+//------------------------------------------------------------------------
+
+//
+// Using SSE intrinsics
+//
+template<bool READ_PTR_ALIGNED, bool WRITE_PTR_ALIGNED>
+EXR_FORCEINLINE
+void writeToRGBASSETemplate
+ (__m128i*& readPtrSSERed,
+ __m128i*& readPtrSSEGreen,
+ __m128i*& readPtrSSEBlue,
+ __m128i*& readPtrSSEAlpha,
+ __m128i*& writePtrSSE,
+ const size_t& lPixelsToCopySSE)
+{
+ for (size_t i = 0; i < lPixelsToCopySSE; ++i)
+ {
+ __m128i redRegister = loadSSE<READ_PTR_ALIGNED> (readPtrSSERed);
+ __m128i greenRegister = loadSSE<READ_PTR_ALIGNED> (readPtrSSEGreen);
+ __m128i blueRegister = loadSSE<READ_PTR_ALIGNED> (readPtrSSEBlue);
+ __m128i alphaRegister = loadSSE<READ_PTR_ALIGNED> (readPtrSSEAlpha);
+
+ __m128i redGreenRegister = _mm_unpacklo_epi16 (redRegister,
+ greenRegister);
+ __m128i blueAlphaRegister = _mm_unpacklo_epi16 (blueRegister,
+ alphaRegister);
+
+ __m128i pixel12Register = _mm_unpacklo_epi32 (redGreenRegister,
+ blueAlphaRegister);
+ __m128i pixel34Register = _mm_unpackhi_epi32 (redGreenRegister,
+ blueAlphaRegister);
+
+ storeSSE<WRITE_PTR_ALIGNED> (writePtrSSE, pixel12Register);
+ ++writePtrSSE;
+
+ storeSSE<WRITE_PTR_ALIGNED> (writePtrSSE, pixel34Register);
+ ++writePtrSSE;
+
+ redGreenRegister = _mm_unpackhi_epi16 (redRegister, greenRegister);
+ blueAlphaRegister = _mm_unpackhi_epi16 (blueRegister, alphaRegister);
+
+ pixel12Register = _mm_unpacklo_epi32 (redGreenRegister,
+ blueAlphaRegister);
+ pixel34Register = _mm_unpackhi_epi32 (redGreenRegister,
+ blueAlphaRegister);
+
+ storeSSE<WRITE_PTR_ALIGNED> (writePtrSSE, pixel12Register);
+ ++writePtrSSE;
+
+ storeSSE<WRITE_PTR_ALIGNED> (writePtrSSE, pixel34Register);
+ ++writePtrSSE;
+
+ ++readPtrSSEAlpha;
+ ++readPtrSSEBlue;
+ ++readPtrSSEGreen;
+ ++readPtrSSERed;
+ }
+}
+
+//
+// Not using SSE intrinsics. This is still faster than the alternative
+// because we have multiple read pointers and therefore we are able to
+// take advantage of data locality for write operations.
+//
+EXR_FORCEINLINE
+void writeToRGBANormal (unsigned short*& readPtrRed,
+ unsigned short*& readPtrGreen,
+ unsigned short*& readPtrBlue,
+ unsigned short*& readPtrAlpha,
+ unsigned short*& writePtr,
+ const size_t& lPixelsToCopy)
+{
+ for (size_t i = 0; i < lPixelsToCopy; ++i)
+ {
+ *(writePtr++) = *(readPtrRed++);
+ *(writePtr++) = *(readPtrGreen++);
+ *(writePtr++) = *(readPtrBlue++);
+ *(writePtr++) = *(readPtrAlpha++);
+ }
+}
+
+//
+// Determine which (template) version to use by checking whether pointers
+// are aligned
+//
+EXR_FORCEINLINE
+void optimizedWriteToRGBA (unsigned short*& readPtrRed,
+ unsigned short*& readPtrGreen,
+ unsigned short*& readPtrBlue,
+ unsigned short*& readPtrAlpha,
+ unsigned short*& writePtr,
+ const size_t& pixelsToCopySSE,
+ const size_t& pixelsToCopyNormal)
+{
+ bool readPtrAreAligned = true;
+
+ readPtrAreAligned &= isPointerSSEAligned(readPtrRed);
+ readPtrAreAligned &= isPointerSSEAligned(readPtrGreen);
+ readPtrAreAligned &= isPointerSSEAligned(readPtrBlue);
+ readPtrAreAligned &= isPointerSSEAligned(readPtrAlpha);
+
+ bool writePtrIsAligned = isPointerSSEAligned(writePtr);
+
+ if (!readPtrAreAligned && !writePtrIsAligned)
+ {
+ writeToRGBASSETemplate<false, false> ((__m128i*&)readPtrRed,
+ (__m128i*&)readPtrGreen,
+ (__m128i*&)readPtrBlue,
+ (__m128i*&)readPtrAlpha,
+ (__m128i*&)writePtr,
+ pixelsToCopySSE);
+ }
+ else if (!readPtrAreAligned && writePtrIsAligned)
+ {
+ writeToRGBASSETemplate<false, true> ((__m128i*&)readPtrRed,
+ (__m128i*&)readPtrGreen,
+ (__m128i*&)readPtrBlue,
+ (__m128i*&)readPtrAlpha,
+ (__m128i*&)writePtr,
+ pixelsToCopySSE);
+ }
+ else if (readPtrAreAligned && !writePtrIsAligned)
+ {
+ writeToRGBASSETemplate<true, false> ((__m128i*&)readPtrRed,
+ (__m128i*&)readPtrGreen,
+ (__m128i*&)readPtrBlue,
+ (__m128i*&)readPtrAlpha,
+ (__m128i*&)writePtr,
+ pixelsToCopySSE);
+ }
+ else if(readPtrAreAligned && writePtrIsAligned)
+ {
+ writeToRGBASSETemplate<true, true> ((__m128i*&)readPtrRed,
+ (__m128i*&)readPtrGreen,
+ (__m128i*&)readPtrBlue,
+ (__m128i*&)readPtrAlpha,
+ (__m128i*&)writePtr,
+ pixelsToCopySSE);
+ }
+
+ writeToRGBANormal (readPtrRed, readPtrGreen, readPtrBlue, readPtrAlpha,
+ writePtr, pixelsToCopyNormal);
+}
+
+
+
+//------------------------------------------------------------------------
+//
+// Write to RGBA Fill A
+//
+//------------------------------------------------------------------------
+
+//
+// Using SSE intrinsics
+//
+template<bool READ_PTR_ALIGNED, bool WRITE_PTR_ALIGNED>
+EXR_FORCEINLINE
+void
+writeToRGBAFillASSETemplate (__m128i*& readPtrSSERed,
+ __m128i*& readPtrSSEGreen,
+ __m128i*& readPtrSSEBlue,
+ const unsigned short& alphaFillValue,
+ __m128i*& writePtrSSE,
+ const size_t& pixelsToCopySSE)
+{
+ const __m128i dummyAlphaRegister = _mm_set_epi16 (alphaFillValue,
+ alphaFillValue,
+ alphaFillValue,
+ alphaFillValue,
+ alphaFillValue,
+ alphaFillValue,
+ alphaFillValue,
+ alphaFillValue);
+
+ for (size_t pixelCounter = 0; pixelCounter < pixelsToCopySSE; ++pixelCounter)
+ {
+ __m128i redRegister = loadSSE<READ_PTR_ALIGNED> (readPtrSSERed);
+ __m128i greenRegister = loadSSE<READ_PTR_ALIGNED> (readPtrSSEGreen);
+ __m128i blueRegister = loadSSE<READ_PTR_ALIGNED> (readPtrSSEBlue);
+
+ __m128i redGreenRegister = _mm_unpacklo_epi16 (redRegister,
+ greenRegister);
+ __m128i blueAlphaRegister = _mm_unpacklo_epi16 (blueRegister,
+ dummyAlphaRegister);
+
+ __m128i pixel12Register = _mm_unpacklo_epi32 (redGreenRegister,
+ blueAlphaRegister);
+ __m128i pixel34Register = _mm_unpackhi_epi32 (redGreenRegister,
+ blueAlphaRegister);
+
+ storeSSE<WRITE_PTR_ALIGNED> (writePtrSSE, pixel12Register);
+ ++writePtrSSE;
+
+ storeSSE<WRITE_PTR_ALIGNED> (writePtrSSE, pixel34Register);
+ ++writePtrSSE;
+
+ redGreenRegister = _mm_unpackhi_epi16 (redRegister,
+ greenRegister);
+ blueAlphaRegister = _mm_unpackhi_epi16 (blueRegister,
+ dummyAlphaRegister);
+
+ pixel12Register = _mm_unpacklo_epi32 (redGreenRegister,
+ blueAlphaRegister);
+ pixel34Register = _mm_unpackhi_epi32 (redGreenRegister,
+ blueAlphaRegister);
+
+ storeSSE<WRITE_PTR_ALIGNED> (writePtrSSE, pixel12Register);
+ ++writePtrSSE;
+
+ storeSSE<WRITE_PTR_ALIGNED> (writePtrSSE, pixel34Register);
+ ++writePtrSSE;
+
+ ++readPtrSSEBlue;
+ ++readPtrSSEGreen;
+ ++readPtrSSERed;
+ }
+}
+
+//
+// Not using SSE intrinsics. This is still faster than the alternative
+// because we have multiple read pointers and therefore we are able to
+// take advantage of data locality for write operations.
+//
+EXR_FORCEINLINE
+void
+writeToRGBAFillANormal (unsigned short*& readPtrRed,
+ unsigned short*& readPtrGreen,
+ unsigned short*& readPtrBlue,
+ const unsigned short& alphaFillValue,
+ unsigned short*& writePtr,
+ const size_t& pixelsToCopy)
+{
+ for (size_t i = 0; i < pixelsToCopy; ++i)
+ {
+ *(writePtr++) = *(readPtrRed++);
+ *(writePtr++) = *(readPtrGreen++);
+ *(writePtr++) = *(readPtrBlue++);
+ *(writePtr++) = alphaFillValue;
+ }
+}
+
+//
+// Determine which (template) version to use by checking whether pointers
+// are aligned.
+//
+EXR_FORCEINLINE
+void
+optimizedWriteToRGBAFillA (unsigned short*& readPtrRed,
+ unsigned short*& readPtrGreen,
+ unsigned short*& readPtrBlue,
+ const unsigned short& alphaFillValue,
+ unsigned short*& writePtr,
+ const size_t& pixelsToCopySSE,
+ const size_t& pixelsToCopyNormal)
+{
+ bool readPtrAreAligned = true;
+
+ readPtrAreAligned &= isPointerSSEAligned (readPtrRed);
+ readPtrAreAligned &= isPointerSSEAligned (readPtrGreen);
+ readPtrAreAligned &= isPointerSSEAligned (readPtrBlue);
+
+ bool writePtrIsAligned = isPointerSSEAligned (writePtr);
+
+ if (!readPtrAreAligned && !writePtrIsAligned)
+ {
+ writeToRGBAFillASSETemplate<false, false> ((__m128i*&)readPtrRed,
+ (__m128i*&)readPtrGreen,
+ (__m128i*&)readPtrBlue,
+ alphaFillValue,
+ (__m128i*&)writePtr,
+ pixelsToCopySSE);
+ }
+ else if (!readPtrAreAligned && writePtrIsAligned)
+ {
+ writeToRGBAFillASSETemplate<false, true> ((__m128i*&)readPtrRed,
+ (__m128i*&)readPtrGreen,
+ (__m128i*&)readPtrBlue,
+ alphaFillValue,
+ (__m128i*&)writePtr,
+ pixelsToCopySSE);
+ }
+ else if (readPtrAreAligned && !writePtrIsAligned)
+ {
+ writeToRGBAFillASSETemplate<true, false> ((__m128i*&)readPtrRed,
+ (__m128i*&)readPtrGreen,
+ (__m128i*&)readPtrBlue,
+ alphaFillValue,
+ (__m128i*&)writePtr,
+ pixelsToCopySSE);
+ }
+ else if (readPtrAreAligned && writePtrIsAligned)
+ {
+ writeToRGBAFillASSETemplate<true, true> ((__m128i*&)readPtrRed,
+ (__m128i*&)readPtrGreen,
+ (__m128i*&)readPtrBlue,
+ alphaFillValue,
+ (__m128i*&)writePtr,
+ pixelsToCopySSE);
+ }
+
+ writeToRGBAFillANormal (readPtrRed,
+ readPtrGreen, readPtrBlue, alphaFillValue,
+ writePtr, pixelsToCopyNormal);
+}
+
+
+
+//------------------------------------------------------------------------
+//
+// Write to RGB
+//
+//------------------------------------------------------------------------
+
+//
+// Using SSE intrinsics
+//
+template<bool READ_PTR_ALIGNED, bool WRITE_PTR_ALIGNED>
+EXR_FORCEINLINE
+void
+writeToRGBSSETemplate (__m128i*& readPtrSSERed,
+ __m128i*& readPtrSSEGreen,
+ __m128i*& readPtrSSEBlue,
+ __m128i*& writePtrSSE,
+ const size_t& pixelsToCopySSE)
+{
+
+ for (size_t pixelCounter = 0; pixelCounter < pixelsToCopySSE; ++pixelCounter)
+ {
+ //
+ // Need to shuffle and unpack pointers to obtain my first register
+ // We must save 8 pixels at a time, so we must have the following three registers at the end:
+ // 1) R1 G1 B1 R2 G2 B2 R3 G3
+ // 2) B3 R4 G4 B4 R5 G5 B5 R6
+ // 3) G6 B6 R7 G7 B7 R8 G8 B8
+ //
+ __m128i redRegister = loadSSE<READ_PTR_ALIGNED> (readPtrSSERed);
+ __m128i greenRegister = loadSSE<READ_PTR_ALIGNED> (readPtrSSEGreen);
+ __m128i blueRegister = loadSSE<READ_PTR_ALIGNED> (readPtrSSEBlue);
+
+ //
+ // First register: R1 G1 B1 R2 G2 B2 R3 G3
+ // Construct 2 registers and then unpack them to obtain our final result:
+ //
+ __m128i redGreenRegister = _mm_unpacklo_epi16 (redRegister,
+ greenRegister);
+ __m128i redBlueRegister = _mm_unpacklo_epi16 (redRegister,
+ blueRegister);
+ __m128i greenBlueRegister = _mm_unpacklo_epi16 (greenRegister,
+ blueRegister);
+
+ // Left Part (R1 G1 B1 R2)
+ __m128i quarterRight = _mm_shufflelo_epi16 (redBlueRegister,
+ _MM_SHUFFLE(3,0,2,1));
+ __m128i halfLeft = _mm_unpacklo_epi32 (redGreenRegister,
+ quarterRight);
+
+ // Right Part (G2 B2 R3 G3)
+ __m128i quarterLeft = _mm_shuffle_epi32 (greenBlueRegister,
+ _MM_SHUFFLE(3,2,0,1));
+ quarterRight = _mm_shuffle_epi32 (redGreenRegister,
+ _MM_SHUFFLE(3,0,1,2));
+ __m128i halfRight = _mm_unpacklo_epi32 (quarterLeft, quarterRight);
+
+ __m128i fullRegister = _mm_unpacklo_epi64 (halfLeft, halfRight);
+ storeSSE<WRITE_PTR_ALIGNED> (writePtrSSE, fullRegister);
+ ++writePtrSSE;
+
+ //
+ // Second register: B3 R4 G4 B4 R5 G5 B5 R6
+ //
+
+ // Left Part (B3, R4, G4, B4)
+ quarterLeft = _mm_shufflehi_epi16 (redBlueRegister,
+ _MM_SHUFFLE(0, 3, 2, 1));
+ quarterRight = _mm_shufflehi_epi16 (greenBlueRegister,
+ _MM_SHUFFLE(1, 0, 3, 2));
+ halfLeft = _mm_unpackhi_epi32 (quarterLeft, quarterRight);
+
+ // Update the registers
+ redGreenRegister = _mm_unpackhi_epi16 (redRegister, greenRegister);
+ redBlueRegister = _mm_unpackhi_epi16 (redRegister, blueRegister);
+ greenBlueRegister = _mm_unpackhi_epi16 (greenRegister, blueRegister);
+
+ // Right Part (R5 G5 B5 R6)
+ quarterRight = _mm_shufflelo_epi16 (redBlueRegister,
+ _MM_SHUFFLE(3,0,2,1));
+ halfRight = _mm_unpacklo_epi32 (redGreenRegister, quarterRight);
+
+ fullRegister = _mm_unpacklo_epi64 (halfLeft, halfRight);
+ storeSSE<WRITE_PTR_ALIGNED> (writePtrSSE, fullRegister);
+ ++writePtrSSE;
+
+ //
+ // Third register: G6 B6 R7 G7 B7 R8 G8 B8
+ //
+
+ // Left part (G6 B6 R7 G7)
+ quarterLeft = _mm_shuffle_epi32 (greenBlueRegister,
+ _MM_SHUFFLE(3,2,0,1));
+ quarterRight = _mm_shuffle_epi32 (redGreenRegister,
+ _MM_SHUFFLE(3,0,1,2));
+ halfLeft = _mm_unpacklo_epi32 (quarterLeft, quarterRight);
+
+ // Right part (B7 R8 G8 B8)
+ quarterLeft = _mm_shufflehi_epi16 (redBlueRegister,
+ _MM_SHUFFLE(0, 3, 2, 1));
+ quarterRight = _mm_shufflehi_epi16 (greenBlueRegister,
+ _MM_SHUFFLE(1, 0, 3, 2));
+ halfRight = _mm_unpackhi_epi32 (quarterLeft, quarterRight);
+
+ fullRegister = _mm_unpacklo_epi64 (halfLeft, halfRight);
+ storeSSE<WRITE_PTR_ALIGNED> (writePtrSSE, fullRegister);
+ ++writePtrSSE;
+
+ //
+ // Increment read pointers
+ //
+ ++readPtrSSEBlue;
+ ++readPtrSSEGreen;
+ ++readPtrSSERed;
+ }
+}
+
+//
+// Not using SSE intrinsics. This is still faster than the alternative
+// because we have multiple read pointers and therefore we are able to
+// take advantage of data locality for write operations.
+//
+EXR_FORCEINLINE
+void
+writeToRGBNormal (unsigned short*& readPtrRed,
+ unsigned short*& readPtrGreen,
+ unsigned short*& readPtrBlue,
+ unsigned short*& writePtr,
+ const size_t& pixelsToCopy)
+{
+ for (size_t i = 0; i < pixelsToCopy; ++i)
+ {
+ *(writePtr++) = *(readPtrRed++);
+ *(writePtr++) = *(readPtrGreen++);
+ *(writePtr++) = *(readPtrBlue++);
+ }
+}
+
+//
+// Determine which (template) version to use by checking whether pointers
+// are aligned
+//
+EXR_FORCEINLINE
+void optimizedWriteToRGB (unsigned short*& readPtrRed,
+ unsigned short*& readPtrGreen,
+ unsigned short*& readPtrBlue,
+ unsigned short*& writePtr,
+ const size_t& pixelsToCopySSE,
+ const size_t& pixelsToCopyNormal)
+{
+ bool readPtrAreAligned = true;
+
+ readPtrAreAligned &= isPointerSSEAligned(readPtrRed);
+ readPtrAreAligned &= isPointerSSEAligned(readPtrGreen);
+ readPtrAreAligned &= isPointerSSEAligned(readPtrBlue);
+
+ bool writePtrIsAligned = isPointerSSEAligned(writePtr);
+
+ if (!readPtrAreAligned && !writePtrIsAligned)
+ {
+ writeToRGBSSETemplate<false, false> ((__m128i*&)readPtrRed,
+ (__m128i*&)readPtrGreen,
+ (__m128i*&)readPtrBlue,
+ (__m128i*&)writePtr,
+ pixelsToCopySSE);
+ }
+ else if (!readPtrAreAligned && writePtrIsAligned)
+ {
+ writeToRGBSSETemplate<false, true> ((__m128i*&)readPtrRed,
+ (__m128i*&)readPtrGreen,
+ (__m128i*&)readPtrBlue,
+ (__m128i*&)writePtr,
+ pixelsToCopySSE);
+ }
+ else if (readPtrAreAligned && !writePtrIsAligned)
+ {
+ writeToRGBSSETemplate<true, false> ((__m128i*&)readPtrRed,
+ (__m128i*&)readPtrGreen,
+ (__m128i*&)readPtrBlue,
+ (__m128i*&)writePtr,
+ pixelsToCopySSE);
+ }
+ else if (readPtrAreAligned && writePtrIsAligned)
+ {
+ writeToRGBSSETemplate<true, true> ((__m128i*&)readPtrRed,
+ (__m128i*&)readPtrGreen,
+ (__m128i*&)readPtrBlue,
+ (__m128i*&)writePtr,
+ pixelsToCopySSE);
+ }
+
+
+ writeToRGBNormal (readPtrRed, readPtrGreen, readPtrBlue,
+ writePtr, pixelsToCopyNormal);
+}
+
+
+
+
+#else // ! defined IMF_HAVE_SSE2
+
+#endif // defined IMF_HAVE_SSE2
+
+
+OPENEXR_IMF_INTERNAL_NAMESPACE_HEADER_EXIT
+
+#endif
+//
+///\todo: version needs fixing!
+//
+
///////////////////////////////////////////////////////////////////////////
//
// Copyright (c) 2004, Industrial Light & Magic, a division of Lucas
// Digital Ltd. LLC
-//
+//
// All rights reserved.
-//
+//
// Redistribution and use in source and binary forms, with or without
// modification, are permitted provided that the following conditions are
// met:
// distribution.
// * Neither the name of Industrial Light & Magic nor the names of
// its contributors may be used to endorse or promote products derived
-// from this software without specific prior written permission.
-//
+// from this software without specific prior written permission.
+//
// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
#include "ImathBox.h"
#include "ImathFun.h"
#include <ImfArray.h>
-#include <ImfXdr.h>
+#include "ImfXdr.h"
#include <ImfPreviewImageAttribute.h>
+#include <ImfPartType.h>
#include "IlmThreadPool.h"
+#include "ImfOutputStreamMutex.h"
#include "IlmThreadSemaphore.h"
#include "IlmThreadMutex.h"
#include "Iex.h"
+#include "ImfInputPart.h"
+#include "ImfNamespace.h"
+#include "ImfOutputPartData.h"
+
#include <string>
#include <vector>
#include <fstream>
#include <assert.h>
-#include <algorithm> // for std::max()
-
+#include <algorithm>
-namespace Imf {
+OPENEXR_IMF_INTERNAL_NAMESPACE_SOURCE_ENTER
-using Imath::Box2i;
-using Imath::divp;
-using Imath::modp;
+using IMATH_NAMESPACE::Box2i;
+using IMATH_NAMESPACE::divp;
+using IMATH_NAMESPACE::modp;
using std::string;
using std::vector;
using std::ofstream;
using std::min;
using std::max;
-using IlmThread::Mutex;
-using IlmThread::Lock;
-using IlmThread::Semaphore;
-using IlmThread::Task;
-using IlmThread::TaskGroup;
-using IlmThread::ThreadPool;
+using ILMTHREAD_NAMESPACE::Mutex;
+using ILMTHREAD_NAMESPACE::Lock;
+using ILMTHREAD_NAMESPACE::Semaphore;
+using ILMTHREAD_NAMESPACE::Task;
+using ILMTHREAD_NAMESPACE::TaskGroup;
+using ILMTHREAD_NAMESPACE::ThreadPool;
+
namespace {
bool zero;
OutSliceInfo (PixelType type = HALF,
- const char *base = 0,
- size_t xStride = 0,
- size_t yStride = 0,
- int xSampling = 1,
- int ySampling = 1,
- bool zero = false);
+ const char *base = 0,
+ size_t xStride = 0,
+ size_t yStride = 0,
+ int xSampling = 1,
+ int ySampling = 1,
+ bool zero = false);
+
};
OutSliceInfo::OutSliceInfo (PixelType t,
- const char *b,
- size_t xs, size_t ys,
- int xsm, int ysm,
- bool z)
+ const char *b,
+ size_t xs, size_t ys,
+ int xsm, int ysm,
+ bool z)
:
type (t),
base (b),
} // namespace
-
-struct OutputFile::Data: public Mutex
+struct OutputFile::Data
{
Header header; // the image header
- int version; // file format version
+ bool multiPart; // is the file multipart?
+ int version; // version attribute \todo NOT BEING WRITTEN PROPERLY
Int64 previewPosition; // file position for preview
FrameBuffer frameBuffer; // framebuffer to write into
int currentScanLine; // next scanline to be written
int minY; // data window's min y coord
int maxY; // data window's max x coord
vector<Int64> lineOffsets; // stores offsets in file for
- // each scanline
+ // each scanline
vector<size_t> bytesPerLine; // combined size of a line over
// all channels
vector<size_t> offsetInLineBuffer; // offset for each scanline in
// its linebuffer
Compressor::Format format; // compressor's data format
vector<OutSliceInfo> slices; // info about channels in file
- OStream * os; // file stream to write to
- bool deleteStream;
Int64 lineOffsetsPosition; // file position for line
// offset table
- Int64 currentPosition; // current file position
vector<LineBuffer*> lineBuffers; // each holds one line buffer
int linesInBuffer; // number of scanlines each
// buffer holds
size_t lineBufferSize; // size of the line buffer
- Data (bool deleteStream, int numThreads);
+ int partNumber; // the output part number
+ OutputStreamMutex * _streamData;
+ bool _deleteStream;
+ Data (int numThreads);
~Data ();
inline LineBuffer * getLineBuffer (int number); // hash function from line
- // buffer indices into our
- // vector of line buffers
+ // buffer indices into our
+ // vector of line buffers
};
-OutputFile::Data::Data (bool deleteStream, int numThreads):
- os (0),
- deleteStream (deleteStream),
- lineOffsetsPosition (0)
+OutputFile::Data::Data (int numThreads):
+ lineOffsetsPosition (0),
+ partNumber (-1),
+ _streamData(0),
+ _deleteStream(false)
{
//
// We need at least one lineBuffer, but if threading is used,
OutputFile::Data::~Data ()
{
- if (deleteStream)
- delete os;
-
for (size_t i = 0; i < lineBuffers.size(); i++)
delete lineBuffers[i];
}
return lineBuffers[number % lineBuffers.size()];
}
-
namespace {
-
Int64
-writeLineOffsets (OStream &os, const vector<Int64> &lineOffsets)
+writeLineOffsets (OPENEXR_IMF_INTERNAL_NAMESPACE::OStream &os, const vector<Int64> &lineOffsets)
{
Int64 pos = os.tellp();
if (pos == -1)
- Iex::throwErrnoExc ("Cannot determine current file position (%T).");
-
+ IEX_NAMESPACE::throwErrnoExc ("Cannot determine current file position (%T).");
+
for (unsigned int i = 0; i < lineOffsets.size(); i++)
- Xdr::write <StreamIO> (os, lineOffsets[i]);
+ Xdr::write<StreamIO> (os, lineOffsets[i]);
return pos;
}
void
-writePixelData (OutputFile::Data *ofd,
+writePixelData (OutputStreamMutex *filedata,
+ OutputFile::Data *partdata,
int lineBufferMinY,
- const char pixelData[],
- int pixelDataSize)
+ const char pixelData[],
+ int pixelDataSize)
{
//
// Store a block of pixel data in the output file, and try
// without calling tellp() (tellp() can be fairly expensive).
//
- Int64 currentPosition = ofd->currentPosition;
- ofd->currentPosition = 0;
+ Int64 currentPosition = filedata->currentPosition;
+ filedata->currentPosition = 0;
if (currentPosition == 0)
- currentPosition = ofd->os->tellp();
+ currentPosition = filedata->os->tellp();
- ofd->lineOffsets[(ofd->currentScanLine - ofd->minY) / ofd->linesInBuffer] =
- currentPosition;
+ partdata->lineOffsets[(partdata->currentScanLine - partdata->minY) / partdata->linesInBuffer] =
+ currentPosition;
#ifdef DEBUG
- assert (ofd->os->tellp() == currentPosition);
+ assert (filedata->os->tellp() == currentPosition);
#endif
+
+
+
+ if (partdata->multiPart)
+ {
+ OPENEXR_IMF_INTERNAL_NAMESPACE::Xdr::write <OPENEXR_IMF_INTERNAL_NAMESPACE::StreamIO> (*filedata->os, partdata->partNumber);
+ }
+
+ OPENEXR_IMF_INTERNAL_NAMESPACE::Xdr::write <OPENEXR_IMF_INTERNAL_NAMESPACE::StreamIO> (*filedata->os, lineBufferMinY);
+ OPENEXR_IMF_INTERNAL_NAMESPACE::Xdr::write <OPENEXR_IMF_INTERNAL_NAMESPACE::StreamIO> (*filedata->os, pixelDataSize);
+ filedata->os->write (pixelData, pixelDataSize);
- Xdr::write <StreamIO> (*ofd->os, lineBufferMinY);
- Xdr::write <StreamIO> (*ofd->os, pixelDataSize);
- ofd->os->write (pixelData, pixelDataSize);
+ filedata->currentPosition = currentPosition +
+ Xdr::size<int>() +
+ Xdr::size<int>() +
+ pixelDataSize;
- ofd->currentPosition = currentPosition +
- Xdr::size<int>() +
- Xdr::size<int>() +
- pixelDataSize;
+ if (partdata->multiPart)
+ {
+ filedata->currentPosition += Xdr::size<int>();
+ }
}
inline void
-writePixelData (OutputFile::Data *ofd, const LineBuffer *lineBuffer)
+writePixelData (OutputStreamMutex* filedata,
+ OutputFile::Data *partdata,
+ const LineBuffer *lineBuffer)
{
- writePixelData (ofd,
- lineBuffer->minY,
+ writePixelData (filedata, partdata,
+ lineBuffer->minY,
lineBuffer->dataPtr,
- lineBuffer->dataSize);
+ lineBuffer->dataSize);
}
Array<char> &lineBuffer,
int lineBufferMinY,
int lineBufferMaxY,
- int /*inSize*/)
+ int inSize)
{
//
// Convert the contents of a lineBuffer from the machine's native
// Xdr representation. This makes it possible to convert the
// pixel data in place, without an intermediate temporary buffer.
//
-
- int startY, endY; // The first and last scanlines in
- // the file that are in the lineBuffer.
- int step;
-
- if (ofd->lineOrder == INCREASING_Y)
- {
- startY = max (lineBufferMinY, ofd->minY);
- endY = min (lineBufferMaxY, ofd->maxY) + 1;
- step = 1;
- }
- else
- {
- startY = min (lineBufferMaxY, ofd->maxY);
- endY = max (lineBufferMinY, ofd->minY) - 1;
- step = -1;
- }
-
+
//
// Iterate over all scanlines in the lineBuffer to convert.
//
- for (int y = startY; y != endY; y += step)
+ char *writePtr = &lineBuffer[0];
+ for (int y = lineBufferMinY; y <= lineBufferMaxY; y++)
{
- //
+ //
// Set these to point to the start of line y.
// We will write to writePtr from readPtr.
- //
+ //
- char *writePtr = lineBuffer + ofd->offsetInLineBuffer[y - ofd->minY];
const char *readPtr = writePtr;
-
- //
+
+ //
// Iterate over all slices in the file.
- //
-
+ //
+
for (unsigned int i = 0; i < ofd->slices.size(); ++i)
{
//
//
// Find the number of sampled pixels, dMaxX-dMinX+1, for
- // slice i in scan line y (i.e. pixels within the data window
+ // slice i in scan line y (i.e. pixels within the data window
// for which x % xSampling == 0).
//
int dMinX = divp (ofd->minX, slice.xSampling);
int dMaxX = divp (ofd->maxX, slice.xSampling);
-
- //
+
+ //
// Convert the samples in place.
- //
-
+ //
+
convertInPlace (writePtr, readPtr, slice.type, dMaxX - dMinX + 1);
}
}
LineBufferTask (TaskGroup *group,
OutputFile::Data *ofd,
- int number,
+ int number,
int scanLineMin,
- int scanLineMax);
+ int scanLineMax);
- virtual ~LineBufferTask ();
+ virtual ~LineBufferTask ();
virtual void execute ();
//
_lineBuffer->wait ();
-
+
//
// Initialize the lineBuffer data if necessary
//
_lineBuffer->minY = _ofd->minY + number * _ofd->linesInBuffer;
_lineBuffer->maxY = min (_lineBuffer->minY + _ofd->linesInBuffer - 1,
- _ofd->maxY);
+ _ofd->maxY);
_lineBuffer->partiallyFull = true;
}
-
+
_lineBuffer->scanLineMin = max (_lineBuffer->minY, scanLineMin);
_lineBuffer->scanLineMax = min (_lineBuffer->maxY, scanLineMax);
}
{
//
// First copy the pixel data from the
- // frame buffer into the line buffer
+ // frame buffer into the line buffer
//
-
+
int yStart, yStop, dy;
if (_ofd->lineOrder == INCREASING_Y)
yStop = _lineBuffer->scanLineMin - 1;
dy = -1;
}
-
- int y;
+
+ int y;
for (y = yStart; y != yStop; y += dy)
{
// Gather one scan line's worth of pixel data and store
// them in _ofd->lineBuffer.
//
-
+
char *writePtr = _lineBuffer->buffer +
_ofd->offsetInLineBuffer[y - _ofd->minY];
//
{
//
// Test if scan line y of this channel contains any data
- // (the scan line contains data only if y % ySampling == 0).
+ // (the scan line contains data only if y % ySampling == 0).
//
-
+
const OutSliceInfo &slice = _ofd->slices[i];
-
+
if (modp (y, slice.ySampling) != 0)
continue;
-
+
//
// Find the x coordinates of the leftmost and rightmost
// sampled pixels (i.e. pixels within the data window
// for which x % xSampling == 0).
//
-
+
int dMinX = divp (_ofd->minX, slice.xSampling);
int dMaxX = divp (_ofd->maxX, slice.xSampling);
-
+
//
- // Fill the line buffer with with pixel data.
+ // Fill the line buffer with with pixel data.
//
-
+
if (slice.zero)
{
//
// The frame buffer contains no data for this channel.
// Store zeroes in _lineBuffer->buffer.
//
-
+
fillChannelWithZeroes (writePtr, _ofd->format, slice.type,
dMaxX - dMinX + 1);
}
{
//
// If necessary, convert the pixel data to Xdr format.
- // Then store the pixel data in _ofd->lineBuffer.
+ // Then store the pixel data in _ofd->lineBuffer.
//
-
+
const char *linePtr = slice.base +
divp (y, slice.ySampling) *
slice.yStride;
-
+
const char *readPtr = linePtr + dMinX * slice.xStride;
const char *endPtr = linePtr + dMaxX * slice.xStride;
-
+
copyFromFrameBuffer (writePtr, readPtr, endPtr,
slice.xStride, _ofd->format,
slice.type);
}
}
-
+
if (_lineBuffer->endOfLineBufferData < writePtr)
_lineBuffer->endOfLineBufferData = writePtr;
-
+
#ifdef DEBUG
-
+
assert (writePtr - (_lineBuffer->buffer +
_ofd->offsetInLineBuffer[y - _ofd->minY]) ==
(int) _ofd->bytesPerLine[y - _ofd->minY]);
-
+
#endif
-
+
}
-
+
//
// If the next scanline isn't past the bounds of the lineBuffer
// then we are done, otherwise compress the linebuffer
//
-
+
if (y >= _lineBuffer->minY && y <= _lineBuffer->maxY)
return;
-
+
_lineBuffer->dataPtr = _lineBuffer->buffer;
_lineBuffer->dataSize = _lineBuffer->endOfLineBufferData -
_lineBuffer->buffer;
-
- //
+
+ //
// Compress the data
- //
+ //
Compressor *compressor = _lineBuffer->compressor;
int compSize = compressor->compress (_lineBuffer->dataPtr,
_lineBuffer->dataSize,
_lineBuffer->minY, compPtr);
-
+
if (compSize < _lineBuffer->dataSize)
{
_lineBuffer->dataSize = compSize;
// native format, so we need to convert the lineBuffer
// to Xdr.
//
-
+
convertToXdr (_ofd, _lineBuffer->buffer, _lineBuffer->minY,
_lineBuffer->maxY, _lineBuffer->dataSize);
}
const Header &header,
int numThreads)
:
- _data (new Data (true, numThreads))
+ _data (new Data (numThreads))
{
+ _data->_streamData=new OutputStreamMutex ();
+ _data->_deleteStream=true;
try
{
- header.sanityCheck();
- _data->os = new StdOFStream (fileName);
- initialize (header);
+ header.sanityCheck();
+ _data->_streamData->os = new StdOFStream (fileName);
+ _data->multiPart=false; // only one header, not multipart
+ initialize (header);
+ _data->_streamData->currentPosition = _data->_streamData->os->tellp();
+
+ // Write header and empty offset table to the file.
+ writeMagicNumberAndVersionField(*_data->_streamData->os, _data->header);
+ _data->previewPosition =
+ _data->header.writeTo (*_data->_streamData->os);
+ _data->lineOffsetsPosition =
+ writeLineOffsets (*_data->_streamData->os,_data->lineOffsets);
}
- catch (Iex::BaseExc &e)
+ catch (IEX_NAMESPACE::BaseExc &e)
{
- delete _data;
+ // ~OutputFile will not run, so free memory here
+ if (_data)
+ {
+ if (_data->_streamData)
+ {
+ delete _data->_streamData->os;
+ delete _data->_streamData;
+ }
- REPLACE_EXC (e, "Cannot open image file "
- "\"" << fileName << "\". " << e);
- throw;
+ delete _data;
+ }
+
+ REPLACE_EXC (e, "Cannot open image file "
+ "\"" << fileName << "\". " << e.what());
+ throw;
}
catch (...)
{
- delete _data;
+ // ~OutputFile will not run, so free memory here
+ if (_data)
+ {
+ if (_data->_streamData)
+ {
+ delete _data->_streamData->os;
+ delete _data->_streamData;
+ }
+ delete _data;
+ }
+
throw;
}
}
OutputFile::OutputFile
- (OStream &os,
+ (OPENEXR_IMF_INTERNAL_NAMESPACE::OStream &os,
const Header &header,
int numThreads)
:
- _data (new Data (false, numThreads))
+ _data (new Data (numThreads))
{
+ _data->_streamData=new OutputStreamMutex ();
+ _data->_deleteStream=false;
try
{
- header.sanityCheck();
- _data->os = &os;
- initialize (header);
+ header.sanityCheck();
+ _data->_streamData->os = &os;
+ _data->multiPart=false;
+ initialize (header);
+ _data->_streamData->currentPosition = _data->_streamData->os->tellp();
+
+ // Write header and empty offset table to the file.
+ writeMagicNumberAndVersionField(*_data->_streamData->os, _data->header);
+ _data->previewPosition =
+ _data->header.writeTo (*_data->_streamData->os);
+ _data->lineOffsetsPosition =
+ writeLineOffsets (*_data->_streamData->os, _data->lineOffsets);
}
- catch (Iex::BaseExc &e)
+ catch (IEX_NAMESPACE::BaseExc &e)
{
- delete _data;
+ // ~OutputFile will not run, so free memory here
+ if (_data)
+ {
+ if (_data->_streamData)
+ delete _data->_streamData;
+ delete _data;
+ }
- REPLACE_EXC (e, "Cannot open image file "
- "\"" << os.fileName() << "\". " << e);
- throw;
+ REPLACE_EXC (e, "Cannot open image file "
+ "\"" << os.fileName() << "\". " << e.what());
+ throw;
}
catch (...)
{
- delete _data;
+ // ~OutputFile will not run, so free memory here
+ if (_data)
+ {
+ if (_data->_streamData)
+ delete _data->_streamData;
+ delete _data;
+ }
+
throw;
}
}
+OutputFile::OutputFile(const OutputPartData* part) : _data(NULL)
+{
+ try
+ {
+ if (part->header.type() != SCANLINEIMAGE)
+ throw IEX_NAMESPACE::ArgExc("Can't build a OutputFile from a type-mismatched part.");
+
+ _data = new Data (part->numThreads);
+ _data->_streamData = part->mutex;
+ _data->_deleteStream=false;
+ _data->multiPart=part->multipart;
+
+ initialize (part->header);
+ _data->partNumber = part->partNumber;
+ _data->lineOffsetsPosition = part->chunkOffsetTablePosition;
+ _data->previewPosition = part->previewPosition;
+ }
+ catch (IEX_NAMESPACE::BaseExc &e)
+ {
+ if (_data) delete _data;
+
+ REPLACE_EXC (e, "Cannot initialize output part "
+ "\"" << part->partNumber << "\". " << e.what());
+ throw;
+ }
+ catch (...)
+ {
+ if (_data) delete _data;
+
+ throw;
+ }
+}
void
OutputFile::initialize (const Header &header)
{
_data->header = header;
+ // "fix" the type if it happens to be set incorrectly
+ // (attribute is optional, but ensure it is correct if it exists)
+ if(_data->header.hasType())
+ {
+ _data->header.setType(SCANLINEIMAGE);
+ }
+
const Box2i &dataWindow = header.dataWindow();
_data->currentScanLine = (header.lineOrder() == INCREASING_Y)?
- dataWindow.min.y: dataWindow.max.y;
+ dataWindow.min.y: dataWindow.max.y;
_data->missingScanLines = dataWindow.max.y - dataWindow.min.y + 1;
_data->lineOrder = header.lineOrder();
_data->maxY = dataWindow.max.y;
size_t maxBytesPerLine = bytesPerLineTable (_data->header,
- _data->bytesPerLine);
+ _data->bytesPerLine);
for (size_t i = 0; i < _data->lineBuffers.size(); ++i)
{
_data->lineBuffers[i] =
- new LineBuffer (newCompressor (_data->header.compression(),
- maxBytesPerLine,
- _data->header));
+ new LineBuffer (newCompressor (_data->header.compression(),
+ maxBytesPerLine,
+ _data->header));
}
LineBuffer *lineBuffer = _data->lineBuffers[0];
_data->lineBuffers[i]->buffer.resizeErase(_data->lineBufferSize);
int lineOffsetSize = (dataWindow.max.y - dataWindow.min.y +
- _data->linesInBuffer) / _data->linesInBuffer;
+ _data->linesInBuffer) / _data->linesInBuffer;
_data->lineOffsets.resize (lineOffsetSize);
-
+
+
offsetInLineBufferTable (_data->bytesPerLine,
- _data->linesInBuffer,
- _data->offsetInLineBuffer);
-
- _data->previewPosition =
- _data->header.writeTo (*_data->os);
-
- _data->lineOffsetsPosition =
- writeLineOffsets (*_data->os, _data->lineOffsets);
-
- _data->currentPosition = _data->os->tellp();
+ _data->linesInBuffer,
+ _data->offsetInLineBuffer);
}
if (_data)
{
{
+ Lock lock(*_data->_streamData);
+ Int64 originalPosition = _data->_streamData->os->tellp();
+
if (_data->lineOffsetsPosition > 0)
{
try
{
- _data->os->seekp (_data->lineOffsetsPosition);
- writeLineOffsets (*_data->os, _data->lineOffsets);
+ _data->_streamData->os->seekp (_data->lineOffsetsPosition);
+ writeLineOffsets (*_data->_streamData->os, _data->lineOffsets);
+
+ //
+ // Restore the original position.
+ //
+ _data->_streamData->os->seekp (originalPosition);
}
catch (...)
{
}
}
- delete _data;
+ if (_data->_deleteStream && _data->_streamData)
+ delete _data->_streamData->os;
+
+ if (_data->partNumber == -1 && _data->_streamData)
+ delete _data->_streamData;
+
+ delete _data;
}
+
}
const char *
OutputFile::fileName () const
{
- return _data->os->fileName();
+ return _data->_streamData->os->fileName();
}
}
-void
+void
OutputFile::setFrameBuffer (const FrameBuffer &frameBuffer)
{
- Lock lock (*_data);
-
+ Lock lock (*_data->_streamData);
+
//
// Check if the new frame buffer descriptor
// is compatible with the image file header.
const ChannelList &channels = _data->header.channels();
for (ChannelList::ConstIterator i = channels.begin();
- i != channels.end();
- ++i)
- {
- FrameBuffer::ConstIterator j = frameBuffer.find (i.name());
-
- if (j == frameBuffer.end())
- continue;
-
- if (i.channel().type != j.slice().type)
- {
- THROW (Iex::ArgExc, "Pixel type of \"" << i.name() << "\" channel "
- "of output file \"" << fileName() << "\" is "
- "not compatible with the frame buffer's "
- "pixel type.");
- }
-
- if (i.channel().xSampling != j.slice().xSampling ||
- i.channel().ySampling != j.slice().ySampling)
+ i != channels.end();
+ ++i)
{
- THROW (Iex::ArgExc, "X and/or y subsampling factors "
- "of \"" << i.name() << "\" channel "
- "of output file \"" << fileName() << "\" are "
- "not compatible with the frame buffer's "
- "subsampling factors.");
- }
+ FrameBuffer::ConstIterator j = frameBuffer.find (i.name());
+
+ if (j == frameBuffer.end())
+ continue;
+
+ if (i.channel().type != j.slice().type)
+ {
+ THROW (IEX_NAMESPACE::ArgExc, "Pixel type of \"" << i.name() << "\" channel "
+ "of output file \"" << fileName() << "\" is "
+ "not compatible with the frame buffer's "
+ "pixel type.");
+ }
+
+ if (i.channel().xSampling != j.slice().xSampling ||
+ i.channel().ySampling != j.slice().ySampling)
+ {
+ THROW (IEX_NAMESPACE::ArgExc, "X and/or y subsampling factors "
+ "of \"" << i.name() << "\" channel "
+ "of output file \"" << fileName() << "\" are "
+ "not compatible with the frame buffer's "
+ "subsampling factors.");
+ }
}
-
+
//
// Initialize slice table for writePixels().
//
vector<OutSliceInfo> slices;
for (ChannelList::ConstIterator i = channels.begin();
- i != channels.end();
- ++i)
- {
- FrameBuffer::ConstIterator j = frameBuffer.find (i.name());
-
- if (j == frameBuffer.end())
- {
- //
- // Channel i is not present in the frame buffer.
- // In the file, channel i will contain only zeroes.
- //
-
- slices.push_back (OutSliceInfo (i.channel().type,
- 0, // base
- 0, // xStride,
- 0, // yStride,
- i.channel().xSampling,
- i.channel().ySampling,
- true)); // zero
- }
- else
+ i != channels.end();
+ ++i)
{
- //
- // Channel i is present in the frame buffer.
- //
-
- slices.push_back (OutSliceInfo (j.slice().type,
- j.slice().base,
- j.slice().xStride,
- j.slice().yStride,
- j.slice().xSampling,
- j.slice().ySampling,
- false)); // zero
- }
+ FrameBuffer::ConstIterator j = frameBuffer.find (i.name());
+
+ if (j == frameBuffer.end())
+ {
+ //
+ // Channel i is not present in the frame buffer.
+ // In the file, channel i will contain only zeroes.
+ //
+
+ slices.push_back (OutSliceInfo (i.channel().type,
+ 0, // base
+ 0, // xStride,
+ 0, // yStride,
+ i.channel().xSampling,
+ i.channel().ySampling,
+ true)); // zero
+ }
+ else
+ {
+ //
+ // Channel i is present in the frame buffer.
+ //
+
+ slices.push_back (OutSliceInfo (j.slice().type,
+ j.slice().base,
+ j.slice().xStride,
+ j.slice().yStride,
+ j.slice().xSampling,
+ j.slice().ySampling,
+ false)); // zero
+ }
}
//
const FrameBuffer &
OutputFile::frameBuffer () const
{
- Lock lock (*_data);
+ Lock lock (*_data->_streamData);
return _data->frameBuffer;
}
-void
+void
OutputFile::writePixels (int numScanLines)
{
try
{
- Lock lock (*_data);
+ Lock lock (*_data->_streamData);
- if (_data->slices.size() == 0)
- throw Iex::ArgExc ("No frame buffer specified "
- "as pixel data source.");
+ if (_data->slices.size() == 0)
+ throw IEX_NAMESPACE::ArgExc ("No frame buffer specified "
+ "as pixel data source.");
//
// Maintain two iterators:
//
// Create a task group for all line buffer tasks. When the
// taskgroup goes out of scope, the destructor waits until
- // all tasks are complete.
+ // all tasks are complete.
//
-
+
TaskGroup taskGroup;
-
+
//
// Determine the range of lineBuffers that intersect the scan
- // line range. Then add the initial compression tasks to the
- // thread pool. We always add in at least one task but the
- // individual task might not do anything if numScanLines == 0.
+ // line range. Then add the initial compression tasks to the
+ // thread pool. We always add in at least one task but the
+ // individual task might not do anything if numScanLines == 0.
//
-
+
if (_data->lineOrder == INCREASING_Y)
{
int last = (_data->currentScanLine + (numScanLines - 1) -
_data->minY) / _data->linesInBuffer;
-
+
scanLineMin = _data->currentScanLine;
scanLineMax = _data->currentScanLine + numScanLines - 1;
-
+
int numTasks = max (min ((int)_data->lineBuffers.size(),
last - first + 1),
- 1);
+ 1);
for (int i = 0; i < numTasks; i++)
- {
+ {
ThreadPool::addGlobalTask
(new LineBufferTask (&taskGroup, _data, first + i,
scanLineMin, scanLineMax));
- }
-
+ }
+
nextCompressBuffer = first + numTasks;
stop = last + 1;
step = 1;
{
int last = (_data->currentScanLine - (numScanLines - 1) -
_data->minY) / _data->linesInBuffer;
-
+
scanLineMax = _data->currentScanLine;
scanLineMin = _data->currentScanLine - numScanLines + 1;
-
+
int numTasks = max (min ((int)_data->lineBuffers.size(),
first - last + 1),
- 1);
+ 1);
for (int i = 0; i < numTasks; i++)
- {
+ {
ThreadPool::addGlobalTask
(new LineBufferTask (&taskGroup, _data, first - i,
scanLineMin, scanLineMax));
- }
-
+ }
+
nextCompressBuffer = first - numTasks;
stop = last - 1;
step = -1;
}
-
+
while (true)
{
if (_data->missingScanLines <= 0)
{
- throw Iex::ArgExc ("Tried to write more scan lines "
+ throw IEX_NAMESPACE::ArgExc ("Tried to write more scan lines "
"than specified by the data window.");
}
-
- //
+
+ //
// Wait until the next line buffer is ready to be written
- //
+ //
LineBuffer *writeBuffer =
- _data->getLineBuffer (nextWriteBuffer);
+ _data->getLineBuffer (nextWriteBuffer);
writeBuffer->wait();
-
- int numLines = writeBuffer->scanLineMax -
+
+ int numLines = writeBuffer->scanLineMax -
writeBuffer->scanLineMin + 1;
_data->missingScanLines -= numLines;
-
- //
+
+ //
// If the line buffer is only partially full, then it is
- // not complete and we cannot write it to disk yet.
- //
+ // not complete and we cannot write it to disk yet.
+ //
if (writeBuffer->partiallyFull)
{
_data->currentScanLine = _data->currentScanLine +
step * numLines;
writeBuffer->post();
-
+
return;
}
-
- //
+
+ //
// Write the line buffer
- //
+ //
- writePixelData (_data, writeBuffer);
+ writePixelData (_data->_streamData, _data, writeBuffer);
nextWriteBuffer += step;
_data->currentScanLine = _data->currentScanLine +
step * numLines;
-
+
#ifdef DEBUG
-
+
assert (_data->currentScanLine ==
((_data->lineOrder == INCREASING_Y) ?
writeBuffer->scanLineMax + 1:
writeBuffer->scanLineMin - 1));
-
+
#endif
-
- //
+
+ //
// Release the lock on the line buffer
- //
+ //
writeBuffer->post();
-
- //
+
+ //
// If this was the last line buffer in the scanline range
- //
+ //
if (nextWriteBuffer == stop)
break;
-
- //
+
+ //
// If there are no more line buffers to compress,
// then only continue to write out remaining lineBuffers
- //
+ //
if (nextCompressBuffer == stop)
continue;
-
- //
+
+ //
// Add nextCompressBuffer as a compression task
- //
+ //
ThreadPool::addGlobalTask
(new LineBufferTask (&taskGroup, _data, nextCompressBuffer,
scanLineMin, scanLineMax));
-
- //
+
+ //
// Update the next line buffer we need to compress
- //
+ //
nextCompressBuffer += step;
}
-
- //
+
+ //
// Finish all tasks
- //
+ //
}
-
- //
- // Exeption handling:
- //
- // LineBufferTask::execute() may have encountered exceptions, but
- // those exceptions occurred in another thread, not in the thread
- // that is executing this call to OutputFile::writePixels().
- // LineBufferTask::execute() has caught all exceptions and stored
- // the exceptions' what() strings in the line buffers.
- // Now we check if any line buffer contains a stored exception; if
- // this is the case then we re-throw the exception in this thread.
- // (It is possible that multiple line buffers contain stored
- // exceptions. We re-throw the first exception we find and
- // ignore all others.)
- //
-
- const string *exception = 0;
-
- for (int i = 0; i < _data->lineBuffers.size(); ++i)
- {
+
+ //
+ // Exeption handling:
+ //
+ // LineBufferTask::execute() may have encountered exceptions, but
+ // those exceptions occurred in another thread, not in the thread
+ // that is executing this call to OutputFile::writePixels().
+ // LineBufferTask::execute() has caught all exceptions and stored
+ // the exceptions' what() strings in the line buffers.
+ // Now we check if any line buffer contains a stored exception; if
+ // this is the case then we re-throw the exception in this thread.
+ // (It is possible that multiple line buffers contain stored
+ // exceptions. We re-throw the first exception we find and
+ // ignore all others.)
+ //
+
+ const string *exception = 0;
+
+ for (size_t i = 0; i < _data->lineBuffers.size(); ++i)
+ {
LineBuffer *lineBuffer = _data->lineBuffers[i];
- if (lineBuffer->hasException && !exception)
- exception = &lineBuffer->exception;
+ if (lineBuffer->hasException && !exception)
+ exception = &lineBuffer->exception;
- lineBuffer->hasException = false;
- }
+ lineBuffer->hasException = false;
+ }
- if (exception)
- throw Iex::IoExc (*exception);
+ if (exception)
+ throw IEX_NAMESPACE::IoExc (*exception);
}
- catch (Iex::BaseExc &e)
+ catch (IEX_NAMESPACE::BaseExc &e)
{
- REPLACE_EXC (e, "Failed to write pixel data to image "
- "file \"" << fileName() << "\". " << e);
- throw;
+ REPLACE_EXC (e, "Failed to write pixel data to image "
+ "file \"" << fileName() << "\". " << e.what());
+ throw;
}
}
-int
+int
OutputFile::currentScanLine () const
{
- Lock lock (*_data);
+ Lock lock (*_data->_streamData);
return _data->currentScanLine;
}
-void
+void
OutputFile::copyPixels (InputFile &in)
{
- Lock lock (*_data);
+ Lock lock (*_data->_streamData);
//
// Check if this file's and and the InputFile's
const Header &inHdr = in.header();
if (inHdr.find("tiles") != inHdr.end())
- THROW (Iex::ArgExc, "Cannot copy pixels from image "
- "file \"" << in.fileName() << "\" to image "
- "file \"" << fileName() << "\". "
+ THROW (IEX_NAMESPACE::ArgExc, "Cannot copy pixels from image "
+ "file \"" << in.fileName() << "\" to image "
+ "file \"" << fileName() << "\". "
"The input file is tiled, but the output file is "
"not. Try using TiledOutputFile::copyPixels "
"instead.");
if (!(hdr.dataWindow() == inHdr.dataWindow()))
- THROW (Iex::ArgExc, "Cannot copy pixels from image "
- "file \"" << in.fileName() << "\" to image "
- "file \"" << fileName() << "\". "
+ THROW (IEX_NAMESPACE::ArgExc, "Cannot copy pixels from image "
+ "file \"" << in.fileName() << "\" to image "
+ "file \"" << fileName() << "\". "
"The files have different data windows.");
if (!(hdr.lineOrder() == inHdr.lineOrder()))
- THROW (Iex::ArgExc, "Quick pixel copy from image "
- "file \"" << in.fileName() << "\" to image "
- "file \"" << fileName() << "\" failed. "
- "The files have different line orders.");
+ THROW (IEX_NAMESPACE::ArgExc, "Quick pixel copy from image "
+ "file \"" << in.fileName() << "\" to image "
+ "file \"" << fileName() << "\" failed. "
+ "The files have different line orders.");
if (!(hdr.compression() == inHdr.compression()))
- THROW (Iex::ArgExc, "Quick pixel copy from image "
- "file \"" << in.fileName() << "\" to image "
- "file \"" << fileName() << "\" failed. "
- "The files use different compression methods.");
+ THROW (IEX_NAMESPACE::ArgExc, "Quick pixel copy from image "
+ "file \"" << in.fileName() << "\" to image "
+ "file \"" << fileName() << "\" failed. "
+ "The files use different compression methods.");
if (!(hdr.channels() == inHdr.channels()))
- THROW (Iex::ArgExc, "Quick pixel copy from image "
- "file \"" << in.fileName() << "\" to image "
- "file \"" << fileName() << "\" failed. "
- "The files have different channel lists.");
+ THROW (IEX_NAMESPACE::ArgExc, "Quick pixel copy from image "
+ "file \"" << in.fileName() << "\" to image "
+ "file \"" << fileName() << "\" failed. "
+ "The files have different channel lists.");
//
// Verify that no pixel data have been written to this file yet.
const Box2i &dataWindow = hdr.dataWindow();
if (_data->missingScanLines != dataWindow.max.y - dataWindow.min.y + 1)
- THROW (Iex::LogicExc, "Quick pixel copy from image "
- "file \"" << in.fileName() << "\" to image "
- "file \"" << fileName() << "\" failed. "
- "\"" << fileName() << "\" already contains "
- "pixel data.");
+ THROW (IEX_NAMESPACE::LogicExc, "Quick pixel copy from image "
+ "file \"" << in.fileName() << "\" to image "
+ "file \"" << fileName() << "\" failed. "
+ "\"" << fileName() << "\" already contains "
+ "pixel data.");
//
// Copy the pixel data.
while (_data->missingScanLines > 0)
{
- const char *pixelData;
- int pixelDataSize;
+ const char *pixelData;
+ int pixelDataSize;
- in.rawPixelData (_data->currentScanLine, pixelData, pixelDataSize);
+ in.rawPixelData (_data->currentScanLine, pixelData, pixelDataSize);
- writePixelData (_data, lineBufferMinY (_data->currentScanLine,
- _data->minY,
- _data->linesInBuffer),
+ writePixelData (_data->_streamData, _data, lineBufferMinY (_data->currentScanLine,
+ _data->minY,
+ _data->linesInBuffer),
pixelData, pixelDataSize);
- _data->currentScanLine += (_data->lineOrder == INCREASING_Y)?
- _data->linesInBuffer: -_data->linesInBuffer;
+ _data->currentScanLine += (_data->lineOrder == INCREASING_Y)?
+ _data->linesInBuffer: -_data->linesInBuffer;
- _data->missingScanLines -= _data->linesInBuffer;
+ _data->missingScanLines -= _data->linesInBuffer;
}
}
void
+OutputFile::copyPixels( InputPart & in)
+{
+ copyPixels(*in.file);
+}
+
+
+
+void
OutputFile::updatePreviewImage (const PreviewRgba newPixels[])
{
- Lock lock (*_data);
+ Lock lock (*_data->_streamData);
if (_data->previewPosition <= 0)
- THROW (Iex::LogicExc, "Cannot update preview image pixels. "
- "File \"" << fileName() << "\" does not "
- "contain a preview image.");
+ THROW (IEX_NAMESPACE::LogicExc, "Cannot update preview image pixels. "
+ "File \"" << fileName() << "\" does not "
+ "contain a preview image.");
//
// Store the new pixels in the header's preview image attribute.
//
PreviewImageAttribute &pia =
- _data->header.typedAttribute <PreviewImageAttribute> ("preview");
+ _data->header.typedAttribute <PreviewImageAttribute> ("preview");
PreviewImage &pi = pia.value();
PreviewRgba *pixels = pi.pixels();
int numPixels = pi.width() * pi.height();
for (int i = 0; i < numPixels; ++i)
- pixels[i] = newPixels[i];
+ pixels[i] = newPixels[i];
//
// Save the current file position, jump to the position in
// preview image, and jump back to the saved file position.
//
- Int64 savedPosition = _data->os->tellp();
+ Int64 savedPosition = _data->_streamData->os->tellp();
try
{
- _data->os->seekp (_data->previewPosition);
- pia.writeValueTo (*_data->os, _data->version);
- _data->os->seekp (savedPosition);
+ _data->_streamData->os->seekp (_data->previewPosition);
+ pia.writeValueTo (*_data->_streamData->os, _data->version);
+ _data->_streamData->os->seekp (savedPosition);
}
- catch (Iex::BaseExc &e)
+ catch (IEX_NAMESPACE::BaseExc &e)
{
- REPLACE_EXC (e, "Cannot update preview image pixels for "
- "file \"" << fileName() << "\". " << e);
- throw;
+ REPLACE_EXC (e, "Cannot update preview image pixels for "
+ "file \"" << fileName() << "\". " << e.what());
+ throw;
}
}
-void
+void
OutputFile::breakScanLine (int y, int offset, int length, char c)
{
- Lock lock (*_data);
+ Lock lock (*_data->_streamData);
- Int64 position =
- _data->lineOffsets[(y - _data->minY) / _data->linesInBuffer];
+ Int64 position =
+ _data->lineOffsets[(y - _data->minY) / _data->linesInBuffer];
if (!position)
- THROW (Iex::ArgExc, "Cannot overwrite scan line " << y << ". "
- "The scan line has not yet been stored in "
- "file \"" << fileName() << "\".");
+ THROW (IEX_NAMESPACE::ArgExc, "Cannot overwrite scan line " << y << ". "
+ "The scan line has not yet been stored in "
+ "file \"" << fileName() << "\".");
- _data->currentPosition = 0;
- _data->os->seekp (position + offset);
+ _data->_streamData->currentPosition = 0;
+ _data->_streamData->os->seekp (position + offset);
for (int i = 0; i < length; ++i)
- _data->os->write (&c, 1);
+ _data->_streamData->os->write (&c, 1);
}
-} // namespace Imf
+OPENEXR_IMF_INTERNAL_NAMESPACE_SOURCE_EXIT
//
// Copyright (c) 2004, Industrial Light & Magic, a division of Lucas
// Digital Ltd. LLC
-//
+//
// All rights reserved.
-//
+//
// Redistribution and use in source and binary forms, with or without
// modification, are permitted provided that the following conditions are
// met:
// distribution.
// * Neither the name of Industrial Light & Magic nor the names of
// its contributors may be used to endorse or promote products derived
-// from this software without specific prior written permission.
-//
+// from this software without specific prior written permission.
+//
// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
//
//-----------------------------------------------------------------------------
-#include <ImfHeader.h>
-#include <ImfFrameBuffer.h>
-#include <ImfThreading.h>
+#include "ImfHeader.h"
+#include "ImfFrameBuffer.h"
+#include "ImfThreading.h"
+#include "ImfGenericOutputFile.h"
+#include "ImfNamespace.h"
+#include "ImfForward.h"
+#include "ImfExport.h"
-namespace Imf {
+OPENEXR_IMF_INTERNAL_NAMESPACE_HEADER_ENTER
-class InputFile;
-struct PreviewRgba;
-
-class OutputFile
+class OutputFile : public GenericOutputFile
{
public:
// used to write the file (see ImfThreading.h).
//-----------------------------------------------------------
+ IMF_EXPORT
OutputFile (const char fileName[], const Header &header,
int numThreads = globalThreadCount());
// used to write the file (see ImfThreading.h).
//------------------------------------------------------------
- OutputFile (OStream &os, const Header &header,
+ IMF_EXPORT
+ OutputFile (OPENEXR_IMF_INTERNAL_NAMESPACE::OStream &os, const Header &header,
int numThreads = globalThreadCount());
// an incomplete file.
//-------------------------------------------------
+ IMF_EXPORT
virtual ~OutputFile ();
// Access to the file name
//------------------------
+ IMF_EXPORT
const char * fileName () const;
// Access to the file header
//--------------------------
+ IMF_EXPORT
const Header & header () const;
// after each call to writePixels.
//-------------------------------------------------------
+ IMF_EXPORT
void setFrameBuffer (const FrameBuffer &frameBuffer);
// Access to the current frame buffer
//-----------------------------------
+ IMF_EXPORT
const FrameBuffer & frameBuffer () const;
// header().dataWindow().max.y - header().dataWindow().min.y + 1.
//-------------------------------------------------------------------
+ IMF_EXPORT
void writePixels (int numScanLines = 1);
//
//------------------------------------------------------------------
+ IMF_EXPORT
int currentScanLine () const;
// "lineOrder" and "channels" attributes must be the same.
//--------------------------------------------------------------
+ IMF_EXPORT
void copyPixels (InputFile &in);
+
+ //-------------------------------------------------------------
+ // Shortcut to copy all pixels from an InputPart into this file
+ // - equivalent to copyPixel(InputFile &in) but for multipart files
+ //---------------------------------------------------------------
+
+ IMF_EXPORT
+ void copyPixels (InputPart &in);
+
//--------------------------------------------------------------
// updatePreviewImage() supplies a new set of pixels for the
// preview image attribute in the file's header. If the header
// does not contain a preview image, updatePreviewImage() throws
- // an Iex::LogicExc.
+ // an IEX_NAMESPACE::LogicExc.
//
// Note: updatePreviewImage() is necessary because images are
// often stored in a file incrementally, a few scan lines at a
//
//--------------------------------------------------------------
+ IMF_EXPORT
void updatePreviewImage (const PreviewRgba newPixels[]);
//---------------------------------------------------------
// Break a scan line -- for testing and debugging only:
- //
+ //
// breakScanLine(y,p,n,c) introduces an error into the
// output file by writing n copies of character c, starting
// p bytes from the beginning of the pixel data block that
//
//---------------------------------------------------------
+ IMF_EXPORT
void breakScanLine (int y, int offset, int length, char c);
private:
+ //------------------------------------------------------------
+ // Constructor -- attaches the OutputStreamMutex to the
+ // given one from MultiPartOutputFile. Set the previewPosition
+ // and lineOffsetsPosition which have been acquired from
+ // the constructor of MultiPartOutputFile as well.
+ //------------------------------------------------------------
+ OutputFile (const OutputPartData* part);
+
OutputFile (const OutputFile &); // not implemented
OutputFile & operator = (const OutputFile &); // not implemented
void initialize (const Header &header);
Data * _data;
+
+
+ friend class MultiPartOutputFile;
+
};
-} // namespace Imf
+OPENEXR_IMF_INTERNAL_NAMESPACE_HEADER_EXIT
+
#endif
--- /dev/null
+///////////////////////////////////////////////////////////////////////////
+//
+// Copyright (c) 2011, Industrial Light & Magic, a division of Lucas
+// Digital Ltd. LLC
+//
+// All rights reserved.
+//
+// Redistribution and use in source and binary forms, with or without
+// modification, are permitted provided that the following conditions are
+// met:
+// * Redistributions of source code must retain the above copyright
+// notice, this list of conditions and the following disclaimer.
+// * Redistributions in binary form must reproduce the above
+// copyright notice, this list of conditions and the following disclaimer
+// in the documentation and/or other materials provided with the
+// distribution.
+// * Neither the name of Industrial Light & Magic nor the names of
+// its contributors may be used to endorse or promote products derived
+// from this software without specific prior written permission.
+//
+// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+//
+///////////////////////////////////////////////////////////////////////////
+
+#include "ImfOutputPart.h"
+#include "ImfNamespace.h"
+
+OPENEXR_IMF_INTERNAL_NAMESPACE_SOURCE_ENTER
+
+OutputPart::OutputPart(MultiPartOutputFile& multiPartFile, int partNumber)
+{
+ file = multiPartFile.getOutputPart<OutputFile>(partNumber);
+}
+
+const char *
+OutputPart::fileName () const
+{
+ return file->fileName();
+}
+
+const Header &
+OutputPart::header () const
+{
+ return file->header();
+}
+
+void
+OutputPart::setFrameBuffer (const FrameBuffer &frameBuffer)
+{
+ file->setFrameBuffer(frameBuffer);
+}
+
+const FrameBuffer &
+OutputPart::frameBuffer () const
+{
+ return file->frameBuffer();
+}
+
+void
+OutputPart::writePixels (int numScanLines)
+{
+ file->writePixels(numScanLines);
+}
+
+int
+OutputPart::currentScanLine () const
+{
+ return file->currentScanLine();
+}
+
+void
+OutputPart::copyPixels (InputFile &in)
+{
+ file->copyPixels(in);
+}
+
+void
+OutputPart::copyPixels (InputPart &in)
+{
+ file->copyPixels(in);
+}
+
+void
+OutputPart::updatePreviewImage (const PreviewRgba newPixels[])
+{
+ file->updatePreviewImage(newPixels);
+}
+
+void
+OutputPart::breakScanLine (int y, int offset, int length, char c)
+{
+ file->breakScanLine(y, offset, length, c);
+}
+
+OPENEXR_IMF_INTERNAL_NAMESPACE_SOURCE_EXIT
--- /dev/null
+///////////////////////////////////////////////////////////////////////////
+//
+// Copyright (c) 2011, Industrial Light & Magic, a division of Lucas
+// Digital Ltd. LLC
+//
+// All rights reserved.
+//
+// Redistribution and use in source and binary forms, with or without
+// modification, are permitted provided that the following conditions are
+// met:
+// * Redistributions of source code must retain the above copyright
+// notice, this list of conditions and the following disclaimer.
+// * Redistributions in binary form must reproduce the above
+// copyright notice, this list of conditions and the following disclaimer
+// in the documentation and/or other materials provided with the
+// distribution.
+// * Neither the name of Industrial Light & Magic nor the names of
+// its contributors may be used to endorse or promote products derived
+// from this software without specific prior written permission.
+//
+// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+//
+///////////////////////////////////////////////////////////////////////////
+
+#ifndef IMFOUTPUTPART_H_
+#define IMFOUTPUTPART_H_
+
+#include "ImfMultiPartOutputFile.h"
+#include "ImfOutputFile.h"
+#include "ImfForward.h"
+#include "ImfNamespace.h"
+#include "ImfExport.h"
+
+OPENEXR_IMF_INTERNAL_NAMESPACE_HEADER_ENTER
+
+
+//---------------------------------------------------------------------
+// class OutputPart:
+//
+// Same interface as OutputFile. Please refer to OutputFile.
+//---------------------------------------------------------------------
+
+class OutputPart
+{
+ public:
+ IMF_EXPORT
+ OutputPart(MultiPartOutputFile& multiPartFile, int partNumber);
+
+ IMF_EXPORT
+ const char * fileName () const;
+ IMF_EXPORT
+ const Header & header () const;
+ IMF_EXPORT
+ void setFrameBuffer (const FrameBuffer &frameBuffer);
+ IMF_EXPORT
+ const FrameBuffer & frameBuffer () const;
+ IMF_EXPORT
+ void writePixels (int numScanLines = 1);
+ IMF_EXPORT
+ int currentScanLine () const;
+ IMF_EXPORT
+ void copyPixels (InputFile &in);
+ IMF_EXPORT
+ void copyPixels (InputPart &in);
+
+ IMF_EXPORT
+ void updatePreviewImage (const PreviewRgba newPixels[]);
+ IMF_EXPORT
+ void breakScanLine (int y, int offset, int length, char c);
+
+ private:
+ OutputFile* file;
+};
+
+
+OPENEXR_IMF_INTERNAL_NAMESPACE_HEADER_EXIT
+
+#endif /* IMFOUTPUTPART_H_ */
--- /dev/null
+///////////////////////////////////////////////////////////////////////////
+//
+// Copyright (c) 2011, Industrial Light & Magic, a division of Lucas
+// Digital Ltd. LLC
+//
+// All rights reserved.
+//
+// Redistribution and use in source and binary forms, with or without
+// modification, are permitted provided that the following conditions are
+// met:
+// * Redistributions of source code must retain the above copyright
+// notice, this list of conditions and the following disclaimer.
+// * Redistributions in binary form must reproduce the above
+// copyright notice, this list of conditions and the following disclaimer
+// in the documentation and/or other materials provided with the
+// distribution.
+// * Neither the name of Industrial Light & Magic nor the names of
+// its contributors may be used to endorse or promote products derived
+// from this software without specific prior written permission.
+//
+// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+//
+///////////////////////////////////////////////////////////////////////////
+
+#include "ImfOutputPartData.h"
+#include "ImfNamespace.h"
+
+OPENEXR_IMF_INTERNAL_NAMESPACE_SOURCE_ENTER
+
+
+OutputPartData::OutputPartData(OutputStreamMutex* mutex, const Header &header,
+ int partNumber, int numThreads, bool multipart):
+ header(header),
+ numThreads(numThreads),
+ partNumber(partNumber),
+ multipart(multipart),
+ mutex(mutex)
+{
+}
+
+
+OPENEXR_IMF_INTERNAL_NAMESPACE_SOURCE_EXIT
--- /dev/null
+///////////////////////////////////////////////////////////////////////////
+//
+// Copyright (c) 2011, Industrial Light & Magic, a division of Lucas
+// Digital Ltd. LLC
+//
+// All rights reserved.
+//
+// Redistribution and use in source and binary forms, with or without
+// modification, are permitted provided that the following conditions are
+// met:
+// * Redistributions of source code must retain the above copyright
+// notice, this list of conditions and the following disclaimer.
+// * Redistributions in binary form must reproduce the above
+// copyright notice, this list of conditions and the following disclaimer
+// in the documentation and/or other materials provided with the
+// distribution.
+// * Neither the name of Industrial Light & Magic nor the names of
+// its contributors may be used to endorse or promote products derived
+// from this software without specific prior written permission.
+//
+// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+//
+///////////////////////////////////////////////////////////////////////////
+
+#ifndef IMFOUTPUTPARTDATA_H_
+#define IMFOUTPUTPARTDATA_H_
+
+#include "ImfHeader.h"
+#include "ImfForward.h"
+#include "ImfNamespace.h"
+#include "ImfExport.h"
+
+OPENEXR_IMF_INTERNAL_NAMESPACE_HEADER_ENTER
+
+struct OutputPartData
+{
+ Header header;
+ Int64 chunkOffsetTablePosition;
+ Int64 previewPosition;
+ int numThreads;
+ int partNumber;
+ bool multipart;
+ OutputStreamMutex* mutex;
+
+ IMF_EXPORT
+ OutputPartData(OutputStreamMutex* mutex, const Header &header,
+ int partNumber, int numThreads, bool multipart);
+
+};
+
+OPENEXR_IMF_INTERNAL_NAMESPACE_HEADER_EXIT
+
+#endif /* IMFOUTPUTPARTDATA_H_ */
--- /dev/null
+///////////////////////////////////////////////////////////////////////////
+//
+// Copyright (c) 2011, Industrial Light & Magic, a division of Lucas
+// Digital Ltd. LLC
+//
+// All rights reserved.
+//
+// Redistribution and use in source and binary forms, with or without
+// modification, are permitted provided that the following conditions are
+// met:
+// * Redistributions of source code must retain the above copyright
+// notice, this list of conditions and the following disclaimer.
+// * Redistributions in binary form must reproduce the above
+// copyright notice, this list of conditions and the following disclaimer
+// in the documentation and/or other materials provided with the
+// distribution.
+// * Neither the name of Industrial Light & Magic nor the names of
+// its contributors may be used to endorse or promote products derived
+// from this software without specific prior written permission.
+//
+// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+//
+///////////////////////////////////////////////////////////////////////////
+
+#ifndef IMFOUTPUTSTREAMMUTEX_H_
+#define IMFOUTPUTSTREAMMUTEX_H_
+
+#include <vector>
+
+#include "ImfIO.h"
+#include "IlmThreadMutex.h"
+#include "ImfGenericOutputFile.h"
+#include "ImfNamespace.h"
+
+OPENEXR_IMF_INTERNAL_NAMESPACE_HEADER_ENTER
+
+using ILMTHREAD_NAMESPACE::Mutex;
+
+//
+// Used to wrap OPENEXR_IMF_INTERNAL_NAMESPACE::OStream as a Mutex.
+//
+struct OutputStreamMutex : public Mutex
+{
+ OPENEXR_IMF_INTERNAL_NAMESPACE::OStream* os;
+ Int64 currentPosition;
+
+ OutputStreamMutex()
+ {
+ os = 0;
+ currentPosition = 0;
+ }
+};
+
+OPENEXR_IMF_INTERNAL_NAMESPACE_HEADER_EXIT
+
+
+
+
+
+#endif /* IMFOUTPUTSTREAMMUTEX_H_ */
--- /dev/null
+///////////////////////////////////////////////////////////////////////////
+//
+// Copyright (c) 2012, Weta Digital Ltd
+//
+// All rights reserved.
+//
+// Redistribution and use in source and binary forms, with or without
+// modification, are permitted provided that the following conditions are
+// met:
+// * Redistributions of source code must retain the above copyright
+// notice, this list of conditions and the following disclaimer.
+// * Redistributions in binary form must reproduce the above
+// copyright notice, this list of conditions and the following disclaimer
+// in the documentation and/or other materials provided with the
+// distribution.
+// * Neither the name of Weta Digital nor the names of
+// its contributors may be used to endorse or promote products derived
+// from this software without specific prior written permission.
+//
+// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+//
+///////////////////////////////////////////////////////////////////////////
+
+
+#ifndef INCLUDED_IMF_PARTHELPER_H
+#define INCLUDED_IMF_PARTHELPER_H
+
+//-----------------------------------------------------------------------------
+//
+// Functions to help split channels into separate parts: provide a list of
+// channels, with desired views. call SplitChannels to assign a part to each
+// layer, or correct the name of the channel.
+// Also can enumerate the parts in a file and list which parts channels are in
+//
+// This is a good way to offer a 'create Multipart file' checkbox to the user in a
+// write dialog box: Populate a list of MultiViewChannelName objects,
+// call SplitChannels with whether single or multipart files are required.
+// Then write the number of parts it specifies, using internal_name for the channel
+// names in the ChannelList and FrameBuffer objects. There should be no need
+// for different codepaths for single part and multipart files
+//
+// Similarly, on reading a file as a MultiPartInputFile, use GetChannelsInMultiPartFile to
+// enumerate all channels in the file, using internal_name in FrameBuffer objects
+// to read the channel
+//
+//
+//-----------------------------------------------------------------------------
+
+#include "ImfForward.h"
+#include "ImfNamespace.h"
+#include "ImfExport.h"
+#include "ImfMultiPartInputFile.h"
+#include "ImfChannelList.h"
+#include "ImfStringVectorAttribute.h"
+#include "ImfStandardAttributes.h"
+#include "ImfMultiView.h"
+
+#include <string>
+#include <map>
+#include <set>
+
+OPENEXR_IMF_INTERNAL_NAMESPACE_HEADER_ENTER
+
+struct MultiViewChannelName{
+
+public:
+ std::string name; ///< name of channel
+ std::string view; ///< view for channel
+
+ int part_number; ///< part number: updated by SplitChannels
+ std::string internal_name;///< name used in headers: in singlepart mode, may contain viewname
+
+ virtual ~MultiViewChannelName() {}
+
+ //return layer for this channel, or "" if no layer
+ std::string getLayer() const
+ {
+ std::size_t q=name.rfind('.');
+ if( q==name.npos )
+ {
+ return "";
+ }
+ return name.substr(0,q);
+
+ }
+
+ std::string getSuffix() const
+ {
+ std::size_t q=name.rfind('.');
+ if( q==name.npos )
+ {
+ return name;
+ }
+ return name.substr(q+1);
+
+ }
+
+};
+
+
+
+//
+///\brief assigns individual channels to different parts based on their layer and view name
+/// input is an array, list, vector etc of MultiViewChannelName objects
+/// on entry, each MultiViewChannelName name/view must be set (view can be empty if not multiview)
+///
+/// if singlepart set, then on exit part_number will be zero, and internal_name will have view name inserted
+/// otherwise, each channel will be assigned to a different part based on its layer name and view name
+///
+/// @param begin pointer to first MultiViewChannelName item
+/// @param end pointer to end of MultiViewChannelName item array
+/// @return total number of parts required
+//
+
+template<typename T> int
+SplitChannels(const T & begin,const T & end,bool multipart=true,const std::string & heroView="")
+{
+ if(!multipart)
+ {
+ for(T i=begin;i!=end;i++)
+ {
+ i->part_number=0;
+
+ //does this have a view name set?
+ if(i->view=="")
+ {
+ i->internal_name=i->name;
+ }else{
+
+ std::string lname = i->getLayer();
+
+ // no layer, only non-hero views get view name in layer name
+
+
+ if(lname=="")
+ {
+ if(i->view==heroView)
+ {
+ i->internal_name = i->name;
+ }else{
+ i->internal_name = i->view+"."+i->name;
+ }
+ }else{
+ i->internal_name = lname+"."+i->view+"."+i->getSuffix();
+ }
+ }
+ }
+ // single part created
+ return 1;
+ }else{
+ // step 1: extract individual layers and parts
+ // for each layer, enumerate which views are active
+
+ std::map< std::string , std::set< std::string > > viewsInLayers;
+ for(T i=begin;i!=end;i++)
+ {
+ viewsInLayers[i->getLayer()].insert(i->view);
+ }
+
+ // step 2: assign a part number to each layer/view
+
+ std::map< std::pair<std::string,std::string> , int > layerToPart;
+
+ int partCount=0;
+
+ for(std::map< std::string , std::set< std::string > >::const_iterator layer=viewsInLayers.begin();
+ layer!=viewsInLayers.end();layer++)
+ {
+ // if this layer has a heroView, insert that first
+ bool layer_has_hero = layer->second.find(heroView)!=layer->second.end();
+ if( layer_has_hero )
+ {
+ layerToPart[ std::make_pair(layer->first,heroView) ] = partCount++;
+ }
+
+
+ // insert other layers which aren't the hero view
+ for(std::set< std::string >::const_iterator view=layer->second.begin();
+ view!=layer->second.end();view++)
+ {
+ if(*view!=heroView)
+ {
+ layerToPart[ std::make_pair(layer->first,*view) ] = partCount++;
+ }
+ }
+
+ }
+
+ // step 3: update part number of each provided channel
+
+ for( T i=begin;i!=end;i++)
+ {
+ i->internal_name=i->name;
+ i->part_number = layerToPart[ std::make_pair(i->getLayer(),i->view) ];
+ }
+
+
+ // return number of parts created
+ return partCount;
+ }
+}
+
+//
+// populate the chans vector<MultiViewChannelName> with a list of channels in the file
+// and their corresponding part number
+//
+template<class T> void
+GetChannelsInMultiPartFile(const MultiPartInputFile & file,T & chans)
+{
+ bool has_multiview=false;
+ StringVector mview;
+ if(file.parts()==1)
+ {
+ if(hasMultiView(file.header(0)))
+ {
+ mview=multiView(file.header(0));
+ has_multiview=true;
+ }
+ }
+
+ for(int p=0;p<file.parts();p++)
+ {
+ const ChannelList & c=file.header(p).channels();
+
+ std::string view="";
+ if(file.header(p).hasView())
+ {
+ view=file.header(p).view();
+ }
+ for(ChannelList::ConstIterator i=c.begin();i!=c.end();i++)
+ {
+ MultiViewChannelName m;
+ m.name=std::string(i.name());
+ m.internal_name=m.name;
+
+ if(has_multiview)
+ {
+ m.view=viewFromChannelName(m.name,mview);
+ m.name=removeViewName(m.internal_name,m.view);
+ }else{
+ m.view=view;
+ }
+ m.part_number=p;
+ chans.push_back(m);
+
+ }
+ }
+}
+
+OPENEXR_IMF_INTERNAL_NAMESPACE_HEADER_EXIT
+
+#endif
--- /dev/null
+///////////////////////////////////////////////////////////////////////////
+//
+// Copyright (c) 2011, Industrial Light & Magic, a division of Lucas
+// Digital Ltd. LLC
+//
+// All rights reserved.
+//
+// Redistribution and use in source and binary forms, with or without
+// modification, are permitted provided that the following conditions are
+// met:
+// * Redistributions of source code must retain the above copyright
+// notice, this list of conditions and the following disclaimer.
+// * Redistributions in binary form must reproduce the above
+// copyright notice, this list of conditions and the following disclaimer
+// in the documentation and/or other materials provided with the
+// distribution.
+// * Neither the name of Industrial Light & Magic nor the names of
+// its contributors may be used to endorse or promote products derived
+// from this software without specific prior written permission.
+//
+// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+//
+///////////////////////////////////////////////////////////////////////////
+
+#include <ImfPartType.h>
+#include "ImfNamespace.h"
+
+OPENEXR_IMF_INTERNAL_NAMESPACE_SOURCE_ENTER
+
+using std::string;
+
+bool isImage(const string& name)
+{
+ return (name == SCANLINEIMAGE || name == TILEDIMAGE);
+}
+
+bool isTiled(const string& name)
+{
+ return (name == TILEDIMAGE || name == DEEPTILE);
+}
+
+bool isDeepData(const string& name)
+{
+ return (name == DEEPTILE || name == DEEPSCANLINE);
+}
+
+bool isSupportedType(const string& name)
+{
+ return (name == SCANLINEIMAGE || name == TILEDIMAGE ||
+ name == DEEPSCANLINE || name == DEEPTILE);
+}
+
+OPENEXR_IMF_INTERNAL_NAMESPACE_SOURCE_EXIT
--- /dev/null
+///////////////////////////////////////////////////////////////////////////
+//
+// Copyright (c) 2011, Industrial Light & Magic, a division of Lucas
+// Digital Ltd. LLC
+//
+// All rights reserved.
+//
+// Redistribution and use in source and binary forms, with or without
+// modification, are permitted provided that the following conditions are
+// met:
+// * Redistributions of source code must retain the above copyright
+// notice, this list of conditions and the following disclaimer.
+// * Redistributions in binary form must reproduce the above
+// copyright notice, this list of conditions and the following disclaimer
+// in the documentation and/or other materials provided with the
+// distribution.
+// * Neither the name of Industrial Light & Magic nor the names of
+// its contributors may be used to endorse or promote products derived
+// from this software without specific prior written permission.
+//
+// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+//
+///////////////////////////////////////////////////////////////////////////
+
+#ifndef IMFPARTTYPE_H_
+#define IMFPARTTYPE_H_
+
+#include <string>
+#include "ImfNamespace.h"
+#include "ImfExport.h"
+
+OPENEXR_IMF_INTERNAL_NAMESPACE_HEADER_ENTER
+
+
+const std::string SCANLINEIMAGE = "scanlineimage";
+const std::string TILEDIMAGE = "tiledimage";
+const std::string DEEPSCANLINE = "deepscanline";
+const std::string DEEPTILE = "deeptile";
+
+IMF_EXPORT bool isImage(const std::string& name);
+
+IMF_EXPORT bool isTiled(const std::string& name);
+
+IMF_EXPORT bool isDeepData(const std::string& name);
+
+IMF_EXPORT bool isSupportedType(const std::string& name);
+
+
+OPENEXR_IMF_INTERNAL_NAMESPACE_HEADER_EXIT
+
+
+#endif /* IMFPARTTYPE_H_ */
//
// Copyright (c) 2002, Industrial Light & Magic, a division of Lucas
// Digital Ltd. LLC
-//
+//
// All rights reserved.
-//
+//
// Redistribution and use in source and binary forms, with or without
// modification, are permitted provided that the following conditions are
// met:
// distribution.
// * Neither the name of Industrial Light & Magic nor the names of
// its contributors may be used to endorse or promote products derived
-// from this software without specific prior written permission.
-//
+// from this software without specific prior written permission.
+//
// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
//
//-----------------------------------------------------------------------------
-namespace Imf {
+#include "ImfNamespace.h"
+
+OPENEXR_IMF_INTERNAL_NAMESPACE_HEADER_ENTER
enum PixelType
{
- UINT = 0, // unsigned int (32 bit)
- HALF = 1, // half (16 bit floating point)
- FLOAT = 2, // float (32 bit floating point)
+ UINT = 0, // unsigned int (32 bit)
+ HALF = 1, // half (16 bit floating point)
+ FLOAT = 2, // float (32 bit floating point)
NUM_PIXELTYPES // number of different pixel types
};
-} // namespace Imf
+OPENEXR_IMF_INTERNAL_NAMESPACE_HEADER_EXIT
+
+
+
+
#endif
//
// Copyright (c) 2004, Industrial Light & Magic, a division of Lucas
// Digital Ltd. LLC
-//
+//
// All rights reserved.
-//
+//
// Redistribution and use in source and binary forms, with or without
// modification, are permitted provided that the following conditions are
// met:
// distribution.
// * Neither the name of Industrial Light & Magic nor the names of
// its contributors may be used to endorse or promote products derived
-// from this software without specific prior written permission.
-//
+// from this software without specific prior written permission.
+//
// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
//
//-----------------------------------------------------------------------------
-#include <ImfPizCompressor.h>
-#include <ImfHeader.h>
-#include <ImfChannelList.h>
-#include <ImfHuf.h>
-#include <ImfWav.h>
-#include <ImfMisc.h>
-#include <ImfCheckedArithmetic.h>
+#include "ImfPizCompressor.h"
+#include "ImfHeader.h"
+#include "ImfChannelList.h"
+#include "ImfHuf.h"
+#include "ImfWav.h"
+#include "ImfMisc.h"
+#include "ImfCheckedArithmetic.h"
#include <ImathFun.h>
#include <ImathBox.h>
#include <Iex.h>
-#include <ImfIO.h>
-#include <ImfXdr.h>
-#include <ImfAutoArray.h>
+#include "ImfIO.h"
+#include "ImfXdr.h"
+#include "ImfAutoArray.h"
#include <string.h>
#include <assert.h>
+#include "ImfNamespace.h"
-namespace Imf {
+OPENEXR_IMF_INTERNAL_NAMESPACE_SOURCE_ENTER
-using Imath::divp;
-using Imath::modp;
-using Imath::Box2i;
-using Imath::V2i;
-using Iex::InputExc;
+using IMATH_NAMESPACE::divp;
+using IMATH_NAMESPACE::modp;
+using IMATH_NAMESPACE::Box2i;
+using IMATH_NAMESPACE::V2i;
+using IEX_NAMESPACE::InputExc;
namespace {
void
bitmapFromData (const unsigned short data[/*nData*/],
- int nData,
- unsigned char bitmap[BITMAP_SIZE],
- unsigned short &minNonZero,
- unsigned short &maxNonZero)
+ int nData,
+ unsigned char bitmap[BITMAP_SIZE],
+ unsigned short &minNonZero,
+ unsigned short &maxNonZero)
{
for (int i = 0; i < BITMAP_SIZE; ++i)
- bitmap[i] = 0;
+ bitmap[i] = 0;
for (int i = 0; i < nData; ++i)
- bitmap[data[i] >> 3] |= (1 << (data[i] & 7));
+ bitmap[data[i] >> 3] |= (1 << (data[i] & 7));
bitmap[0] &= ~1; // zero is not explicitly stored in
- // the bitmap; we assume that the
- // data always contain zeroes
+ // the bitmap; we assume that the
+ // data always contain zeroes
minNonZero = BITMAP_SIZE - 1;
maxNonZero = 0;
for (int i = 0; i < BITMAP_SIZE; ++i)
{
- if (bitmap[i])
- {
- if (minNonZero > i)
- minNonZero = i;
- if (maxNonZero < i)
- maxNonZero = i;
- }
+ if (bitmap[i])
+ {
+ if (minNonZero > i)
+ minNonZero = i;
+ if (maxNonZero < i)
+ maxNonZero = i;
+ }
}
}
unsigned short
forwardLutFromBitmap (const unsigned char bitmap[BITMAP_SIZE],
- unsigned short lut[USHORT_RANGE])
+ unsigned short lut[USHORT_RANGE])
{
int k = 0;
for (int i = 0; i < USHORT_RANGE; ++i)
{
- if ((i == 0) || (bitmap[i >> 3] & (1 << (i & 7))))
- lut[i] = k++;
- else
- lut[i] = 0;
+ if ((i == 0) || (bitmap[i >> 3] & (1 << (i & 7))))
+ lut[i] = k++;
+ else
+ lut[i] = 0;
}
return k - 1; // maximum value stored in lut[],
unsigned short
reverseLutFromBitmap (const unsigned char bitmap[BITMAP_SIZE],
- unsigned short lut[USHORT_RANGE])
+ unsigned short lut[USHORT_RANGE])
{
int k = 0;
for (int i = 0; i < USHORT_RANGE; ++i)
{
- if ((i == 0) || (bitmap[i >> 3] & (1 << (i & 7))))
- lut[k++] = i;
+ if ((i == 0) || (bitmap[i >> 3] & (1 << (i & 7))))
+ lut[k++] = i;
}
int n = k - 1;
while (k < USHORT_RANGE)
- lut[k++] = 0;
+ lut[k++] = 0;
return n; // maximum k where lut[k] is non-zero,
} // i.e. number of ones in bitmap minus 1
void
applyLut (const unsigned short lut[USHORT_RANGE],
- unsigned short data[/*nData*/],
- int nData)
+ unsigned short data[/*nData*/],
+ int nData)
{
for (int i = 0; i < nData; ++i)
- data[i] = lut[data[i]];
+ data[i] = lut[data[i]];
}
bool onlyHalfChannels = true;
for (ChannelList::ConstIterator c = channels.begin();
- c != channels.end();
- ++c)
+ c != channels.end();
+ ++c)
{
- _numChans++;
+ _numChans++;
- assert (pixelTypeSize (c.channel().type) % pixelTypeSize (HALF) == 0);
+ assert (pixelTypeSize (c.channel().type) % pixelTypeSize (HALF) == 0);
- if (c.channel().type != HALF)
- onlyHalfChannels = false;
+ if (c.channel().type != HALF)
+ onlyHalfChannels = false;
}
_channelData = new ChannelData[_numChans];
//
if (onlyHalfChannels && (sizeof (half) == pixelTypeSize (HALF)))
- _format = NATIVE;
+ _format = NATIVE;
}
int
PizCompressor::compress (const char *inPtr,
- int inSize,
- int minY,
- const char *&outPtr)
+ int inSize,
+ int minY,
+ const char *&outPtr)
{
return compress (inPtr,
- inSize,
- Box2i (V2i (_minX, minY),
- V2i (_maxX, minY + numScanLines() - 1)),
- outPtr);
+ inSize,
+ Box2i (V2i (_minX, minY),
+ V2i (_maxX, minY + numScanLines() - 1)),
+ outPtr);
}
int
PizCompressor::compressTile (const char *inPtr,
- int inSize,
- Imath::Box2i range,
- const char *&outPtr)
+ int inSize,
+ IMATH_NAMESPACE::Box2i range,
+ const char *&outPtr)
{
return compress (inPtr, inSize, range, outPtr);
}
int
PizCompressor::uncompress (const char *inPtr,
- int inSize,
- int minY,
- const char *&outPtr)
+ int inSize,
+ int minY,
+ const char *&outPtr)
{
return uncompress (inPtr,
- inSize,
- Box2i (V2i (_minX, minY),
- V2i (_maxX, minY + numScanLines() - 1)),
- outPtr);
+ inSize,
+ Box2i (V2i (_minX, minY),
+ V2i (_maxX, minY + numScanLines() - 1)),
+ outPtr);
}
int
PizCompressor::uncompressTile (const char *inPtr,
- int inSize,
- Imath::Box2i range,
- const char *&outPtr)
+ int inSize,
+ IMATH_NAMESPACE::Box2i range,
+ const char *&outPtr)
{
return uncompress (inPtr, inSize, range, outPtr);
}
int
PizCompressor::compress (const char *inPtr,
- int inSize,
- Imath::Box2i range,
- const char *&outPtr)
+ int inSize,
+ IMATH_NAMESPACE::Box2i range,
+ const char *&outPtr)
{
//
// This is the compress function which is used by both the tiled and
//
//
- // Special case Â- empty input buffer
+ // Special case �- empty input buffer
//
if (inSize == 0)
{
- outPtr = _outBuffer;
- return 0;
+ outPtr = _outBuffer;
+ return 0;
}
//
int maxX = range.max.x;
int minY = range.min.y;
int maxY = range.max.y;
-
+
if (maxY > _maxY)
maxY = _maxY;
-
+
if (maxX > _maxX)
maxX = _maxX;
int i = 0;
for (ChannelList::ConstIterator c = _channels.begin();
- c != _channels.end();
- ++c, ++i)
+ c != _channels.end();
+ ++c, ++i)
{
- ChannelData &cd = _channelData[i];
+ ChannelData &cd = _channelData[i];
- cd.start = tmpBufferEnd;
- cd.end = cd.start;
+ cd.start = tmpBufferEnd;
+ cd.end = cd.start;
- cd.nx = numSamples (c.channel().xSampling, minX, maxX);
- cd.ny = numSamples (c.channel().ySampling, minY, maxY);
- cd.ys = c.channel().ySampling;
+ cd.nx = numSamples (c.channel().xSampling, minX, maxX);
+ cd.ny = numSamples (c.channel().ySampling, minY, maxY);
+ cd.ys = c.channel().ySampling;
- cd.size = pixelTypeSize (c.channel().type) / pixelTypeSize (HALF);
+ cd.size = pixelTypeSize (c.channel().type) / pixelTypeSize (HALF);
- tmpBufferEnd += cd.nx * cd.ny * cd.size;
+ tmpBufferEnd += cd.nx * cd.ny * cd.size;
}
if (_format == XDR)
{
- //
- // Machine-independent (Xdr) data format
- //
-
- for (int y = minY; y <= maxY; ++y)
- {
- for (int i = 0; i < _numChans; ++i)
- {
- ChannelData &cd = _channelData[i];
-
- if (modp (y, cd.ys) != 0)
- continue;
-
- for (int x = cd.nx * cd.size; x > 0; --x)
- {
- Xdr::read <CharPtrIO> (inPtr, *cd.end);
- ++cd.end;
- }
- }
- }
+ //
+ // Machine-independent (Xdr) data format
+ //
+
+ for (int y = minY; y <= maxY; ++y)
+ {
+ for (int i = 0; i < _numChans; ++i)
+ {
+ ChannelData &cd = _channelData[i];
+
+ if (modp (y, cd.ys) != 0)
+ continue;
+
+ for (int x = cd.nx * cd.size; x > 0; --x)
+ {
+ Xdr::read <CharPtrIO> (inPtr, *cd.end);
+ ++cd.end;
+ }
+ }
+ }
}
else
{
- //
- // Native, machine-dependent data format
- //
-
- for (int y = minY; y <= maxY; ++y)
- {
- for (int i = 0; i < _numChans; ++i)
- {
- ChannelData &cd = _channelData[i];
-
- if (modp (y, cd.ys) != 0)
- continue;
-
- int n = cd.nx * cd.size;
- memcpy (cd.end, inPtr, n * sizeof (unsigned short));
- inPtr += n * sizeof (unsigned short);
- cd.end += n;
- }
- }
+ //
+ // Native, machine-dependent data format
+ //
+
+ for (int y = minY; y <= maxY; ++y)
+ {
+ for (int i = 0; i < _numChans; ++i)
+ {
+ ChannelData &cd = _channelData[i];
+
+ if (modp (y, cd.ys) != 0)
+ continue;
+
+ int n = cd.nx * cd.size;
+ memcpy (cd.end, inPtr, n * sizeof (unsigned short));
+ inPtr += n * sizeof (unsigned short);
+ cd.end += n;
+ }
+ }
}
#if defined (DEBUG)
- for (int i = 1; i < _numChans; ++i)
- assert (_channelData[i-1].end == _channelData[i].start);
+ for (int i = 1; i < _numChans; ++i)
+ assert (_channelData[i-1].end == _channelData[i].start);
- assert (_channelData[_numChans-1].end == tmpBufferEnd);
+ assert (_channelData[_numChans-1].end == tmpBufferEnd);
#endif
unsigned short maxNonZero;
bitmapFromData (_tmpBuffer,
- tmpBufferEnd - _tmpBuffer,
- bitmap,
- minNonZero, maxNonZero);
+ tmpBufferEnd - _tmpBuffer,
+ bitmap,
+ minNonZero, maxNonZero);
AutoArray <unsigned short, USHORT_RANGE> lut;
unsigned short maxValue = forwardLutFromBitmap (bitmap, lut);
if (minNonZero <= maxNonZero)
{
- Xdr::write <CharPtrIO> (buf, (char *) &bitmap[0] + minNonZero,
- maxNonZero - minNonZero + 1);
+ Xdr::write <CharPtrIO> (buf, (char *) &bitmap[0] + minNonZero,
+ maxNonZero - minNonZero + 1);
}
//
for (int i = 0; i < _numChans; ++i)
{
- ChannelData &cd = _channelData[i];
-
- for (int j = 0; j < cd.size; ++j)
- {
- wav2Encode (cd.start + j,
- cd.nx, cd.size,
- cd.ny, cd.nx * cd.size,
- maxValue);
- }
+ ChannelData &cd = _channelData[i];
+
+ for (int j = 0; j < cd.size; ++j)
+ {
+ wav2Encode (cd.start + j,
+ cd.nx, cd.size,
+ cd.ny, cd.nx * cd.size,
+ maxValue);
+ }
}
//
int
PizCompressor::uncompress (const char *inPtr,
- int inSize,
- Imath::Box2i range,
- const char *&outPtr)
+ int inSize,
+ IMATH_NAMESPACE::Box2i range,
+ const char *&outPtr)
{
//
// This is the cunompress function which is used by both the tiled and
// scanline decompression routines.
//
-
+
//
// Special case - empty input buffer
//
if (inSize == 0)
{
- outPtr = _outBuffer;
- return 0;
+ outPtr = _outBuffer;
+ return 0;
}
//
int maxX = range.max.x;
int minY = range.min.y;
int maxY = range.max.y;
-
+
if (maxY > _maxY)
maxY = _maxY;
-
+
if (maxX > _maxX)
maxX = _maxX;
int i = 0;
for (ChannelList::ConstIterator c = _channels.begin();
- c != _channels.end();
- ++c, ++i)
+ c != _channels.end();
+ ++c, ++i)
{
- ChannelData &cd = _channelData[i];
+ ChannelData &cd = _channelData[i];
- cd.start = tmpBufferEnd;
- cd.end = cd.start;
+ cd.start = tmpBufferEnd;
+ cd.end = cd.start;
- cd.nx = numSamples (c.channel().xSampling, minX, maxX);
- cd.ny = numSamples (c.channel().ySampling, minY, maxY);
- cd.ys = c.channel().ySampling;
+ cd.nx = numSamples (c.channel().xSampling, minX, maxX);
+ cd.ny = numSamples (c.channel().ySampling, minY, maxY);
+ cd.ys = c.channel().ySampling;
- cd.size = pixelTypeSize (c.channel().type) / pixelTypeSize (HALF);
+ cd.size = pixelTypeSize (c.channel().type) / pixelTypeSize (HALF);
- tmpBufferEnd += cd.nx * cd.ny * cd.size;
+ tmpBufferEnd += cd.nx * cd.ny * cd.size;
}
//
if (maxNonZero >= BITMAP_SIZE)
{
- throw InputExc ("Error in header for PIZ-compressed data "
- "(invalid bitmap size).");
+ throw InputExc ("Error in header for PIZ-compressed data "
+ "(invalid bitmap size).");
}
if (minNonZero <= maxNonZero)
{
- Xdr::read <CharPtrIO> (inPtr, (char *) &bitmap[0] + minNonZero,
- maxNonZero - minNonZero + 1);
+ Xdr::read <CharPtrIO> (inPtr, (char *) &bitmap[0] + minNonZero,
+ maxNonZero - minNonZero + 1);
}
AutoArray <unsigned short, USHORT_RANGE> lut;
int length;
Xdr::read <CharPtrIO> (inPtr, length);
+ if (length > inSize)
+ {
+ throw InputExc ("Error in header for PIZ-compressed data "
+ "(invalid array length).");
+ }
+
hufUncompress (inPtr, length, _tmpBuffer, tmpBufferEnd - _tmpBuffer);
//
for (int i = 0; i < _numChans; ++i)
{
- ChannelData &cd = _channelData[i];
-
- for (int j = 0; j < cd.size; ++j)
- {
- wav2Decode (cd.start + j,
- cd.nx, cd.size,
- cd.ny, cd.nx * cd.size,
- maxValue);
- }
+ ChannelData &cd = _channelData[i];
+
+ for (int j = 0; j < cd.size; ++j)
+ {
+ wav2Decode (cd.start + j,
+ cd.nx, cd.size,
+ cd.ny, cd.nx * cd.size,
+ maxValue);
+ }
}
//
//
applyLut (lut, _tmpBuffer, tmpBufferEnd - _tmpBuffer);
-
+
//
// Rearrange the pixel data into the format expected by the caller.
//
if (_format == XDR)
{
- //
- // Machine-independent (Xdr) data format
- //
-
- for (int y = minY; y <= maxY; ++y)
- {
- for (int i = 0; i < _numChans; ++i)
- {
- ChannelData &cd = _channelData[i];
-
- if (modp (y, cd.ys) != 0)
- continue;
-
- for (int x = cd.nx * cd.size; x > 0; --x)
- {
- Xdr::write <CharPtrIO> (outEnd, *cd.end);
- ++cd.end;
- }
- }
- }
+ //
+ // Machine-independent (Xdr) data format
+ //
+
+ for (int y = minY; y <= maxY; ++y)
+ {
+ for (int i = 0; i < _numChans; ++i)
+ {
+ ChannelData &cd = _channelData[i];
+
+ if (modp (y, cd.ys) != 0)
+ continue;
+
+ for (int x = cd.nx * cd.size; x > 0; --x)
+ {
+ Xdr::write <CharPtrIO> (outEnd, *cd.end);
+ ++cd.end;
+ }
+ }
+ }
}
else
{
- //
- // Native, machine-dependent data format
- //
-
- for (int y = minY; y <= maxY; ++y)
- {
- for (int i = 0; i < _numChans; ++i)
- {
- ChannelData &cd = _channelData[i];
-
- if (modp (y, cd.ys) != 0)
- continue;
-
- int n = cd.nx * cd.size;
- memcpy (outEnd, cd.end, n * sizeof (unsigned short));
- outEnd += n * sizeof (unsigned short);
- cd.end += n;
- }
- }
+ //
+ // Native, machine-dependent data format
+ //
+
+ for (int y = minY; y <= maxY; ++y)
+ {
+ for (int i = 0; i < _numChans; ++i)
+ {
+ ChannelData &cd = _channelData[i];
+
+ if (modp (y, cd.ys) != 0)
+ continue;
+
+ int n = cd.nx * cd.size;
+ memcpy (outEnd, cd.end, n * sizeof (unsigned short));
+ outEnd += n * sizeof (unsigned short);
+ cd.end += n;
+ }
+ }
}
#if defined (DEBUG)
- for (int i = 1; i < _numChans; ++i)
- assert (_channelData[i-1].end == _channelData[i].start);
+ for (int i = 1; i < _numChans; ++i)
+ assert (_channelData[i-1].end == _channelData[i].start);
- assert (_channelData[_numChans-1].end == tmpBufferEnd);
+ assert (_channelData[_numChans-1].end == tmpBufferEnd);
#endif
}
-} // namespace Imf
+OPENEXR_IMF_INTERNAL_NAMESPACE_SOURCE_EXIT
//
// Copyright (c) 2004, Industrial Light & Magic, a division of Lucas
// Digital Ltd. LLC
-//
+//
// All rights reserved.
-//
+//
// Redistribution and use in source and binary forms, with or without
// modification, are permitted provided that the following conditions are
// met:
// distribution.
// * Neither the name of Industrial Light & Magic nor the names of
// its contributors may be used to endorse or promote products derived
-// from this software without specific prior written permission.
-//
+// from this software without specific prior written permission.
+//
// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
//
//-----------------------------------------------------------------------------
-#include <ImfCompressor.h>
+#include "ImfCompressor.h"
+#include "ImfNamespace.h"
+#include "ImfExport.h"
+#include "ImfForward.h"
-namespace Imf {
-class ChannelList;
+OPENEXR_IMF_INTERNAL_NAMESPACE_HEADER_ENTER
class PizCompressor: public Compressor
{
public:
+ IMF_EXPORT
PizCompressor (const Header &hdr,
size_t maxScanLineSize,
size_t numScanLines);
+ IMF_EXPORT
virtual ~PizCompressor ();
+ IMF_EXPORT
virtual int numScanLines () const;
+ IMF_EXPORT
virtual Format format () const;
+ IMF_EXPORT
virtual int compress (const char *inPtr,
- int inSize,
- int minY,
- const char *&outPtr);
-
+ int inSize,
+ int minY,
+ const char *&outPtr);
+
+ IMF_EXPORT
virtual int compressTile (const char *inPtr,
- int inSize,
- Imath::Box2i range,
- const char *&outPtr);
+ int inSize,
+ IMATH_NAMESPACE::Box2i range,
+ const char *&outPtr);
+ IMF_EXPORT
virtual int uncompress (const char *inPtr,
- int inSize,
- int minY,
- const char *&outPtr);
-
+ int inSize,
+ int minY,
+ const char *&outPtr);
+
+ IMF_EXPORT
virtual int uncompressTile (const char *inPtr,
- int inSize,
- Imath::Box2i range,
- const char *&outPtr);
+ int inSize,
+ IMATH_NAMESPACE::Box2i range,
+ const char *&outPtr);
private:
struct ChannelData;
-
+
int compress (const char *inPtr,
- int inSize,
- Imath::Box2i range,
- const char *&outPtr);
-
+ int inSize,
+ IMATH_NAMESPACE::Box2i range,
+ const char *&outPtr);
+
int uncompress (const char *inPtr,
- int inSize,
- Imath::Box2i range,
- const char *&outPtr);
+ int inSize,
+ IMATH_NAMESPACE::Box2i range,
+ const char *&outPtr);
int _maxScanLineSize;
Format _format;
};
-} // namespace Imf
+OPENEXR_IMF_INTERNAL_NAMESPACE_HEADER_EXIT
#endif
//
// Copyright (c) 2003, Industrial Light & Magic, a division of Lucas
// Digital Ltd. LLC
-//
+//
// All rights reserved.
-//
+//
// Redistribution and use in source and binary forms, with or without
// modification, are permitted provided that the following conditions are
// met:
// distribution.
// * Neither the name of Industrial Light & Magic nor the names of
// its contributors may be used to endorse or promote products derived
-// from this software without specific prior written permission.
-//
+// from this software without specific prior written permission.
+//
// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
//
//-----------------------------------------------------------------------------
-#include <ImfPreviewImage.h>
-#include <ImfCheckedArithmetic.h>
+#include "ImfPreviewImage.h"
+#include "ImfCheckedArithmetic.h"
#include "Iex.h"
+#include "ImfNamespace.h"
-namespace Imf {
+OPENEXR_IMF_INTERNAL_NAMESPACE_SOURCE_ENTER
PreviewImage::PreviewImage (unsigned int width,
- unsigned int height,
- const PreviewRgba pixels[])
+ unsigned int height,
+ const PreviewRgba pixels[])
{
_width = width;
_height = height;
if (pixels)
{
- for (unsigned int i = 0; i < _width * _height; ++i)
- _pixels[i] = pixels[i];
+ for (unsigned int i = 0; i < _width * _height; ++i)
+ _pixels[i] = pixels[i];
}
else
{
- for (unsigned int i = 0; i < _width * _height; ++i)
- _pixels[i] = PreviewRgba();
+ for (unsigned int i = 0; i < _width * _height; ++i)
+ _pixels[i] = PreviewRgba();
}
}
_pixels (new PreviewRgba [other._width * other._height])
{
for (unsigned int i = 0; i < _width * _height; ++i)
- _pixels[i] = other._pixels[i];
+ _pixels[i] = other._pixels[i];
}
_pixels = new PreviewRgba [other._width * other._height];
for (unsigned int i = 0; i < _width * _height; ++i)
- _pixels[i] = other._pixels[i];
+ _pixels[i] = other._pixels[i];
return *this;
}
-} // namespace Imf
+OPENEXR_IMF_INTERNAL_NAMESPACE_SOURCE_EXIT
//
// Copyright (c) 2003, Industrial Light & Magic, a division of Lucas
// Digital Ltd. LLC
-//
+//
// All rights reserved.
-//
+//
// Redistribution and use in source and binary forms, with or without
// modification, are permitted provided that the following conditions are
// met:
// distribution.
// * Neither the name of Industrial Light & Magic nor the names of
// its contributors may be used to endorse or promote products derived
-// from this software without specific prior written permission.
-//
+// from this software without specific prior written permission.
+//
// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
#ifndef INCLUDED_IMF_PREVIEW_IMAGE_H
#define INCLUDED_IMF_PREVIEW_IMAGE_H
+#include "ImfNamespace.h"
+#include "ImfExport.h"
+
//-----------------------------------------------------------------------------
//
// class PreviewImage -- a usually small, low-dynamic range image,
//
//-----------------------------------------------------------------------------
-namespace Imf {
+
+OPENEXR_IMF_INTERNAL_NAMESPACE_HEADER_ENTER
struct PreviewRgba
unsigned char r; // Red, green and blue components of
unsigned char g; // the pixel's color; intensity is
unsigned char b; // proportional to pow (x/255, 2.2),
- // where x is r, g, or b.
+ // where x is r, g, or b.
unsigned char a; // The pixel's alpha; 0 == transparent,
- // 255 == opaque.
+ // 255 == opaque.
PreviewRgba (unsigned char r = 0,
- unsigned char g = 0,
- unsigned char b = 0,
- unsigned char a = 255)
- : r(r), g(g), b(b), a(a) {}
+ unsigned char g = 0,
+ unsigned char b = 0,
+ unsigned char a = 255)
+ : r(r), g(g), b(b), a(a) {}
};
// (r = 0, b = 0, g = 0, a = 255).
//
//--------------------------------------------------------------------
-
+
+ IMF_EXPORT
PreviewImage (unsigned int width = 0,
- unsigned int height = 0,
- const PreviewRgba pixels[] = 0);
+ unsigned int height = 0,
+ const PreviewRgba pixels[] = 0);
//-----------------------------------------------------
// Copy constructor, destructor and assignment operator
//-----------------------------------------------------
+ IMF_EXPORT
PreviewImage (const PreviewImage &other);
+ IMF_EXPORT
~PreviewImage ();
+ IMF_EXPORT
PreviewImage & operator = (const PreviewImage &other);
// Access to width, height and to the pixel array
//-----------------------------------------------
+ IMF_EXPORT
unsigned int width () const {return _width;}
+ IMF_EXPORT
unsigned int height () const {return _height;}
+ IMF_EXPORT
PreviewRgba * pixels () {return _pixels;}
+ IMF_EXPORT
const PreviewRgba * pixels () const {return _pixels;}
// Access to individual pixels
//----------------------------
+ IMF_EXPORT
PreviewRgba & pixel (unsigned int x, unsigned int y)
- {return _pixels[y * _width + x];}
+ {return _pixels[y * _width + x];}
+ IMF_EXPORT
const PreviewRgba & pixel (unsigned int x, unsigned int y) const
- {return _pixels[y * _width + x];}
+ {return _pixels[y * _width + x];}
private:
};
-} // namespace Imf
+OPENEXR_IMF_INTERNAL_NAMESPACE_HEADER_EXIT
#endif
//
// Copyright (c) 2004, Industrial Light & Magic, a division of Lucas
// Digital Ltd. LLC
-//
+//
// All rights reserved.
-//
+//
// Redistribution and use in source and binary forms, with or without
// modification, are permitted provided that the following conditions are
// met:
// distribution.
// * Neither the name of Industrial Light & Magic nor the names of
// its contributors may be used to endorse or promote products derived
-// from this software without specific prior written permission.
-//
+// from this software without specific prior written permission.
+//
// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
#include <ImfPreviewImageAttribute.h>
-namespace Imf {
+OPENEXR_IMF_INTERNAL_NAMESPACE_SOURCE_ENTER
+using namespace OPENEXR_IMF_INTERNAL_NAMESPACE;
template <>
const char *
template <>
void
-PreviewImageAttribute::writeValueTo (OStream &os, int) const
+PreviewImageAttribute::writeValueTo (OPENEXR_IMF_INTERNAL_NAMESPACE::OStream &os, int version) const
{
Xdr::write <StreamIO> (os, _value.width());
Xdr::write <StreamIO> (os, _value.height());
for (int i = 0; i < numPixels; ++i)
{
- Xdr::write <StreamIO> (os, pixels[i].r);
- Xdr::write <StreamIO> (os, pixels[i].g);
- Xdr::write <StreamIO> (os, pixels[i].b);
- Xdr::write <StreamIO> (os, pixels[i].a);
+ Xdr::write <StreamIO> (os, pixels[i].r);
+ Xdr::write <StreamIO> (os, pixels[i].g);
+ Xdr::write <StreamIO> (os, pixels[i].b);
+ Xdr::write <StreamIO> (os, pixels[i].a);
}
}
template <>
void
-PreviewImageAttribute::readValueFrom (IStream &is, int, int)
+PreviewImageAttribute::readValueFrom (OPENEXR_IMF_INTERNAL_NAMESPACE::IStream &is, int size, int version)
{
int width, height;
for (int i = 0; i < numPixels; ++i)
{
- Xdr::read <StreamIO> (is, pixels[i].r);
- Xdr::read <StreamIO> (is, pixels[i].g);
- Xdr::read <StreamIO> (is, pixels[i].b);
- Xdr::read <StreamIO> (is, pixels[i].a);
+ Xdr::read <StreamIO> (is, pixels[i].r);
+ Xdr::read <StreamIO> (is, pixels[i].g);
+ Xdr::read <StreamIO> (is, pixels[i].b);
+ Xdr::read <StreamIO> (is, pixels[i].a);
}
_value = p;
}
-} // namespace Imf
+OPENEXR_IMF_INTERNAL_NAMESPACE_SOURCE_EXIT
//
// Copyright (c) 2004, Industrial Light & Magic, a division of Lucas
// Digital Ltd. LLC
-//
+//
// All rights reserved.
-//
+//
// Redistribution and use in source and binary forms, with or without
// modification, are permitted provided that the following conditions are
// met:
// distribution.
// * Neither the name of Industrial Light & Magic nor the names of
// its contributors may be used to endorse or promote products derived
-// from this software without specific prior written permission.
-//
+// from this software without specific prior written permission.
+//
// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
//
//-----------------------------------------------------------------------------
-#include <ImfAttribute.h>
-#include <ImfPreviewImage.h>
+#include "ImfAttribute.h"
+#include "ImfPreviewImage.h"
+OPENEXR_IMF_INTERNAL_NAMESPACE_HEADER_ENTER
-namespace Imf {
-
-typedef TypedAttribute<PreviewImage> PreviewImageAttribute;
+typedef TypedAttribute<OPENEXR_IMF_INTERNAL_NAMESPACE::PreviewImage> PreviewImageAttribute;
template <>
+IMF_EXPORT
const char *PreviewImageAttribute::staticTypeName ();
template <>
-void PreviewImageAttribute::writeValueTo (OStream &, int) const;
+IMF_EXPORT
+void PreviewImageAttribute::writeValueTo (OPENEXR_IMF_INTERNAL_NAMESPACE::OStream &,
+ int) const;
template <>
-void PreviewImageAttribute::readValueFrom (IStream &, int, int);
-
+IMF_EXPORT
+void PreviewImageAttribute::readValueFrom (OPENEXR_IMF_INTERNAL_NAMESPACE::IStream &,
+ int, int);
-} // namespace Imf
-// Metrowerks compiler wants the .cpp file inlined, too
-#ifdef __MWERKS__
-#include <ImfPreviewImageAttribute.cpp>
-#endif
+OPENEXR_IMF_INTERNAL_NAMESPACE_HEADER_EXIT
#endif
// string of bytes is compressed with zlib.
//
//-----------------------------------------------------------------------------
-//#define ZLIB_WINAPI
-#include <ImfPxr24Compressor.h>
-#include <ImfHeader.h>
-#include <ImfChannelList.h>
-#include <ImfMisc.h>
-#include <ImfCheckedArithmetic.h>
+#include "ImfPxr24Compressor.h"
+#include "ImfHeader.h"
+#include "ImfChannelList.h"
+#include "ImfMisc.h"
+#include "ImfCheckedArithmetic.h"
+#include "ImfNamespace.h"
+
#include <ImathFun.h>
#include <Iex.h>
+
#include <half.h>
#include <zlib.h>
#include <assert.h>
#include <algorithm>
using namespace std;
-using namespace Imath;
+using namespace IMATH_NAMESPACE;
+
+OPENEXR_IMF_INTERNAL_NAMESPACE_SOURCE_ENTER
-namespace Imf {
namespace {
//
{
union
{
- float f;
- unsigned int i;
+ float f;
+ unsigned int i;
} u;
u.f = f;
if (e == 0x7f800000)
{
- if (m)
- {
- //
- // F is a NAN; we preserve the sign bit and
- // the 15 leftmost bits of the significand,
- // with one exception: If the 15 leftmost
- // bits are all zero, the NAN would turn
- // into an infinity, so we have to set at
- // least one bit in the significand.
- //
-
- m >>= 8;
- i = (e >> 8) | m | (m == 0);
+ if (m)
+ {
+ //
+ // F is a NAN; we preserve the sign bit and
+ // the 15 leftmost bits of the significand,
+ // with one exception: If the 15 leftmost
+ // bits are all zero, the NAN would turn
+ // into an infinity, so we have to set at
+ // least one bit in the significand.
+ //
+
+ m >>= 8;
+ i = (e >> 8) | m | (m == 0);
+ }
+ else
+ {
+ //
+ // F is an infinity.
+ //
+
+ i = e >> 8;
+ }
}
else
{
- //
- // F is an infinity.
- //
-
- i = e >> 8;
- }
- }
- else
- {
- //
- // F is finite, round the significand to 15 bits.
- //
-
- i = ((e | m) + (m & 0x00000080)) >> 8;
-
- if (i >= 0x7f8000)
- {
- //
- // F was close to FLT_MAX, and the significand was
- // rounded up, resulting in an exponent overflow.
- // Avoid the overflow by truncating the significand
- // instead of rounding it.
- //
-
- i = (e | m) >> 8;
- }
+ //
+ // F is finite, round the significand to 15 bits.
+ //
+
+ i = ((e | m) + (m & 0x00000080)) >> 8;
+
+ if (i >= 0x7f8000)
+ {
+ //
+ // F was close to FLT_MAX, and the significand was
+ // rounded up, resulting in an exponent overflow.
+ // Avoid the overflow by truncating the significand
+ // instead of rounding it.
+ //
+
+ i = (e | m) >> 8;
+ }
}
return (s >> 8) | i;
void
notEnoughData ()
{
- throw Iex::InputExc ("Error decompressing data "
- "(input data are shorter than expected).");
+ throw IEX_NAMESPACE::InputExc ("Error decompressing data "
+ "(input data are shorter than expected).");
}
void
tooMuchData ()
{
- throw Iex::InputExc ("Error decompressing data "
- "(input data are longer than expected).");
+ throw IEX_NAMESPACE::InputExc ("Error decompressing data "
+ "(input data are longer than expected).");
}
} // namespace
Pxr24Compressor::Pxr24Compressor (const Header &hdr,
- size_t maxScanLineSize,
- size_t numScanLines)
+ size_t maxScanLineSize,
+ size_t numScanLines)
:
Compressor (hdr),
_maxScanLineSize (maxScanLineSize),
int
Pxr24Compressor::compress (const char *inPtr,
- int inSize,
- int minY,
- const char *&outPtr)
+ int inSize,
+ int minY,
+ const char *&outPtr)
{
return compress (inPtr,
- inSize,
- Box2i (V2i (_minX, minY),
- V2i (_maxX, minY + _numScanLines - 1)),
- outPtr);
+ inSize,
+ Box2i (V2i (_minX, minY),
+ V2i (_maxX, minY + _numScanLines - 1)),
+ outPtr);
}
-
+
int
Pxr24Compressor::compressTile (const char *inPtr,
- int inSize,
- Box2i range,
- const char *&outPtr)
+ int inSize,
+ Box2i range,
+ const char *&outPtr)
{
return compress (inPtr, inSize, range, outPtr);
}
int
Pxr24Compressor::uncompress (const char *inPtr,
- int inSize,
- int minY,
- const char *&outPtr)
+ int inSize,
+ int minY,
+ const char *&outPtr)
{
return uncompress (inPtr,
- inSize,
- Box2i (V2i (_minX, minY),
- V2i (_maxX, minY + _numScanLines - 1)),
- outPtr);
+ inSize,
+ Box2i (V2i (_minX, minY),
+ V2i (_maxX, minY + _numScanLines - 1)),
+ outPtr);
}
-
+
int
Pxr24Compressor::uncompressTile (const char *inPtr,
- int inSize,
- Box2i range,
- const char *&outPtr)
+ int inSize,
+ Box2i range,
+ const char *&outPtr)
{
return uncompress (inPtr, inSize, range, outPtr);
}
int
Pxr24Compressor::compress (const char *inPtr,
- int inSize,
- Box2i range,
- const char *&outPtr)
+ int inSize,
+ Box2i range,
+ const char *&outPtr)
{
if (inSize == 0)
{
- outPtr = _outBuffer;
- return 0;
+ outPtr = _outBuffer;
+ return 0;
}
int minX = range.min.x;
for (int y = minY; y <= maxY; ++y)
{
- for (ChannelList::ConstIterator i = _channels.begin();
- i != _channels.end();
- ++i)
- {
- const Channel &c = i.channel();
+ for (ChannelList::ConstIterator i = _channels.begin();
+ i != _channels.end();
+ ++i)
+ {
+ const Channel &c = i.channel();
- if (modp (y, c.ySampling) != 0)
- continue;
+ if (modp (y, c.ySampling) != 0)
+ continue;
- int n = numSamples (c.xSampling, minX, maxX);
+ int n = numSamples (c.xSampling, minX, maxX);
- unsigned char *ptr[4];
- unsigned int previousPixel = 0;
+ unsigned char *ptr[4];
+ unsigned int previousPixel = 0;
- switch (c.type)
- {
- case UINT:
+ switch (c.type)
+ {
+ case OPENEXR_IMF_INTERNAL_NAMESPACE::UINT:
- ptr[0] = tmpBufferEnd;
- ptr[1] = ptr[0] + n;
- ptr[2] = ptr[1] + n;
- ptr[3] = ptr[2] + n;
- tmpBufferEnd = ptr[3] + n;
+ ptr[0] = tmpBufferEnd;
+ ptr[1] = ptr[0] + n;
+ ptr[2] = ptr[1] + n;
+ ptr[3] = ptr[2] + n;
+ tmpBufferEnd = ptr[3] + n;
- for (int j = 0; j < n; ++j)
- {
- unsigned int pixel;
- char *pPtr = (char *) &pixel;
+ for (int j = 0; j < n; ++j)
+ {
+ unsigned int pixel;
+ char *pPtr = (char *) &pixel;
- for (int k = 0; k < sizeof (pixel); ++k)
- *pPtr++ = *inPtr++;
+ for (size_t k = 0; k < sizeof (pixel); ++k)
+ *pPtr++ = *inPtr++;
- unsigned int diff = pixel - previousPixel;
- previousPixel = pixel;
+ unsigned int diff = pixel - previousPixel;
+ previousPixel = pixel;
- *(ptr[0]++) = diff >> 24;
- *(ptr[1]++) = diff >> 16;
- *(ptr[2]++) = diff >> 8;
- *(ptr[3]++) = diff;
- }
+ *(ptr[0]++) = diff >> 24;
+ *(ptr[1]++) = diff >> 16;
+ *(ptr[2]++) = diff >> 8;
+ *(ptr[3]++) = diff;
+ }
- break;
+ break;
- case HALF:
+ case OPENEXR_IMF_INTERNAL_NAMESPACE::HALF:
- ptr[0] = tmpBufferEnd;
- ptr[1] = ptr[0] + n;
- tmpBufferEnd = ptr[1] + n;
+ ptr[0] = tmpBufferEnd;
+ ptr[1] = ptr[0] + n;
+ tmpBufferEnd = ptr[1] + n;
- for (int j = 0; j < n; ++j)
- {
- half pixel;
+ for (int j = 0; j < n; ++j)
+ {
+ half pixel;
- pixel = *(const half *) inPtr;
- inPtr += sizeof (half);
+ pixel = *(const half *) inPtr;
+ inPtr += sizeof (half);
- unsigned int diff = pixel.bits() - previousPixel;
- previousPixel = pixel.bits();
+ unsigned int diff = pixel.bits() - previousPixel;
+ previousPixel = pixel.bits();
- *(ptr[0]++) = diff >> 8;
- *(ptr[1]++) = diff;
- }
+ *(ptr[0]++) = diff >> 8;
+ *(ptr[1]++) = diff;
+ }
- break;
+ break;
- case FLOAT:
+ case OPENEXR_IMF_INTERNAL_NAMESPACE::FLOAT:
- ptr[0] = tmpBufferEnd;
- ptr[1] = ptr[0] + n;
- ptr[2] = ptr[1] + n;
- tmpBufferEnd = ptr[2] + n;
+ ptr[0] = tmpBufferEnd;
+ ptr[1] = ptr[0] + n;
+ ptr[2] = ptr[1] + n;
+ tmpBufferEnd = ptr[2] + n;
- for (int j = 0; j < n; ++j)
- {
- float pixel;
- char *pPtr = (char *) &pixel;
+ for (int j = 0; j < n; ++j)
+ {
+ float pixel;
+ char *pPtr = (char *) &pixel;
- for (int k = 0; k < sizeof (pixel); ++k)
- *pPtr++ = *inPtr++;
+ for (size_t k = 0; k < sizeof (pixel); ++k)
+ *pPtr++ = *inPtr++;
- unsigned int pixel24 = floatToFloat24 (pixel);
- unsigned int diff = pixel24 - previousPixel;
- previousPixel = pixel24;
+ unsigned int pixel24 = floatToFloat24 (pixel);
+ unsigned int diff = pixel24 - previousPixel;
+ previousPixel = pixel24;
- *(ptr[0]++) = diff >> 16;
- *(ptr[1]++) = diff >> 8;
- *(ptr[2]++) = diff;
- }
+ *(ptr[0]++) = diff >> 16;
+ *(ptr[1]++) = diff >> 8;
+ *(ptr[2]++) = diff;
+ }
- break;
+ break;
- default:
+ default:
- assert (false);
- }
- }
+ assert (false);
+ }
+ }
}
uLongf outSize = int (ceil ((tmpBufferEnd - _tmpBuffer) * 1.01)) + 100;
if (Z_OK != ::compress ((Bytef *) _outBuffer,
- &outSize,
- (const Bytef *) _tmpBuffer,
- tmpBufferEnd - _tmpBuffer))
+ &outSize,
+ (const Bytef *) _tmpBuffer,
+ tmpBufferEnd - _tmpBuffer))
{
- throw Iex::BaseExc ("Data compression (zlib) failed.");
+ throw IEX_NAMESPACE::BaseExc ("Data compression (zlib) failed.");
}
outPtr = _outBuffer;
return outSize;
}
-
-int
+
+int
Pxr24Compressor::uncompress (const char *inPtr,
- int inSize,
- Box2i range,
- const char *&outPtr)
+ int inSize,
+ Box2i range,
+ const char *&outPtr)
{
if (inSize == 0)
{
- outPtr = _outBuffer;
- return 0;
+ outPtr = _outBuffer;
+ return 0;
}
uLongf tmpSize = _maxScanLineSize * _numScanLines;
if (Z_OK != ::uncompress ((Bytef *)_tmpBuffer,
- &tmpSize,
- (const Bytef *) inPtr,
- inSize))
+ &tmpSize,
+ (const Bytef *) inPtr,
+ inSize))
{
- throw Iex::InputExc ("Data decompression (zlib) failed.");
+ throw IEX_NAMESPACE::InputExc ("Data decompression (zlib) failed.");
}
int minX = range.min.x;
for (int y = minY; y <= maxY; ++y)
{
- for (ChannelList::ConstIterator i = _channels.begin();
- i != _channels.end();
- ++i)
- {
- const Channel &c = i.channel();
+ for (ChannelList::ConstIterator i = _channels.begin();
+ i != _channels.end();
+ ++i)
+ {
+ const Channel &c = i.channel();
- if (modp (y, c.ySampling) != 0)
- continue;
+ if (modp (y, c.ySampling) != 0)
+ continue;
- int n = numSamples (c.xSampling, minX, maxX);
+ int n = numSamples (c.xSampling, minX, maxX);
- const unsigned char *ptr[4];
- unsigned int pixel = 0;
+ const unsigned char *ptr[4];
+ unsigned int pixel = 0;
- switch (c.type)
- {
- case UINT:
+ switch (c.type)
+ {
+ case OPENEXR_IMF_INTERNAL_NAMESPACE::UINT:
- ptr[0] = tmpBufferEnd;
- ptr[1] = ptr[0] + n;
- ptr[2] = ptr[1] + n;
- ptr[3] = ptr[2] + n;
- tmpBufferEnd = ptr[3] + n;
+ ptr[0] = tmpBufferEnd;
+ ptr[1] = ptr[0] + n;
+ ptr[2] = ptr[1] + n;
+ ptr[3] = ptr[2] + n;
+ tmpBufferEnd = ptr[3] + n;
- if (tmpBufferEnd - _tmpBuffer > tmpSize)
- notEnoughData();
+ if ( (uLongf)(tmpBufferEnd - _tmpBuffer) > tmpSize)
+ notEnoughData();
- for (int j = 0; j < n; ++j)
- {
- unsigned int diff = (*(ptr[0]++) << 24) |
- (*(ptr[1]++) << 16) |
- (*(ptr[2]++) << 8) |
- *(ptr[3]++);
+ for (int j = 0; j < n; ++j)
+ {
+ unsigned int diff = (*(ptr[0]++) << 24) |
+ (*(ptr[1]++) << 16) |
+ (*(ptr[2]++) << 8) |
+ *(ptr[3]++);
- pixel += diff;
+ pixel += diff;
- char *pPtr = (char *) &pixel;
+ char *pPtr = (char *) &pixel;
- for (int k = 0; k < sizeof (pixel); ++k)
- *writePtr++ = *pPtr++;
- }
+ for (size_t k = 0; k < sizeof (pixel); ++k)
+ *writePtr++ = *pPtr++;
+ }
- break;
+ break;
- case HALF:
+ case OPENEXR_IMF_INTERNAL_NAMESPACE::HALF:
- ptr[0] = tmpBufferEnd;
- ptr[1] = ptr[0] + n;
- tmpBufferEnd = ptr[1] + n;
+ ptr[0] = tmpBufferEnd;
+ ptr[1] = ptr[0] + n;
+ tmpBufferEnd = ptr[1] + n;
- if (tmpBufferEnd - _tmpBuffer > tmpSize)
- notEnoughData();
+ if ( (uLongf)(tmpBufferEnd - _tmpBuffer) > tmpSize)
+ notEnoughData();
- for (int j = 0; j < n; ++j)
- {
- unsigned int diff = (*(ptr[0]++) << 8) |
- *(ptr[1]++);
+ for (int j = 0; j < n; ++j)
+ {
+ unsigned int diff = (*(ptr[0]++) << 8) |
+ *(ptr[1]++);
- pixel += diff;
+ pixel += diff;
- half * hPtr = (half *) writePtr;
- hPtr->setBits ((unsigned short) pixel);
- writePtr += sizeof (half);
- }
+ half * hPtr = (half *) writePtr;
+ hPtr->setBits ((unsigned short) pixel);
+ writePtr += sizeof (half);
+ }
- break;
+ break;
- case FLOAT:
+ case OPENEXR_IMF_INTERNAL_NAMESPACE::FLOAT:
- ptr[0] = tmpBufferEnd;
- ptr[1] = ptr[0] + n;
- ptr[2] = ptr[1] + n;
- tmpBufferEnd = ptr[2] + n;
+ ptr[0] = tmpBufferEnd;
+ ptr[1] = ptr[0] + n;
+ ptr[2] = ptr[1] + n;
+ tmpBufferEnd = ptr[2] + n;
- if (tmpBufferEnd - _tmpBuffer > tmpSize)
- notEnoughData();
+ if ( (uLongf) (tmpBufferEnd - _tmpBuffer) > tmpSize)
+ notEnoughData();
- for (int j = 0; j < n; ++j)
- {
- unsigned int diff = (*(ptr[0]++) << 24) |
- (*(ptr[1]++) << 16) |
- (*(ptr[2]++) << 8);
- pixel += diff;
+ for (int j = 0; j < n; ++j)
+ {
+ unsigned int diff = (*(ptr[0]++) << 24) |
+ (*(ptr[1]++) << 16) |
+ (*(ptr[2]++) << 8);
+ pixel += diff;
- char *pPtr = (char *) &pixel;
+ char *pPtr = (char *) &pixel;
- for (int k = 0; k < sizeof (pixel); ++k)
- *writePtr++ = *pPtr++;
- }
+ for (size_t k = 0; k < sizeof (pixel); ++k)
+ *writePtr++ = *pPtr++;
+ }
- break;
+ break;
- default:
+ default:
- assert (false);
- }
- }
+ assert (false);
+ }
+ }
}
- if (tmpBufferEnd - _tmpBuffer < tmpSize)
- tooMuchData();
+ if ((uLongf) (tmpBufferEnd - _tmpBuffer) < tmpSize)
+ tooMuchData();
outPtr = _outBuffer;
return writePtr - _outBuffer;
}
-} // namespace Imf
+OPENEXR_IMF_INTERNAL_NAMESPACE_SOURCE_EXIT
//
//-----------------------------------------------------------------------------
-#include <ImfCompressor.h>
+#include "ImfCompressor.h"
+#include "ImfNamespace.h"
+#include "ImfExport.h"
+#include "ImfForward.h"
-namespace Imf {
-
-class ChannelList;
+OPENEXR_IMF_INTERNAL_NAMESPACE_HEADER_ENTER
class Pxr24Compressor: public Compressor
{
public:
- Pxr24Compressor (const Header &hdr,
+ IMF_EXPORT
+ Pxr24Compressor (const Header &hdr,
size_t maxScanLineSize,
size_t numScanLines);
+ IMF_EXPORT
virtual ~Pxr24Compressor ();
+ IMF_EXPORT
virtual int numScanLines () const;
+ IMF_EXPORT
virtual Format format () const;
+ IMF_EXPORT
virtual int compress (const char *inPtr,
- int inSize,
- int minY,
- const char *&outPtr);
-
+ int inSize,
+ int minY,
+ const char *&outPtr);
+
+ IMF_EXPORT
virtual int compressTile (const char *inPtr,
- int inSize,
- Imath::Box2i range,
- const char *&outPtr);
+ int inSize,
+ IMATH_NAMESPACE::Box2i range,
+ const char *&outPtr);
+ IMF_EXPORT
virtual int uncompress (const char *inPtr,
- int inSize,
- int minY,
- const char *&outPtr);
-
+ int inSize,
+ int minY,
+ const char *&outPtr);
+
+ IMF_EXPORT
virtual int uncompressTile (const char *inPtr,
- int inSize,
- Imath::Box2i range,
- const char *&outPtr);
+ int inSize,
+ IMATH_NAMESPACE::Box2i range,
+ const char *&outPtr);
private:
int compress (const char *inPtr,
- int inSize,
- Imath::Box2i range,
- const char *&outPtr);
-
+ int inSize,
+ IMATH_NAMESPACE::Box2i range,
+ const char *&outPtr);
+
int uncompress (const char *inPtr,
- int inSize,
- Imath::Box2i range,
- const char *&outPtr);
+ int inSize,
+ IMATH_NAMESPACE::Box2i range,
+ const char *&outPtr);
int _maxScanLineSize;
int _numScanLines;
};
-} // namespace Imf
+OPENEXR_IMF_INTERNAL_NAMESPACE_HEADER_EXIT
#endif
//
// Copyright (c) 2006, Industrial Light & Magic, a division of Lucas
// Digital Ltd. LLC
-//
+//
// All rights reserved.
-//
+//
// Redistribution and use in source and binary forms, with or without
// modification, are permitted provided that the following conditions are
// met:
// distribution.
// * Neither the name of Industrial Light & Magic nor the names of
// its contributors may be used to endorse or promote products derived
-// from this software without specific prior written permission.
-//
+// from this software without specific prior written permission.
+//
// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
#include <cmath>
using namespace std;
+#include "ImfNamespace.h"
+
+OPENEXR_IMF_INTERNAL_NAMESPACE_SOURCE_ENTER
-namespace Imf {
namespace {
double
}
else
{
- double r = frac (1 / x, e);
-
+ double r = frac (1 / x, e);
+
if (e > r)
{
return floor (1 / x + e);
if (x >= 0)
{
- sign = 1; // positive
+ sign = 1; // positive
}
else if (x < 0)
{
- sign = -1; // negative
- x = -x;
+ sign = -1; // negative
+ x = -x;
}
else
{
- n = 0; // NaN
- d = 0;
- return;
+ n = 0; // NaN
+ d = 0;
+ return;
}
if (x >= (1U << 31) - 0.5)
{
- n = sign; // infinity
- d = 0;
- return;
+ n = sign; // infinity
+ d = 0;
+ return;
}
double e = (x < 1? 1: x) / (1U << 30);
}
-} // namespace Imf
+OPENEXR_IMF_INTERNAL_NAMESPACE_SOURCE_EXIT
//
// Copyright (c) 2006, Industrial Light & Magic, a division of Lucas
// Digital Ltd. LLC
-//
+//
// All rights reserved.
-//
+//
// Redistribution and use in source and binary forms, with or without
// modification, are permitted provided that the following conditions are
// met:
// distribution.
// * Neither the name of Industrial Light & Magic nor the names of
// its contributors may be used to endorse or promote products derived
-// from this software without specific prior written permission.
-//
+// from this software without specific prior written permission.
+//
// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
#ifndef INCLUDED_IMF_RATIONAL_H
#define INCLUDED_IMF_RATIONAL_H
+#include "ImfExport.h"
+#include "ImfNamespace.h"
+
//-----------------------------------------------------------------------------
//
// Rational numbers
//
// A rational number is represented as pair of integers, n and d.
// The value of of the rational number is
-//
+//
// n/d for d > 0
// positive infinity for n > 0, d == 0
// negative infinity for n < 0, d == 0
//
//-----------------------------------------------------------------------------
-namespace Imf {
+OPENEXR_IMF_INTERNAL_NAMESPACE_HEADER_ENTER
+
class Rational
{
// Constructor, explicitly sets n and d
//-------------------------------------
- Rational (int _n, int _d): n (_n), d (_d) {}
+ Rational (int n, int d): n (n), d (d) {}
//----------------------------
// Constructor, approximates x
//----------------------------
+ IMF_EXPORT
explicit Rational (double x);
operator double () const {return double (n) / double (d);}
};
-} // namespace Imf
+
+OPENEXR_IMF_INTERNAL_NAMESPACE_HEADER_EXIT
#endif
//
// Copyright (c) 2006, Industrial Light & Magic, a division of Lucas
// Digital Ltd. LLC
-//
+//
// All rights reserved.
-//
+//
// Redistribution and use in source and binary forms, with or without
// modification, are permitted provided that the following conditions are
// met:
// distribution.
// * Neither the name of Industrial Light & Magic nor the names of
// its contributors may be used to endorse or promote products derived
-// from this software without specific prior written permission.
-//
+// from this software without specific prior written permission.
+//
// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
#include <ImfRationalAttribute.h>
-namespace Imf {
+OPENEXR_IMF_INTERNAL_NAMESPACE_SOURCE_ENTER
+using namespace OPENEXR_IMF_INTERNAL_NAMESPACE;
template <>
const char *
template <>
void
-RationalAttribute::writeValueTo (OStream &os, int) const
+RationalAttribute::writeValueTo (OPENEXR_IMF_INTERNAL_NAMESPACE::OStream &os, int version) const
{
Xdr::write <StreamIO> (os, _value.n);
Xdr::write <StreamIO> (os, _value.d);
template <>
void
-RationalAttribute::readValueFrom (IStream &is, int, int)
+RationalAttribute::readValueFrom (OPENEXR_IMF_INTERNAL_NAMESPACE::IStream &is, int size, int version)
{
Xdr::read <StreamIO> (is, _value.n);
Xdr::read <StreamIO> (is, _value.d);
}
-} // namespace Imf
+OPENEXR_IMF_INTERNAL_NAMESPACE_SOURCE_EXIT
//
// Copyright (c) 2004, Industrial Light & Magic, a division of Lucas
// Digital Ltd. LLC
-//
+//
// All rights reserved.
-//
+//
// Redistribution and use in source and binary forms, with or without
// modification, are permitted provided that the following conditions are
// met:
// distribution.
// * Neither the name of Industrial Light & Magic nor the names of
// its contributors may be used to endorse or promote products derived
-// from this software without specific prior written permission.
-//
+// from this software without specific prior written permission.
+//
// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
//
//-----------------------------------------------------------------------------
-#include <ImfAttribute.h>
-#include <ImfRational.h>
+#include "ImfAttribute.h"
+#include "ImfRational.h"
+OPENEXR_IMF_INTERNAL_NAMESPACE_HEADER_ENTER
-namespace Imf {
-
-typedef TypedAttribute<Rational> RationalAttribute;
+typedef TypedAttribute<OPENEXR_IMF_INTERNAL_NAMESPACE::Rational> RationalAttribute;
template <>
+IMF_EXPORT
const char *RationalAttribute::staticTypeName ();
template <>
-void RationalAttribute::writeValueTo (OStream &, int) const;
+IMF_EXPORT
+void RationalAttribute::writeValueTo (OPENEXR_IMF_INTERNAL_NAMESPACE::OStream &,
+ int) const;
template <>
-void RationalAttribute::readValueFrom (IStream &, int, int);
-
+IMF_EXPORT
+void RationalAttribute::readValueFrom (OPENEXR_IMF_INTERNAL_NAMESPACE::IStream &,
+ int, int);
-} // namespace Imf
-// Metrowerks compiler wants the .cpp file inlined, too
-#ifdef __MWERKS__
-#include <ImfRationalAttribute.cpp>
-#endif
+OPENEXR_IMF_INTERNAL_NAMESPACE_HEADER_EXIT
#endif
//
// Copyright (c) 2004, Industrial Light & Magic, a division of Lucas
// Digital Ltd. LLC
-//
+//
// All rights reserved.
-//
+//
// Redistribution and use in source and binary forms, with or without
// modification, are permitted provided that the following conditions are
// met:
// distribution.
// * Neither the name of Industrial Light & Magic nor the names of
// its contributors may be used to endorse or promote products derived
-// from this software without specific prior written permission.
-//
+// from this software without specific prior written permission.
+//
// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
//-----------------------------------------------------------------------------
#include "half.h"
+#include "ImfNamespace.h"
-namespace Imf {
+OPENEXR_IMF_INTERNAL_NAMESPACE_HEADER_ENTER
//
half g;
half b;
half a;
-
+
Rgba () {}
Rgba (half r, half g, half b, half a = 1.f): r (r), g (g), b (b), a (a) {}
Rgba & operator = (const Rgba &other)
{
- r = other.r;
- g = other.g;
- b = other.b;
- a = other.a;
+ r = other.r;
+ g = other.g;
+ b = other.b;
+ a = other.a;
- return *this;
+ return *this;
}
};
WRITE_A = 0x08, // Alpha
WRITE_Y = 0x10, // Luminance, for black-and-white images,
- // or in combination with chroma
+ // or in combination with chroma
WRITE_C = 0x20, // Chroma (two subsampled channels, RY and BY,
- // supported only for scanline-based files)
+ // supported only for scanline-based files)
WRITE_RGB = 0x07, // Red, green, blue
WRITE_RGBA = 0x0f, // Red, green, blue, alpha
};
-} // namespace Imf
+OPENEXR_IMF_INTERNAL_NAMESPACE_HEADER_EXIT
+
+
+
+
#endif
//
// Copyright (c) 2004, Industrial Light & Magic, a division of Lucas
// Digital Ltd. LLC
-//
+//
// All rights reserved.
-//
+//
// Redistribution and use in source and binary forms, with or without
// modification, are permitted provided that the following conditions are
// met:
// distribution.
// * Neither the name of Industrial Light & Magic nor the names of
// its contributors may be used to endorse or promote products derived
-// from this software without specific prior written permission.
-//
+// from this software without specific prior written permission.
+//
// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
#include <string.h>
#include <algorithm>
+#include "ImfNamespace.h"
-namespace Imf {
+OPENEXR_IMF_INTERNAL_NAMESPACE_SOURCE_ENTER
using namespace std;
-using namespace Imath;
+using namespace IMATH_NAMESPACE;
using namespace RgbaYca;
-using namespace IlmThread;
+using namespace ILMTHREAD_NAMESPACE;
namespace {
if (rgbaChannels & (WRITE_Y | WRITE_C))
{
- if (rgbaChannels & WRITE_Y)
- {
- ch.insert ("Y", Channel (HALF, 1, 1));
- }
-
- if (rgbaChannels & WRITE_C)
- {
- ch.insert ("RY", Channel (HALF, 2, 2, true));
- ch.insert ("BY", Channel (HALF, 2, 2, true));
- }
+ if (rgbaChannels & WRITE_Y)
+ {
+ ch.insert ("Y", Channel (HALF, 1, 1));
+ }
+
+ if (rgbaChannels & WRITE_C)
+ {
+ ch.insert ("RY", Channel (HALF, 2, 2, true));
+ ch.insert ("BY", Channel (HALF, 2, 2, true));
+ }
}
else
{
- if (rgbaChannels & WRITE_R)
- ch.insert ("R", Channel (HALF, 1, 1));
+ if (rgbaChannels & WRITE_R)
+ ch.insert ("R", Channel (HALF, 1, 1));
- if (rgbaChannels & WRITE_G)
- ch.insert ("G", Channel (HALF, 1, 1));
+ if (rgbaChannels & WRITE_G)
+ ch.insert ("G", Channel (HALF, 1, 1));
- if (rgbaChannels & WRITE_B)
- ch.insert ("B", Channel (HALF, 1, 1));
+ if (rgbaChannels & WRITE_B)
+ ch.insert ("B", Channel (HALF, 1, 1));
}
if (rgbaChannels & WRITE_A)
- ch.insert ("A", Channel (HALF, 1, 1));
+ ch.insert ("A", Channel (HALF, 1, 1));
header.channels() = ch;
}
int i = 0;
if (ch.findChannel (channelNamePrefix + "R"))
- i |= WRITE_R;
+ i |= WRITE_R;
if (ch.findChannel (channelNamePrefix + "G"))
- i |= WRITE_G;
-
+ i |= WRITE_G;
+
if (ch.findChannel (channelNamePrefix + "B"))
- i |= WRITE_B;
+ i |= WRITE_B;
if (ch.findChannel (channelNamePrefix + "A"))
- i |= WRITE_A;
+ i |= WRITE_A;
if (ch.findChannel (channelNamePrefix + "Y"))
- i |= WRITE_Y;
+ i |= WRITE_Y;
if (ch.findChannel (channelNamePrefix + "RY") ||
- ch.findChannel (channelNamePrefix + "BY"))
- i |= WRITE_C;
+ ch.findChannel (channelNamePrefix + "BY"))
+ i |= WRITE_C;
return RgbaChannels (i);
}
prefixFromLayerName (const string &layerName, const Header &header)
{
if (layerName.empty())
- return "";
+ return "";
if (hasMultiView (header) && multiView(header)[0] == layerName)
- return "";
+ return "";
return layerName + ".";
}
Chromaticities cr;
if (hasChromaticities (header))
- cr = chromaticities (header);
+ cr = chromaticities (header);
return computeYw (cr);
}
int i = LOG2_CACHE_LINE_SIZE + 2;
while ((size >> i) > 1)
- ++i;
+ ++i;
if (size > (1 << (i + 1)) - 64)
- return 64 + ((1 << (i + 1)) - size);
+ return 64 + ((1 << (i + 1)) - size);
if (size < (1 << i) + 64)
- return 64 + ((1 << i) - size);
+ return 64 + ((1 << i) - size);
return 0;
}
~ToYca ();
void setYCRounding (unsigned int roundY,
- unsigned int roundC);
+ unsigned int roundC);
void setFrameBuffer (const Rgba *base,
- size_t xStride,
- size_t yStride);
+ size_t xStride,
+ size_t yStride);
void writePixels (int numScanLines);
int currentScanLine () const;
RgbaOutputFile::ToYca::ToYca (OutputFile &outputFile,
- RgbaChannels rgbaChannels)
+ RgbaChannels rgbaChannels)
:
_outputFile (outputFile)
{
_linesConverted = 0;
_lineOrder = _outputFile.header().lineOrder();
-
+
if (_lineOrder == INCREASING_Y)
- _currentScanLine = dw.min.y;
+ _currentScanLine = dw.min.y;
else
- _currentScanLine = dw.max.y;
+ _currentScanLine = dw.max.y;
_yw = ywFromHeader (_outputFile.header());
_bufBase = new Rgba[(_width + pad) * N];
for (int i = 0; i < N; ++i)
- _buf[i] = _bufBase + (i * (_width + pad));
+ _buf[i] = _bufBase + (i * (_width + pad));
_tmpBuf = new Rgba[_width + N - 1];
void
RgbaOutputFile::ToYca::setYCRounding (unsigned int roundY,
- unsigned int roundC)
+ unsigned int roundC)
{
_roundY = roundY;
_roundC = roundC;
void
RgbaOutputFile::ToYca::setFrameBuffer (const Rgba *base,
- size_t xStride,
- size_t yStride)
+ size_t xStride,
+ size_t yStride)
{
if (_fbBase == 0)
{
- FrameBuffer fb;
-
- if (_writeY)
- {
- fb.insert ("Y",
- Slice (HALF, // type
- (char *) &_tmpBuf[-_xMin].g, // base
- sizeof (Rgba), // xStride
- 0, // yStride
- 1, // xSampling
- 1)); // ySampling
- }
-
- if (_writeC)
- {
- fb.insert ("RY",
- Slice (HALF, // type
- (char *) &_tmpBuf[-_xMin].r, // base
- sizeof (Rgba) * 2, // xStride
- 0, // yStride
- 2, // xSampling
- 2)); // ySampling
-
- fb.insert ("BY",
- Slice (HALF, // type
- (char *) &_tmpBuf[-_xMin].b, // base
- sizeof (Rgba) * 2, // xStride
- 0, // yStride
- 2, // xSampling
- 2)); // ySampling
- }
-
- if (_writeA)
- {
- fb.insert ("A",
- Slice (HALF, // type
- (char *) &_tmpBuf[-_xMin].a, // base
- sizeof (Rgba), // xStride
- 0, // yStride
- 1, // xSampling
- 1)); // ySampling
- }
-
- _outputFile.setFrameBuffer (fb);
+ FrameBuffer fb;
+
+ if (_writeY)
+ {
+ fb.insert ("Y",
+ Slice (HALF, // type
+ (char *) &_tmpBuf[-_xMin].g, // base
+ sizeof (Rgba), // xStride
+ 0, // yStride
+ 1, // xSampling
+ 1)); // ySampling
+ }
+
+ if (_writeC)
+ {
+ fb.insert ("RY",
+ Slice (HALF, // type
+ (char *) &_tmpBuf[-_xMin].r, // base
+ sizeof (Rgba) * 2, // xStride
+ 0, // yStride
+ 2, // xSampling
+ 2)); // ySampling
+
+ fb.insert ("BY",
+ Slice (HALF, // type
+ (char *) &_tmpBuf[-_xMin].b, // base
+ sizeof (Rgba) * 2, // xStride
+ 0, // yStride
+ 2, // xSampling
+ 2)); // ySampling
+ }
+
+ if (_writeA)
+ {
+ fb.insert ("A",
+ Slice (HALF, // type
+ (char *) &_tmpBuf[-_xMin].a, // base
+ sizeof (Rgba), // xStride
+ 0, // yStride
+ 1, // xSampling
+ 1)); // ySampling
+ }
+
+ _outputFile.setFrameBuffer (fb);
}
_fbBase = base;
{
if (_fbBase == 0)
{
- THROW (Iex::ArgExc, "No frame buffer was specified as the "
- "pixel data source for image file "
- "\"" << _outputFile.fileName() << "\".");
+ THROW (IEX_NAMESPACE::ArgExc, "No frame buffer was specified as the "
+ "pixel data source for image file "
+ "\"" << _outputFile.fileName() << "\".");
}
if (_writeY && !_writeC)
{
- //
- // We are writing only luminance; filtering
- // and subsampling are not necessary.
- //
-
- for (int i = 0; i < numScanLines; ++i)
- {
- //
- // Copy the next scan line from the caller's
- // frame buffer into _tmpBuf.
- //
-
- for (int j = 0; j < _width; ++j)
- {
- _tmpBuf[j] = _fbBase[_fbYStride * _currentScanLine +
- _fbXStride * (j + _xMin)];
- }
-
- //
- // Convert the scan line from RGB to luminance/chroma,
- // and store the result in the output file.
- //
-
- RGBAtoYCA (_yw, _width, _writeA, _tmpBuf, _tmpBuf);
- _outputFile.writePixels (1);
-
- ++_linesConverted;
-
- if (_lineOrder == INCREASING_Y)
- ++_currentScanLine;
- else
- --_currentScanLine;
- }
+ //
+ // We are writing only luminance; filtering
+ // and subsampling are not necessary.
+ //
+
+ for (int i = 0; i < numScanLines; ++i)
+ {
+ //
+ // Copy the next scan line from the caller's
+ // frame buffer into _tmpBuf.
+ //
+
+ for (int j = 0; j < _width; ++j)
+ {
+ _tmpBuf[j] = _fbBase[_fbYStride * _currentScanLine +
+ _fbXStride * (j + _xMin)];
+ }
+
+ //
+ // Convert the scan line from RGB to luminance/chroma,
+ // and store the result in the output file.
+ //
+
+ RGBAtoYCA (_yw, _width, _writeA, _tmpBuf, _tmpBuf);
+ _outputFile.writePixels (1);
+
+ ++_linesConverted;
+
+ if (_lineOrder == INCREASING_Y)
+ ++_currentScanLine;
+ else
+ --_currentScanLine;
+ }
}
else
{
- //
- // We are writing chroma; the pixels must be filtered and subsampled.
- //
-
- for (int i = 0; i < numScanLines; ++i)
- {
- //
- // Copy the next scan line from the caller's
- // frame buffer into _tmpBuf.
- //
-
- for (int j = 0; j < _width; ++j)
- {
- _tmpBuf[j + N2] = _fbBase[_fbYStride * _currentScanLine +
- _fbXStride * (j + _xMin)];
- }
-
- //
- // Convert the scan line from RGB to luminance/chroma.
- //
-
- RGBAtoYCA (_yw, _width, _writeA, _tmpBuf + N2, _tmpBuf + N2);
-
- //
- // Append N2 copies of the first and last pixel to the
- // beginning and end of the scan line.
- //
-
- padTmpBuf ();
-
- //
- // Filter and subsample the scan line's chroma channels
- // horizontally; store the result in _buf.
- //
-
- rotateBuffers();
- decimateChromaHoriz (_width, _tmpBuf, _buf[N - 1]);
-
- //
- // If this is the first scan line in the image,
- // store N2 more copies of the scan line in _buf.
- //
-
- if (_linesConverted == 0)
- {
- for (int j = 0; j < N2; ++j)
- duplicateLastBuffer();
- }
-
- ++_linesConverted;
-
- //
- // If we have have converted at least N2 scan lines from
- // RGBA to luminance/chroma, then we can start to filter
- // and subsample vertically, and store pixels in the
- // output file.
- //
-
- if (_linesConverted > N2)
- decimateChromaVertAndWriteScanLine();
-
- //
- // If we have already converted the last scan line in
- // the image to luminance/chroma, filter, subsample and
- // store the remaining scan lines in _buf.
- //
-
- if (_linesConverted >= _height)
- {
- for (int j = 0; j < N2 - _height; ++j)
- duplicateLastBuffer();
-
- duplicateSecondToLastBuffer();
- ++_linesConverted;
- decimateChromaVertAndWriteScanLine();
-
- for (int j = 1; j < min (_height, N2); ++j)
- {
- duplicateLastBuffer();
- ++_linesConverted;
- decimateChromaVertAndWriteScanLine();
- }
- }
-
- if (_lineOrder == INCREASING_Y)
- ++_currentScanLine;
- else
- --_currentScanLine;
- }
+ //
+ // We are writing chroma; the pixels must be filtered and subsampled.
+ //
+
+ for (int i = 0; i < numScanLines; ++i)
+ {
+ //
+ // Copy the next scan line from the caller's
+ // frame buffer into _tmpBuf.
+ //
+
+ for (int j = 0; j < _width; ++j)
+ {
+ _tmpBuf[j + N2] = _fbBase[_fbYStride * _currentScanLine +
+ _fbXStride * (j + _xMin)];
+ }
+
+ //
+ // Convert the scan line from RGB to luminance/chroma.
+ //
+
+ RGBAtoYCA (_yw, _width, _writeA, _tmpBuf + N2, _tmpBuf + N2);
+
+ //
+ // Append N2 copies of the first and last pixel to the
+ // beginning and end of the scan line.
+ //
+
+ padTmpBuf ();
+
+ //
+ // Filter and subsample the scan line's chroma channels
+ // horizontally; store the result in _buf.
+ //
+
+ rotateBuffers();
+ decimateChromaHoriz (_width, _tmpBuf, _buf[N - 1]);
+
+ //
+ // If this is the first scan line in the image,
+ // store N2 more copies of the scan line in _buf.
+ //
+
+ if (_linesConverted == 0)
+ {
+ for (int j = 0; j < N2; ++j)
+ duplicateLastBuffer();
+ }
+
+ ++_linesConverted;
+
+ //
+ // If we have have converted at least N2 scan lines from
+ // RGBA to luminance/chroma, then we can start to filter
+ // and subsample vertically, and store pixels in the
+ // output file.
+ //
+
+ if (_linesConverted > N2)
+ decimateChromaVertAndWriteScanLine();
+
+ //
+ // If we have already converted the last scan line in
+ // the image to luminance/chroma, filter, subsample and
+ // store the remaining scan lines in _buf.
+ //
+
+ if (_linesConverted >= _height)
+ {
+ for (int j = 0; j < N2 - _height; ++j)
+ duplicateLastBuffer();
+
+ duplicateSecondToLastBuffer();
+ ++_linesConverted;
+ decimateChromaVertAndWriteScanLine();
+
+ for (int j = 1; j < min (_height, N2); ++j)
+ {
+ duplicateLastBuffer();
+ ++_linesConverted;
+ decimateChromaVertAndWriteScanLine();
+ }
+ }
+
+ if (_lineOrder == INCREASING_Y)
+ ++_currentScanLine;
+ else
+ --_currentScanLine;
+ }
}
}
{
for (int i = 0; i < N2; ++i)
{
- _tmpBuf[i] = _tmpBuf[N2];
- _tmpBuf[_width + N2 + i] = _tmpBuf[_width + N2 - 2];
+ _tmpBuf[i] = _tmpBuf[N2];
+ _tmpBuf[_width + N2 + i] = _tmpBuf[_width + N2 - 2];
}
}
Rgba *tmp = _buf[0];
for (int i = 0; i < N - 1; ++i)
- _buf[i] = _buf[i + 1];
+ _buf[i] = _buf[i + 1];
_buf[N - 1] = tmp;
}
RgbaOutputFile::ToYca::decimateChromaVertAndWriteScanLine ()
{
if (_linesConverted & 1)
- memcpy (_tmpBuf, _buf[N2], _width * sizeof (Rgba));
+ memcpy (_tmpBuf, _buf[N2], _width * sizeof (Rgba));
else
- decimateChromaVert (_width, _buf, _tmpBuf);
+ decimateChromaVert (_width, _buf, _tmpBuf);
if (_writeY && _writeC)
- roundYCA (_width, _roundY, _roundC, _tmpBuf, _tmpBuf);
+ roundYCA (_width, _roundY, _roundC, _tmpBuf, _tmpBuf);
_outputFile.writePixels (1);
}
RgbaOutputFile::RgbaOutputFile (const char name[],
- const Header &header,
- RgbaChannels rgbaChannels,
+ const Header &header,
+ RgbaChannels rgbaChannels,
int numThreads):
_outputFile (0),
_toYca (0)
_outputFile = new OutputFile (name, hd, numThreads);
if (rgbaChannels & (WRITE_Y | WRITE_C))
- _toYca = new ToYca (*_outputFile, rgbaChannels);
+ _toYca = new ToYca (*_outputFile, rgbaChannels);
}
-RgbaOutputFile::RgbaOutputFile (OStream &os,
- const Header &header,
- RgbaChannels rgbaChannels,
+RgbaOutputFile::RgbaOutputFile (OPENEXR_IMF_INTERNAL_NAMESPACE::OStream &os,
+ const Header &header,
+ RgbaChannels rgbaChannels,
int numThreads):
_outputFile (0),
_toYca (0)
_outputFile = new OutputFile (os, hd, numThreads);
if (rgbaChannels & (WRITE_Y | WRITE_C))
- _toYca = new ToYca (*_outputFile, rgbaChannels);
+ _toYca = new ToYca (*_outputFile, rgbaChannels);
}
RgbaOutputFile::RgbaOutputFile (const char name[],
- const Imath::Box2i &displayWindow,
- const Imath::Box2i &dataWindow,
- RgbaChannels rgbaChannels,
- float pixelAspectRatio,
- const Imath::V2f screenWindowCenter,
- float screenWindowWidth,
- LineOrder lineOrder,
- Compression compression,
+ const IMATH_NAMESPACE::Box2i &displayWindow,
+ const IMATH_NAMESPACE::Box2i &dataWindow,
+ RgbaChannels rgbaChannels,
+ float pixelAspectRatio,
+ const IMATH_NAMESPACE::V2f screenWindowCenter,
+ float screenWindowWidth,
+ LineOrder lineOrder,
+ Compression compression,
int numThreads):
_outputFile (0),
_toYca (0)
{
Header hd (displayWindow,
- dataWindow.isEmpty()? displayWindow: dataWindow,
- pixelAspectRatio,
- screenWindowCenter,
- screenWindowWidth,
- lineOrder,
- compression);
+ dataWindow.isEmpty()? displayWindow: dataWindow,
+ pixelAspectRatio,
+ screenWindowCenter,
+ screenWindowWidth,
+ lineOrder,
+ compression);
insertChannels (hd, rgbaChannels);
_outputFile = new OutputFile (name, hd, numThreads);
if (rgbaChannels & (WRITE_Y | WRITE_C))
- _toYca = new ToYca (*_outputFile, rgbaChannels);
+ _toYca = new ToYca (*_outputFile, rgbaChannels);
}
RgbaOutputFile::RgbaOutputFile (const char name[],
- int width,
- int height,
- RgbaChannels rgbaChannels,
- float pixelAspectRatio,
- const Imath::V2f screenWindowCenter,
- float screenWindowWidth,
- LineOrder lineOrder,
- Compression compression,
+ int width,
+ int height,
+ RgbaChannels rgbaChannels,
+ float pixelAspectRatio,
+ const IMATH_NAMESPACE::V2f screenWindowCenter,
+ float screenWindowWidth,
+ LineOrder lineOrder,
+ Compression compression,
int numThreads):
_outputFile (0),
_toYca (0)
{
Header hd (width,
- height,
- pixelAspectRatio,
- screenWindowCenter,
- screenWindowWidth,
- lineOrder,
- compression);
+ height,
+ pixelAspectRatio,
+ screenWindowCenter,
+ screenWindowWidth,
+ lineOrder,
+ compression);
insertChannels (hd, rgbaChannels);
_outputFile = new OutputFile (name, hd, numThreads);
if (rgbaChannels & (WRITE_Y | WRITE_C))
- _toYca = new ToYca (*_outputFile, rgbaChannels);
+ _toYca = new ToYca (*_outputFile, rgbaChannels);
}
void
RgbaOutputFile::setFrameBuffer (const Rgba *base,
- size_t xStride,
- size_t yStride)
+ size_t xStride,
+ size_t yStride)
{
if (_toYca)
{
- Lock lock (*_toYca);
- _toYca->setFrameBuffer (base, xStride, yStride);
+ Lock lock (*_toYca);
+ _toYca->setFrameBuffer (base, xStride, yStride);
}
else
{
- size_t xs = xStride * sizeof (Rgba);
- size_t ys = yStride * sizeof (Rgba);
+ size_t xs = xStride * sizeof (Rgba);
+ size_t ys = yStride * sizeof (Rgba);
- FrameBuffer fb;
+ FrameBuffer fb;
- fb.insert ("R", Slice (HALF, (char *) &base[0].r, xs, ys));
- fb.insert ("G", Slice (HALF, (char *) &base[0].g, xs, ys));
- fb.insert ("B", Slice (HALF, (char *) &base[0].b, xs, ys));
- fb.insert ("A", Slice (HALF, (char *) &base[0].a, xs, ys));
+ fb.insert ("R", Slice (HALF, (char *) &base[0].r, xs, ys));
+ fb.insert ("G", Slice (HALF, (char *) &base[0].g, xs, ys));
+ fb.insert ("B", Slice (HALF, (char *) &base[0].b, xs, ys));
+ fb.insert ("A", Slice (HALF, (char *) &base[0].a, xs, ys));
- _outputFile->setFrameBuffer (fb);
+ _outputFile->setFrameBuffer (fb);
}
}
-void
+void
RgbaOutputFile::writePixels (int numScanLines)
{
if (_toYca)
{
- Lock lock (*_toYca);
- _toYca->writePixels (numScanLines);
+ Lock lock (*_toYca);
+ _toYca->writePixels (numScanLines);
}
else
{
- _outputFile->writePixels (numScanLines);
+ _outputFile->writePixels (numScanLines);
}
}
-int
+int
RgbaOutputFile::currentScanLine () const
{
if (_toYca)
{
- Lock lock (*_toYca);
- return _toYca->currentScanLine();
+ Lock lock (*_toYca);
+ return _toYca->currentScanLine();
}
else
{
- return _outputFile->currentScanLine();
+ return _outputFile->currentScanLine();
}
}
}
-const Imath::Box2i &
+const IMATH_NAMESPACE::Box2i &
RgbaOutputFile::displayWindow () const
{
return _outputFile->header().displayWindow();
}
-const Imath::Box2i &
+const IMATH_NAMESPACE::Box2i &
RgbaOutputFile::dataWindow () const
{
return _outputFile->header().dataWindow();
}
-float
+float
RgbaOutputFile::pixelAspectRatio () const
{
return _outputFile->header().pixelAspectRatio();
}
-const Imath::V2f
+const IMATH_NAMESPACE::V2f
RgbaOutputFile::screenWindowCenter () const
{
return _outputFile->header().screenWindowCenter();
}
-float
+float
RgbaOutputFile::screenWindowWidth () const
{
return _outputFile->header().screenWindowWidth();
}
-void
+void
RgbaOutputFile::updatePreviewImage (const PreviewRgba newPixels[])
{
_outputFile->updatePreviewImage (newPixels);
}
-void
+void
RgbaOutputFile::setYCRounding (unsigned int roundY, unsigned int roundC)
{
if (_toYca)
{
- Lock lock (*_toYca);
- _toYca->setYCRounding (roundY, roundC);
+ Lock lock (*_toYca);
+ _toYca->setYCRounding (roundY, roundC);
}
}
-void
+void
RgbaOutputFile::breakScanLine (int y, int offset, int length, char c)
{
_outputFile->breakScanLine (y, offset, length, c);
~FromYca ();
void setFrameBuffer (Rgba *base,
- size_t xStride,
- size_t yStride,
- const string &channelNamePrefix);
+ size_t xStride,
+ size_t yStride,
+ const string &channelNamePrefix);
void readPixels (int scanLine1, int scanLine2);
RgbaInputFile::FromYca::FromYca (InputFile &inputFile,
- RgbaChannels rgbaChannels)
+ RgbaChannels rgbaChannels)
:
_inputFile (inputFile)
{
_bufBase = new Rgba[(_width + pad) * (N + 2 + 3)];
for (int i = 0; i < N + 2; ++i)
- _buf1[i] = _bufBase + (i * (_width + pad));
-
+ _buf1[i] = _bufBase + (i * (_width + pad));
+
for (int i = 0; i < 3; ++i)
- _buf2[i] = _bufBase + ((i + N + 2) * (_width + pad));
+ _buf2[i] = _bufBase + ((i + N + 2) * (_width + pad));
_tmpBuf = new Rgba[_width + N - 1];
void
RgbaInputFile::FromYca::setFrameBuffer (Rgba *base,
- size_t xStride,
- size_t yStride,
- const string &channelNamePrefix)
+ size_t xStride,
+ size_t yStride,
+ const string &channelNamePrefix)
{
if (_fbBase == 0)
{
- FrameBuffer fb;
-
- fb.insert (channelNamePrefix + "Y",
- Slice (HALF, // type
- (char *) &_tmpBuf[N2 - _xMin].g, // base
- sizeof (Rgba), // xStride
- 0, // yStride
- 1, // xSampling
- 1, // ySampling
- 0.5)); // fillValue
-
- if (_readC)
- {
- fb.insert (channelNamePrefix + "RY",
- Slice (HALF, // type
- (char *) &_tmpBuf[N2 - _xMin].r, // base
- sizeof (Rgba) * 2, // xStride
- 0, // yStride
- 2, // xSampling
- 2, // ySampling
- 0.0)); // fillValue
-
- fb.insert (channelNamePrefix + "BY",
- Slice (HALF, // type
- (char *) &_tmpBuf[N2 - _xMin].b, // base
- sizeof (Rgba) * 2, // xStride
- 0, // yStride
- 2, // xSampling
- 2, // ySampling
- 0.0)); // fillValue
- }
-
- fb.insert (channelNamePrefix + "A",
- Slice (HALF, // type
- (char *) &_tmpBuf[N2 - _xMin].a, // base
- sizeof (Rgba), // xStride
- 0, // yStride
- 1, // xSampling
- 1, // ySampling
- 1.0)); // fillValue
-
- _inputFile.setFrameBuffer (fb);
+ FrameBuffer fb;
+
+ fb.insert (channelNamePrefix + "Y",
+ Slice (HALF, // type
+ (char *) &_tmpBuf[N2 - _xMin].g, // base
+ sizeof (Rgba), // xStride
+ 0, // yStride
+ 1, // xSampling
+ 1, // ySampling
+ 0.5)); // fillValue
+
+ if (_readC)
+ {
+ fb.insert (channelNamePrefix + "RY",
+ Slice (HALF, // type
+ (char *) &_tmpBuf[N2 - _xMin].r, // base
+ sizeof (Rgba) * 2, // xStride
+ 0, // yStride
+ 2, // xSampling
+ 2, // ySampling
+ 0.0)); // fillValue
+
+ fb.insert (channelNamePrefix + "BY",
+ Slice (HALF, // type
+ (char *) &_tmpBuf[N2 - _xMin].b, // base
+ sizeof (Rgba) * 2, // xStride
+ 0, // yStride
+ 2, // xSampling
+ 2, // ySampling
+ 0.0)); // fillValue
+ }
+
+ fb.insert (channelNamePrefix + "A",
+ Slice (HALF, // type
+ (char *) &_tmpBuf[N2 - _xMin].a, // base
+ sizeof (Rgba), // xStride
+ 0, // yStride
+ 1, // xSampling
+ 1, // ySampling
+ 1.0)); // fillValue
+
+ _inputFile.setFrameBuffer (fb);
}
_fbBase = base;
}
-void
+void
RgbaInputFile::FromYca::readPixels (int scanLine1, int scanLine2)
{
int minY = min (scanLine1, scanLine2);
if (_lineOrder == INCREASING_Y)
{
- for (int y = minY; y <= maxY; ++y)
- readPixels (y);
+ for (int y = minY; y <= maxY; ++y)
+ readPixels (y);
}
else
{
- for (int y = maxY; y >= minY; --y)
- readPixels (y);
+ for (int y = maxY; y >= minY; --y)
+ readPixels (y);
}
}
-void
+void
RgbaInputFile::FromYca::readPixels (int scanLine)
{
if (_fbBase == 0)
{
- THROW (Iex::ArgExc, "No frame buffer was specified as the "
- "pixel data destination for image file "
- "\"" << _inputFile.fileName() << "\".");
+ THROW (IEX_NAMESPACE::ArgExc, "No frame buffer was specified as the "
+ "pixel data destination for image file "
+ "\"" << _inputFile.fileName() << "\".");
}
//
int dy = scanLine - _currentScanLine;
if (abs (dy) < N + 2)
- rotateBuf1 (dy);
+ rotateBuf1 (dy);
if (abs (dy) < 3)
- rotateBuf2 (dy);
+ rotateBuf2 (dy);
if (dy < 0)
{
- {
- int n = min (-dy, N + 2);
- int yMin = scanLine - N2 - 1;
-
- for (int i = n - 1; i >= 0; --i)
- readYCAScanLine (yMin + i, _buf1[i]);
- }
-
- {
- int n = min (-dy, 3);
-
- for (int i = 0; i < n; ++i)
- {
- if ((scanLine + i) & 1)
- {
- YCAtoRGBA (_yw, _width, _buf1[N2 + i], _buf2[i]);
- }
- else
- {
- reconstructChromaVert (_width, _buf1 + i, _buf2[i]);
- YCAtoRGBA (_yw, _width, _buf2[i], _buf2[i]);
- }
- }
- }
+ {
+ int n = min (-dy, N + 2);
+ int yMin = scanLine - N2 - 1;
+
+ for (int i = n - 1; i >= 0; --i)
+ readYCAScanLine (yMin + i, _buf1[i]);
+ }
+
+ {
+ int n = min (-dy, 3);
+
+ for (int i = 0; i < n; ++i)
+ {
+ if ((scanLine + i) & 1)
+ {
+ YCAtoRGBA (_yw, _width, _buf1[N2 + i], _buf2[i]);
+ }
+ else
+ {
+ reconstructChromaVert (_width, _buf1 + i, _buf2[i]);
+ YCAtoRGBA (_yw, _width, _buf2[i], _buf2[i]);
+ }
+ }
+ }
}
else
{
- {
- int n = min (dy, N + 2);
- int yMax = scanLine + N2 + 1;
-
- for (int i = n - 1; i >= 0; --i)
- readYCAScanLine (yMax - i, _buf1[N + 1 - i]);
- }
-
- {
- int n = min (dy, 3);
-
- for (int i = 2; i > 2 - n; --i)
- {
- if ((scanLine + i) & 1)
- {
- YCAtoRGBA (_yw, _width, _buf1[N2 + i], _buf2[i]);
- }
- else
- {
- reconstructChromaVert (_width, _buf1 + i, _buf2[i]);
- YCAtoRGBA (_yw, _width, _buf2[i], _buf2[i]);
- }
- }
- }
+ {
+ int n = min (dy, N + 2);
+ int yMax = scanLine + N2 + 1;
+
+ for (int i = n - 1; i >= 0; --i)
+ readYCAScanLine (yMax - i, _buf1[N + 1 - i]);
+ }
+
+ {
+ int n = min (dy, 3);
+
+ for (int i = 2; i > 2 - n; --i)
+ {
+ if ((scanLine + i) & 1)
+ {
+ YCAtoRGBA (_yw, _width, _buf1[N2 + i], _buf2[i]);
+ }
+ else
+ {
+ reconstructChromaVert (_width, _buf1 + i, _buf2[i]);
+ YCAtoRGBA (_yw, _width, _buf2[i], _buf2[i]);
+ }
+ }
+ }
}
fixSaturation (_yw, _width, _buf2, _tmpBuf);
for (int i = 0; i < _width; ++i)
- _fbBase[_fbYStride * scanLine + _fbXStride * (i + _xMin)] = _tmpBuf[i];
+ _fbBase[_fbYStride * scanLine + _fbXStride * (i + _xMin)] = _tmpBuf[i];
_currentScanLine = scanLine;
}
Rgba *tmp[N + 2];
for (int i = 0; i < N + 2; ++i)
- tmp[i] = _buf1[i];
+ tmp[i] = _buf1[i];
for (int i = 0; i < N + 2; ++i)
- _buf1[i] = tmp[(i + d) % (N + 2)];
+ _buf1[i] = tmp[(i + d) % (N + 2)];
}
Rgba *tmp[3];
for (int i = 0; i < 3; ++i)
- tmp[i] = _buf2[i];
+ tmp[i] = _buf2[i];
for (int i = 0; i < 3; ++i)
- _buf2[i] = tmp[(i + d) % 3];
+ _buf2[i] = tmp[(i + d) % 3];
}
//
if (y < _yMin)
- y = _yMin;
+ y = _yMin;
else if (y > _yMax)
- y = _yMax - 1;
+ y = _yMax - 1;
//
// Read scan line y into _tmpBuf.
if (!_readC)
{
- for (int i = 0; i < _width; ++i)
- {
- _tmpBuf[i + N2].r = 0;
- _tmpBuf[i + N2].b = 0;
- }
+ for (int i = 0; i < _width; ++i)
+ {
+ _tmpBuf[i + N2].r = 0;
+ _tmpBuf[i + N2].b = 0;
+ }
}
if (y & 1)
{
- memcpy (buf, _tmpBuf + N2, _width * sizeof (Rgba));
+ memcpy (buf, _tmpBuf + N2, _width * sizeof (Rgba));
}
else
{
- padTmpBuf();
- reconstructChromaHoriz (_width, _tmpBuf, buf);
+ padTmpBuf();
+ reconstructChromaHoriz (_width, _tmpBuf, buf);
}
}
{
for (int i = 0; i < N2; ++i)
{
- _tmpBuf[i] = _tmpBuf[N2];
- _tmpBuf[_width + N2 + i] = _tmpBuf[_width + N2 - 2];
+ _tmpBuf[i] = _tmpBuf[N2];
+ _tmpBuf[_width + N2 + i] = _tmpBuf[_width + N2 - 2];
}
}
RgbaChannels rgbaChannels = channels();
if (rgbaChannels & (WRITE_Y | WRITE_C))
- _fromYca = new FromYca (*_inputFile, rgbaChannels);
+ _fromYca = new FromYca (*_inputFile, rgbaChannels);
}
-RgbaInputFile::RgbaInputFile (IStream &is, int numThreads):
+RgbaInputFile::RgbaInputFile (OPENEXR_IMF_INTERNAL_NAMESPACE::IStream &is, int numThreads):
_inputFile (new InputFile (is, numThreads)),
_fromYca (0),
_channelNamePrefix ("")
RgbaChannels rgbaChannels = channels();
if (rgbaChannels & (WRITE_Y | WRITE_C))
- _fromYca = new FromYca (*_inputFile, rgbaChannels);
+ _fromYca = new FromYca (*_inputFile, rgbaChannels);
}
RgbaInputFile::RgbaInputFile (const char name[],
- const string &layerName,
- int numThreads)
+ const string &layerName,
+ int numThreads)
:
_inputFile (new InputFile (name, numThreads)),
_fromYca (0),
RgbaChannels rgbaChannels = channels();
if (rgbaChannels & (WRITE_Y | WRITE_C))
- _fromYca = new FromYca (*_inputFile, rgbaChannels);
+ _fromYca = new FromYca (*_inputFile, rgbaChannels);
}
-RgbaInputFile::RgbaInputFile (IStream &is,
- const string &layerName,
- int numThreads)
+RgbaInputFile::RgbaInputFile (OPENEXR_IMF_INTERNAL_NAMESPACE::IStream &is,
+ const string &layerName,
+ int numThreads)
:
_inputFile (new InputFile (is, numThreads)),
_fromYca (0),
RgbaChannels rgbaChannels = channels();
if (rgbaChannels & (WRITE_Y | WRITE_C))
- _fromYca = new FromYca (*_inputFile, rgbaChannels);
+ _fromYca = new FromYca (*_inputFile, rgbaChannels);
}
}
-void
+void
RgbaInputFile::setFrameBuffer (Rgba *base, size_t xStride, size_t yStride)
{
if (_fromYca)
{
- Lock lock (*_fromYca);
- _fromYca->setFrameBuffer (base, xStride, yStride, _channelNamePrefix);
+ Lock lock (*_fromYca);
+ _fromYca->setFrameBuffer (base, xStride, yStride, _channelNamePrefix);
}
else
{
- size_t xs = xStride * sizeof (Rgba);
- size_t ys = yStride * sizeof (Rgba);
-
- FrameBuffer fb;
-
- fb.insert (_channelNamePrefix + "R",
- Slice (HALF,
- (char *) &base[0].r,
- xs, ys,
- 1, 1, // xSampling, ySampling
- 0.0)); // fillValue
-
- fb.insert (_channelNamePrefix + "G",
- Slice (HALF,
- (char *) &base[0].g,
- xs, ys,
- 1, 1, // xSampling, ySampling
- 0.0)); // fillValue
-
- fb.insert (_channelNamePrefix + "B",
- Slice (HALF,
- (char *) &base[0].b,
- xs, ys,
- 1, 1, // xSampling, ySampling
- 0.0)); // fillValue
-
- fb.insert (_channelNamePrefix + "A",
- Slice (HALF,
- (char *) &base[0].a,
- xs, ys,
- 1, 1, // xSampling, ySampling
- 1.0)); // fillValue
-
- _inputFile->setFrameBuffer (fb);
+ size_t xs = xStride * sizeof (Rgba);
+ size_t ys = yStride * sizeof (Rgba);
+
+ FrameBuffer fb;
+
+ fb.insert (_channelNamePrefix + "R",
+ Slice (HALF,
+ (char *) &base[0].r,
+ xs, ys,
+ 1, 1, // xSampling, ySampling
+ 0.0)); // fillValue
+
+ fb.insert (_channelNamePrefix + "G",
+ Slice (HALF,
+ (char *) &base[0].g,
+ xs, ys,
+ 1, 1, // xSampling, ySampling
+ 0.0)); // fillValue
+
+ fb.insert (_channelNamePrefix + "B",
+ Slice (HALF,
+ (char *) &base[0].b,
+ xs, ys,
+ 1, 1, // xSampling, ySampling
+ 0.0)); // fillValue
+
+ fb.insert (_channelNamePrefix + "A",
+ Slice (HALF,
+ (char *) &base[0].a,
+ xs, ys,
+ 1, 1, // xSampling, ySampling
+ 1.0)); // fillValue
+
+ _inputFile->setFrameBuffer (fb);
}
}
RgbaChannels rgbaChannels = channels();
if (rgbaChannels & (WRITE_Y | WRITE_C))
- _fromYca = new FromYca (*_inputFile, rgbaChannels);
+ _fromYca = new FromYca (*_inputFile, rgbaChannels);
FrameBuffer fb;
_inputFile->setFrameBuffer (fb);
}
-void
+void
RgbaInputFile::readPixels (int scanLine1, int scanLine2)
{
if (_fromYca)
{
- Lock lock (*_fromYca);
- _fromYca->readPixels (scanLine1, scanLine2);
+ Lock lock (*_fromYca);
+ _fromYca->readPixels (scanLine1, scanLine2);
}
else
{
- _inputFile->readPixels (scanLine1, scanLine2);
+ _inputFile->readPixels (scanLine1, scanLine2);
}
}
-void
+void
RgbaInputFile::readPixels (int scanLine)
{
readPixels (scanLine, scanLine);
}
-const FrameBuffer &
+const FrameBuffer &
RgbaInputFile::frameBuffer () const
{
return _inputFile->frameBuffer();
}
-const Imath::Box2i &
+const IMATH_NAMESPACE::Box2i &
RgbaInputFile::displayWindow () const
{
return _inputFile->header().displayWindow();
}
-const Imath::Box2i &
+const IMATH_NAMESPACE::Box2i &
RgbaInputFile::dataWindow () const
{
return _inputFile->header().dataWindow();
}
-float
+float
RgbaInputFile::pixelAspectRatio () const
{
return _inputFile->header().pixelAspectRatio();
}
-const Imath::V2f
+const IMATH_NAMESPACE::V2f
RgbaInputFile::screenWindowCenter () const
{
return _inputFile->header().screenWindowCenter();
}
-float
+float
RgbaInputFile::screenWindowWidth () const
{
return _inputFile->header().screenWindowWidth();
}
-RgbaChannels
+RgbaChannels
RgbaInputFile::channels () const
{
return rgbaChannels (_inputFile->header().channels(), _channelNamePrefix);
}
-} // namespace Imf
+OPENEXR_IMF_INTERNAL_NAMESPACE_SOURCE_EXIT
//
// Copyright (c) 2004, Industrial Light & Magic, a division of Lucas
// Digital Ltd. LLC
-//
+//
// All rights reserved.
-//
+//
// Redistribution and use in source and binary forms, with or without
// modification, are permitted provided that the following conditions are
// met:
// distribution.
// * Neither the name of Industrial Light & Magic nor the names of
// its contributors may be used to endorse or promote products derived
-// from this software without specific prior written permission.
-//
+// from this software without specific prior written permission.
+//
// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
//
//-----------------------------------------------------------------------------
-#include <ImfHeader.h>
-#include <ImfFrameBuffer.h>
-#include <ImfRgba.h>
+#include "ImfHeader.h"
+#include "ImfFrameBuffer.h"
+#include "ImfRgba.h"
#include "ImathVec.h"
#include "ImathBox.h"
#include "half.h"
-#include <ImfThreading.h>
+#include "ImfThreading.h"
#include <string>
+#include "ImfNamespace.h"
+#include "ImfForward.h"
-namespace Imf {
-
+OPENEXR_IMF_INTERNAL_NAMESPACE_HEADER_ENTER
-class OutputFile;
-class InputFile;
-struct PreviewRgba;
//
// RGBA output file.
// Constructor -- header is constructed by the caller
//---------------------------------------------------
+ IMF_EXPORT
RgbaOutputFile (const char name[],
- const Header &header,
- RgbaChannels rgbaChannels = WRITE_RGBA,
+ const Header &header,
+ RgbaChannels rgbaChannels = WRITE_RGBA,
int numThreads = globalThreadCount());
// automatically close the file.
//----------------------------------------------------
- RgbaOutputFile (OStream &os,
- const Header &header,
- RgbaChannels rgbaChannels = WRITE_RGBA,
+ IMF_EXPORT
+ RgbaOutputFile (OPENEXR_IMF_INTERNAL_NAMESPACE::OStream &os,
+ const Header &header,
+ RgbaChannels rgbaChannels = WRITE_RGBA,
int numThreads = globalThreadCount());
// call arguments (empty dataWindow means "same as displayWindow")
//----------------------------------------------------------------
+ IMF_EXPORT
RgbaOutputFile (const char name[],
- const Imath::Box2i &displayWindow,
- const Imath::Box2i &dataWindow = Imath::Box2i(),
- RgbaChannels rgbaChannels = WRITE_RGBA,
- float pixelAspectRatio = 1,
- const Imath::V2f screenWindowCenter = Imath::V2f (0, 0),
- float screenWindowWidth = 1,
- LineOrder lineOrder = INCREASING_Y,
- Compression compression = PIZ_COMPRESSION,
+ const IMATH_NAMESPACE::Box2i &displayWindow,
+ const IMATH_NAMESPACE::Box2i &dataWindow = IMATH_NAMESPACE::Box2i(),
+ RgbaChannels rgbaChannels = WRITE_RGBA,
+ float pixelAspectRatio = 1,
+ const IMATH_NAMESPACE::V2f screenWindowCenter = IMATH_NAMESPACE::V2f (0, 0),
+ float screenWindowWidth = 1,
+ LineOrder lineOrder = INCREASING_Y,
+ Compression compression = PIZ_COMPRESSION,
int numThreads = globalThreadCount());
// Box2i (V2i (0, 0), V2i (width - 1, height -1))
//-----------------------------------------------
+ IMF_EXPORT
RgbaOutputFile (const char name[],
- int width,
- int height,
- RgbaChannels rgbaChannels = WRITE_RGBA,
- float pixelAspectRatio = 1,
- const Imath::V2f screenWindowCenter = Imath::V2f (0, 0),
- float screenWindowWidth = 1,
- LineOrder lineOrder = INCREASING_Y,
- Compression compression = PIZ_COMPRESSION,
+ int width,
+ int height,
+ RgbaChannels rgbaChannels = WRITE_RGBA,
+ float pixelAspectRatio = 1,
+ const IMATH_NAMESPACE::V2f screenWindowCenter = IMATH_NAMESPACE::V2f (0, 0),
+ float screenWindowWidth = 1,
+ LineOrder lineOrder = INCREASING_Y,
+ Compression compression = PIZ_COMPRESSION,
int numThreads = globalThreadCount());
// Destructor
//-----------
+ IMF_EXPORT
virtual ~RgbaOutputFile ();
//
//------------------------------------------------
+ IMF_EXPORT
void setFrameBuffer (const Rgba *base,
- size_t xStride,
- size_t yStride);
+ size_t xStride,
+ size_t yStride);
//---------------------------------------------
// Write pixel data (see class Imf::OutputFile)
//---------------------------------------------
+ IMF_EXPORT
void writePixels (int numScanLines = 1);
+ IMF_EXPORT
int currentScanLine () const;
// Access to the file header
//--------------------------
+ IMF_EXPORT
const Header & header () const;
+ IMF_EXPORT
const FrameBuffer & frameBuffer () const;
- const Imath::Box2i & displayWindow () const;
- const Imath::Box2i & dataWindow () const;
+ IMF_EXPORT
+ const IMATH_NAMESPACE::Box2i & displayWindow () const;
+ IMF_EXPORT
+ const IMATH_NAMESPACE::Box2i & dataWindow () const;
+ IMF_EXPORT
float pixelAspectRatio () const;
- const Imath::V2f screenWindowCenter () const;
+ IMF_EXPORT
+ const IMATH_NAMESPACE::V2f screenWindowCenter () const;
+ IMF_EXPORT
float screenWindowWidth () const;
+ IMF_EXPORT
LineOrder lineOrder () const;
+ IMF_EXPORT
Compression compression () const;
+ IMF_EXPORT
RgbaChannels channels () const;
// Update the preview image (see Imf::OutputFile::updatePreviewImage())
// --------------------------------------------------------------------
+ IMF_EXPORT
void updatePreviewImage (const PreviewRgba[]);
// without chroma, then no rounding is performed.
//-----------------------------------------------------------------------
+ IMF_EXPORT
void setYCRounding (unsigned int roundY,
- unsigned int roundC);
+ unsigned int roundC);
//----------------------------------------------------
//
//----------------------------------------------------
+ IMF_EXPORT
void breakScanLine (int y,
- int offset,
- int length,
- char c);
+ int offset,
+ int length,
+ char c);
private:
RgbaOutputFile (const RgbaOutputFile &); // not implemented
// destructor will automatically close the file.
//-------------------------------------------------------
+ IMF_EXPORT
RgbaInputFile (const char name[], int numThreads = globalThreadCount());
// close the file.
//-----------------------------------------------------------
- RgbaInputFile (IStream &is, int numThreads = globalThreadCount());
+ IMF_EXPORT
+ RgbaInputFile (OPENEXR_IMF_INTERNAL_NAMESPACE::IStream &is, int numThreads = globalThreadCount());
//--------------------------------------------------------------
// are expected to be layerName.R, layerName.G, etc.
//--------------------------------------------------------------
+ IMF_EXPORT
RgbaInputFile (const char name[],
- const std::string &layerName,
- int numThreads = globalThreadCount());
+ const std::string &layerName,
+ int numThreads = globalThreadCount());
- RgbaInputFile (IStream &is,
- const std::string &layerName,
- int numThreads = globalThreadCount());
+ IMF_EXPORT
+ RgbaInputFile (OPENEXR_IMF_INTERNAL_NAMESPACE::IStream &is,
+ const std::string &layerName,
+ int numThreads = globalThreadCount());
//-----------
// Destructor
//-----------
+ IMF_EXPORT
virtual ~RgbaInputFile ();
//
//-----------------------------------------------------
+ IMF_EXPORT
void setFrameBuffer (Rgba *base,
- size_t xStride,
- size_t yStride);
+ size_t xStride,
+ size_t yStride);
//----------------------------------------------------------------
// called at least once before the next call to readPixels().
//----------------------------------------------------------------
+ IMF_EXPORT
void setLayerName (const std::string &layerName);
// Read pixel data (see class Imf::InputFile)
//-------------------------------------------
+ IMF_EXPORT
void readPixels (int scanLine1, int scanLine2);
+ IMF_EXPORT
void readPixels (int scanLine);
// Access to the file header
//--------------------------
+ IMF_EXPORT
const Header & header () const;
+ IMF_EXPORT
const FrameBuffer & frameBuffer () const;
- const Imath::Box2i & displayWindow () const;
- const Imath::Box2i & dataWindow () const;
+ IMF_EXPORT
+ const IMATH_NAMESPACE::Box2i & displayWindow () const;
+ IMF_EXPORT
+ const IMATH_NAMESPACE::Box2i & dataWindow () const;
+ IMF_EXPORT
float pixelAspectRatio () const;
- const Imath::V2f screenWindowCenter () const;
+ IMF_EXPORT
+ const IMATH_NAMESPACE::V2f screenWindowCenter () const;
+ IMF_EXPORT
float screenWindowWidth () const;
+ IMF_EXPORT
LineOrder lineOrder () const;
+ IMF_EXPORT
Compression compression () const;
+ IMF_EXPORT
RgbaChannels channels () const;
+ IMF_EXPORT
const char * fileName () const;
+ IMF_EXPORT
bool isComplete () const;
// Access to the file format version
//----------------------------------
+ IMF_EXPORT
int version () const;
private:
};
-} // namespace Imf
+OPENEXR_IMF_INTERNAL_NAMESPACE_HEADER_EXIT
+
+
+
+
#endif
#include <assert.h>
#include <algorithm>
-using namespace Imath;
+using namespace IMATH_NAMESPACE;
using namespace std;
+#include "ImfNamespace.h"
+
+OPENEXR_IMF_INTERNAL_NAMESPACE_SOURCE_ENTER
-namespace Imf {
namespace RgbaYca {
void
RGBAtoYCA (const V3f &yw,
- int n,
- bool aIsValid,
- const Rgba rgbaIn[/*n*/],
- Rgba ycaOut[/*n*/])
+ int n,
+ bool aIsValid,
+ const Rgba rgbaIn[/*n*/],
+ Rgba ycaOut[/*n*/])
{
for (int i = 0; i < n; ++i)
{
- Rgba in = rgbaIn[i];
- Rgba &out = ycaOut[i];
-
- //
- // Conversion to YCA and subsequent chroma subsampling
- // work only if R, G and B are finite and non-negative.
- //
-
- if (!in.r.isFinite() || in.r < 0)
- in.r = 0;
-
- if (!in.g.isFinite() || in.g < 0)
- in.g = 0;
-
- if (!in.b.isFinite() || in.b < 0)
- in.b = 0;
-
- if (in.r == in.g && in.g == in.b)
- {
- //
- // Special case -- R, G and B are equal. To avoid rounding
- // errors, we explicitly set the output luminance channel
- // to G, and the chroma channels to 0.
- //
- // The special cases here and in YCAtoRGBA() ensure that
- // converting black-and white images from RGBA to YCA and
- // back is lossless.
- //
-
- out.r = 0;
- out.g = in.g;
- out.b = 0;
- }
- else
- {
- out.g = in.r * yw.x + in.g * yw.y + in.b * yw.z;
-
- float Y = out.g;
-
- if (abs (in.r - Y) < HALF_MAX * Y)
- out.r = (in.r - Y) / Y;
- else
- out.r = 0;
-
- if (abs (in.b - Y) < HALF_MAX * Y)
- out.b = (in.b - Y) / Y;
- else
- out.b = 0;
- }
-
- if (aIsValid)
- out.a = in.a;
- else
- out.a = 1;
+ Rgba in = rgbaIn[i];
+ Rgba &out = ycaOut[i];
+
+ //
+ // Conversion to YCA and subsequent chroma subsampling
+ // work only if R, G and B are finite and non-negative.
+ //
+
+ if (!in.r.isFinite() || in.r < 0)
+ in.r = 0;
+
+ if (!in.g.isFinite() || in.g < 0)
+ in.g = 0;
+
+ if (!in.b.isFinite() || in.b < 0)
+ in.b = 0;
+
+ if (in.r == in.g && in.g == in.b)
+ {
+ //
+ // Special case -- R, G and B are equal. To avoid rounding
+ // errors, we explicitly set the output luminance channel
+ // to G, and the chroma channels to 0.
+ //
+ // The special cases here and in YCAtoRGBA() ensure that
+ // converting black-and white images from RGBA to YCA and
+ // back is lossless.
+ //
+
+ out.r = 0;
+ out.g = in.g;
+ out.b = 0;
+ }
+ else
+ {
+ out.g = in.r * yw.x + in.g * yw.y + in.b * yw.z;
+
+ float Y = out.g;
+
+ if (abs (in.r - Y) < HALF_MAX * Y)
+ out.r = (in.r - Y) / Y;
+ else
+ out.r = 0;
+
+ if (abs (in.b - Y) < HALF_MAX * Y)
+ out.b = (in.b - Y) / Y;
+ else
+ out.b = 0;
+ }
+
+ if (aIsValid)
+ out.a = in.a;
+ else
+ out.a = 1;
}
}
void
decimateChromaHoriz (int n,
- const Rgba ycaIn[/*n+N-1*/],
- Rgba ycaOut[/*n*/])
+ const Rgba ycaIn[/*n+N-1*/],
+ Rgba ycaOut[/*n*/])
{
#ifdef DEBUG
- assert (ycaIn != ycaOut);
+ assert (ycaIn != ycaOut);
#endif
int begin = N2;
for (int i = begin, j = 0; i < end; ++i, ++j)
{
- if ((j & 1) == 0)
- {
- ycaOut[j].r = ycaIn[i - 13].r * 0.001064f +
- ycaIn[i - 11].r * -0.003771f +
- ycaIn[i - 9].r * 0.009801f +
- ycaIn[i - 7].r * -0.021586f +
- ycaIn[i - 5].r * 0.043978f +
- ycaIn[i - 3].r * -0.093067f +
- ycaIn[i - 1].r * 0.313659f +
- ycaIn[i ].r * 0.499846f +
- ycaIn[i + 1].r * 0.313659f +
- ycaIn[i + 3].r * -0.093067f +
- ycaIn[i + 5].r * 0.043978f +
- ycaIn[i + 7].r * -0.021586f +
- ycaIn[i + 9].r * 0.009801f +
- ycaIn[i + 11].r * -0.003771f +
- ycaIn[i + 13].r * 0.001064f;
-
- ycaOut[j].b = ycaIn[i - 13].b * 0.001064f +
- ycaIn[i - 11].b * -0.003771f +
- ycaIn[i - 9].b * 0.009801f +
- ycaIn[i - 7].b * -0.021586f +
- ycaIn[i - 5].b * 0.043978f +
- ycaIn[i - 3].b * -0.093067f +
- ycaIn[i - 1].b * 0.313659f +
- ycaIn[i ].b * 0.499846f +
- ycaIn[i + 1].b * 0.313659f +
- ycaIn[i + 3].b * -0.093067f +
- ycaIn[i + 5].b * 0.043978f +
- ycaIn[i + 7].b * -0.021586f +
- ycaIn[i + 9].b * 0.009801f +
- ycaIn[i + 11].b * -0.003771f +
- ycaIn[i + 13].b * 0.001064f;
- }
-
- ycaOut[j].g = ycaIn[i].g;
- ycaOut[j].a = ycaIn[i].a;
+ if ((j & 1) == 0)
+ {
+ ycaOut[j].r = ycaIn[i - 13].r * 0.001064f +
+ ycaIn[i - 11].r * -0.003771f +
+ ycaIn[i - 9].r * 0.009801f +
+ ycaIn[i - 7].r * -0.021586f +
+ ycaIn[i - 5].r * 0.043978f +
+ ycaIn[i - 3].r * -0.093067f +
+ ycaIn[i - 1].r * 0.313659f +
+ ycaIn[i ].r * 0.499846f +
+ ycaIn[i + 1].r * 0.313659f +
+ ycaIn[i + 3].r * -0.093067f +
+ ycaIn[i + 5].r * 0.043978f +
+ ycaIn[i + 7].r * -0.021586f +
+ ycaIn[i + 9].r * 0.009801f +
+ ycaIn[i + 11].r * -0.003771f +
+ ycaIn[i + 13].r * 0.001064f;
+
+ ycaOut[j].b = ycaIn[i - 13].b * 0.001064f +
+ ycaIn[i - 11].b * -0.003771f +
+ ycaIn[i - 9].b * 0.009801f +
+ ycaIn[i - 7].b * -0.021586f +
+ ycaIn[i - 5].b * 0.043978f +
+ ycaIn[i - 3].b * -0.093067f +
+ ycaIn[i - 1].b * 0.313659f +
+ ycaIn[i ].b * 0.499846f +
+ ycaIn[i + 1].b * 0.313659f +
+ ycaIn[i + 3].b * -0.093067f +
+ ycaIn[i + 5].b * 0.043978f +
+ ycaIn[i + 7].b * -0.021586f +
+ ycaIn[i + 9].b * 0.009801f +
+ ycaIn[i + 11].b * -0.003771f +
+ ycaIn[i + 13].b * 0.001064f;
+ }
+
+ ycaOut[j].g = ycaIn[i].g;
+ ycaOut[j].a = ycaIn[i].a;
}
}
void
decimateChromaVert (int n,
- const Rgba * const ycaIn[N],
- Rgba ycaOut[/*n*/])
+ const Rgba * const ycaIn[N],
+ Rgba ycaOut[/*n*/])
{
for (int i = 0; i < n; ++i)
{
- if ((i & 1) == 0)
- {
- ycaOut[i].r = ycaIn[ 0][i].r * 0.001064f +
- ycaIn[ 2][i].r * -0.003771f +
- ycaIn[ 4][i].r * 0.009801f +
- ycaIn[ 6][i].r * -0.021586f +
- ycaIn[ 8][i].r * 0.043978f +
- ycaIn[10][i].r * -0.093067f +
- ycaIn[12][i].r * 0.313659f +
- ycaIn[13][i].r * 0.499846f +
- ycaIn[14][i].r * 0.313659f +
- ycaIn[16][i].r * -0.093067f +
- ycaIn[18][i].r * 0.043978f +
- ycaIn[20][i].r * -0.021586f +
- ycaIn[22][i].r * 0.009801f +
- ycaIn[24][i].r * -0.003771f +
- ycaIn[26][i].r * 0.001064f;
-
- ycaOut[i].b = ycaIn[ 0][i].b * 0.001064f +
- ycaIn[ 2][i].b * -0.003771f +
- ycaIn[ 4][i].b * 0.009801f +
- ycaIn[ 6][i].b * -0.021586f +
- ycaIn[ 8][i].b * 0.043978f +
- ycaIn[10][i].b * -0.093067f +
- ycaIn[12][i].b * 0.313659f +
- ycaIn[13][i].b * 0.499846f +
- ycaIn[14][i].b * 0.313659f +
- ycaIn[16][i].b * -0.093067f +
- ycaIn[18][i].b * 0.043978f +
- ycaIn[20][i].b * -0.021586f +
- ycaIn[22][i].b * 0.009801f +
- ycaIn[24][i].b * -0.003771f +
- ycaIn[26][i].b * 0.001064f;
- }
-
- ycaOut[i].g = ycaIn[13][i].g;
- ycaOut[i].a = ycaIn[13][i].a;
+ if ((i & 1) == 0)
+ {
+ ycaOut[i].r = ycaIn[ 0][i].r * 0.001064f +
+ ycaIn[ 2][i].r * -0.003771f +
+ ycaIn[ 4][i].r * 0.009801f +
+ ycaIn[ 6][i].r * -0.021586f +
+ ycaIn[ 8][i].r * 0.043978f +
+ ycaIn[10][i].r * -0.093067f +
+ ycaIn[12][i].r * 0.313659f +
+ ycaIn[13][i].r * 0.499846f +
+ ycaIn[14][i].r * 0.313659f +
+ ycaIn[16][i].r * -0.093067f +
+ ycaIn[18][i].r * 0.043978f +
+ ycaIn[20][i].r * -0.021586f +
+ ycaIn[22][i].r * 0.009801f +
+ ycaIn[24][i].r * -0.003771f +
+ ycaIn[26][i].r * 0.001064f;
+
+ ycaOut[i].b = ycaIn[ 0][i].b * 0.001064f +
+ ycaIn[ 2][i].b * -0.003771f +
+ ycaIn[ 4][i].b * 0.009801f +
+ ycaIn[ 6][i].b * -0.021586f +
+ ycaIn[ 8][i].b * 0.043978f +
+ ycaIn[10][i].b * -0.093067f +
+ ycaIn[12][i].b * 0.313659f +
+ ycaIn[13][i].b * 0.499846f +
+ ycaIn[14][i].b * 0.313659f +
+ ycaIn[16][i].b * -0.093067f +
+ ycaIn[18][i].b * 0.043978f +
+ ycaIn[20][i].b * -0.021586f +
+ ycaIn[22][i].b * 0.009801f +
+ ycaIn[24][i].b * -0.003771f +
+ ycaIn[26][i].b * 0.001064f;
+ }
+
+ ycaOut[i].g = ycaIn[13][i].g;
+ ycaOut[i].a = ycaIn[13][i].a;
}
}
void
roundYCA (int n,
- unsigned int roundY,
- unsigned int roundC,
- const Rgba ycaIn[/*n*/],
- Rgba ycaOut[/*n*/])
+ unsigned int roundY,
+ unsigned int roundC,
+ const Rgba ycaIn[/*n*/],
+ Rgba ycaOut[/*n*/])
{
for (int i = 0; i < n; ++i)
{
- ycaOut[i].g = ycaIn[i].g.round (roundY);
- ycaOut[i].a = ycaIn[i].a;
-
- if ((i & 1) == 0)
- {
- ycaOut[i].r = ycaIn[i].r.round (roundC);
- ycaOut[i].b = ycaIn[i].b.round (roundC);
- }
+ ycaOut[i].g = ycaIn[i].g.round (roundY);
+ ycaOut[i].a = ycaIn[i].a;
+
+ if ((i & 1) == 0)
+ {
+ ycaOut[i].r = ycaIn[i].r.round (roundC);
+ ycaOut[i].b = ycaIn[i].b.round (roundC);
+ }
}
}
void
reconstructChromaHoriz (int n,
- const Rgba ycaIn[/*n+N-1*/],
- Rgba ycaOut[/*n*/])
+ const Rgba ycaIn[/*n+N-1*/],
+ Rgba ycaOut[/*n*/])
{
#ifdef DEBUG
- assert (ycaIn != ycaOut);
+ assert (ycaIn != ycaOut);
#endif
int begin = N2;
for (int i = begin, j = 0; i < end; ++i, ++j)
{
- if (j & 1)
- {
- ycaOut[j].r = ycaIn[i - 13].r * 0.002128f +
- ycaIn[i - 11].r * -0.007540f +
- ycaIn[i - 9].r * 0.019597f +
- ycaIn[i - 7].r * -0.043159f +
- ycaIn[i - 5].r * 0.087929f +
- ycaIn[i - 3].r * -0.186077f +
- ycaIn[i - 1].r * 0.627123f +
- ycaIn[i + 1].r * 0.627123f +
- ycaIn[i + 3].r * -0.186077f +
- ycaIn[i + 5].r * 0.087929f +
- ycaIn[i + 7].r * -0.043159f +
- ycaIn[i + 9].r * 0.019597f +
- ycaIn[i + 11].r * -0.007540f +
- ycaIn[i + 13].r * 0.002128f;
-
- ycaOut[j].b = ycaIn[i - 13].b * 0.002128f +
- ycaIn[i - 11].b * -0.007540f +
- ycaIn[i - 9].b * 0.019597f +
- ycaIn[i - 7].b * -0.043159f +
- ycaIn[i - 5].b * 0.087929f +
- ycaIn[i - 3].b * -0.186077f +
- ycaIn[i - 1].b * 0.627123f +
- ycaIn[i + 1].b * 0.627123f +
- ycaIn[i + 3].b * -0.186077f +
- ycaIn[i + 5].b * 0.087929f +
- ycaIn[i + 7].b * -0.043159f +
- ycaIn[i + 9].b * 0.019597f +
- ycaIn[i + 11].b * -0.007540f +
- ycaIn[i + 13].b * 0.002128f;
- }
- else
- {
- ycaOut[j].r = ycaIn[i].r;
- ycaOut[j].b = ycaIn[i].b;
- }
-
- ycaOut[j].g = ycaIn[i].g;
- ycaOut[j].a = ycaIn[i].a;
+ if (j & 1)
+ {
+ ycaOut[j].r = ycaIn[i - 13].r * 0.002128f +
+ ycaIn[i - 11].r * -0.007540f +
+ ycaIn[i - 9].r * 0.019597f +
+ ycaIn[i - 7].r * -0.043159f +
+ ycaIn[i - 5].r * 0.087929f +
+ ycaIn[i - 3].r * -0.186077f +
+ ycaIn[i - 1].r * 0.627123f +
+ ycaIn[i + 1].r * 0.627123f +
+ ycaIn[i + 3].r * -0.186077f +
+ ycaIn[i + 5].r * 0.087929f +
+ ycaIn[i + 7].r * -0.043159f +
+ ycaIn[i + 9].r * 0.019597f +
+ ycaIn[i + 11].r * -0.007540f +
+ ycaIn[i + 13].r * 0.002128f;
+
+ ycaOut[j].b = ycaIn[i - 13].b * 0.002128f +
+ ycaIn[i - 11].b * -0.007540f +
+ ycaIn[i - 9].b * 0.019597f +
+ ycaIn[i - 7].b * -0.043159f +
+ ycaIn[i - 5].b * 0.087929f +
+ ycaIn[i - 3].b * -0.186077f +
+ ycaIn[i - 1].b * 0.627123f +
+ ycaIn[i + 1].b * 0.627123f +
+ ycaIn[i + 3].b * -0.186077f +
+ ycaIn[i + 5].b * 0.087929f +
+ ycaIn[i + 7].b * -0.043159f +
+ ycaIn[i + 9].b * 0.019597f +
+ ycaIn[i + 11].b * -0.007540f +
+ ycaIn[i + 13].b * 0.002128f;
+ }
+ else
+ {
+ ycaOut[j].r = ycaIn[i].r;
+ ycaOut[j].b = ycaIn[i].b;
+ }
+
+ ycaOut[j].g = ycaIn[i].g;
+ ycaOut[j].a = ycaIn[i].a;
}
}
void
reconstructChromaVert (int n,
- const Rgba * const ycaIn[N],
- Rgba ycaOut[/*n*/])
+ const Rgba * const ycaIn[N],
+ Rgba ycaOut[/*n*/])
{
for (int i = 0; i < n; ++i)
{
- ycaOut[i].r = ycaIn[ 0][i].r * 0.002128f +
- ycaIn[ 2][i].r * -0.007540f +
- ycaIn[ 4][i].r * 0.019597f +
- ycaIn[ 6][i].r * -0.043159f +
- ycaIn[ 8][i].r * 0.087929f +
- ycaIn[10][i].r * -0.186077f +
- ycaIn[12][i].r * 0.627123f +
- ycaIn[14][i].r * 0.627123f +
- ycaIn[16][i].r * -0.186077f +
- ycaIn[18][i].r * 0.087929f +
- ycaIn[20][i].r * -0.043159f +
- ycaIn[22][i].r * 0.019597f +
- ycaIn[24][i].r * -0.007540f +
- ycaIn[26][i].r * 0.002128f;
-
- ycaOut[i].b = ycaIn[ 0][i].b * 0.002128f +
- ycaIn[ 2][i].b * -0.007540f +
- ycaIn[ 4][i].b * 0.019597f +
- ycaIn[ 6][i].b * -0.043159f +
- ycaIn[ 8][i].b * 0.087929f +
- ycaIn[10][i].b * -0.186077f +
- ycaIn[12][i].b * 0.627123f +
- ycaIn[14][i].b * 0.627123f +
- ycaIn[16][i].b * -0.186077f +
- ycaIn[18][i].b * 0.087929f +
- ycaIn[20][i].b * -0.043159f +
- ycaIn[22][i].b * 0.019597f +
- ycaIn[24][i].b * -0.007540f +
- ycaIn[26][i].b * 0.002128f;
-
- ycaOut[i].g = ycaIn[13][i].g;
- ycaOut[i].a = ycaIn[13][i].a;
+ ycaOut[i].r = ycaIn[ 0][i].r * 0.002128f +
+ ycaIn[ 2][i].r * -0.007540f +
+ ycaIn[ 4][i].r * 0.019597f +
+ ycaIn[ 6][i].r * -0.043159f +
+ ycaIn[ 8][i].r * 0.087929f +
+ ycaIn[10][i].r * -0.186077f +
+ ycaIn[12][i].r * 0.627123f +
+ ycaIn[14][i].r * 0.627123f +
+ ycaIn[16][i].r * -0.186077f +
+ ycaIn[18][i].r * 0.087929f +
+ ycaIn[20][i].r * -0.043159f +
+ ycaIn[22][i].r * 0.019597f +
+ ycaIn[24][i].r * -0.007540f +
+ ycaIn[26][i].r * 0.002128f;
+
+ ycaOut[i].b = ycaIn[ 0][i].b * 0.002128f +
+ ycaIn[ 2][i].b * -0.007540f +
+ ycaIn[ 4][i].b * 0.019597f +
+ ycaIn[ 6][i].b * -0.043159f +
+ ycaIn[ 8][i].b * 0.087929f +
+ ycaIn[10][i].b * -0.186077f +
+ ycaIn[12][i].b * 0.627123f +
+ ycaIn[14][i].b * 0.627123f +
+ ycaIn[16][i].b * -0.186077f +
+ ycaIn[18][i].b * 0.087929f +
+ ycaIn[20][i].b * -0.043159f +
+ ycaIn[22][i].b * 0.019597f +
+ ycaIn[24][i].b * -0.007540f +
+ ycaIn[26][i].b * 0.002128f;
+
+ ycaOut[i].g = ycaIn[13][i].g;
+ ycaOut[i].a = ycaIn[13][i].a;
}
}
-
+
void
-YCAtoRGBA (const Imath::V3f &yw,
- int n,
- const Rgba ycaIn[/*n*/],
- Rgba rgbaOut[/*n*/])
+YCAtoRGBA (const IMATH_NAMESPACE::V3f &yw,
+ int n,
+ const Rgba ycaIn[/*n*/],
+ Rgba rgbaOut[/*n*/])
{
for (int i = 0; i < n; ++i)
{
- const Rgba &in = ycaIn[i];
- Rgba &out = rgbaOut[i];
-
- if (in.r == 0 && in.b == 0)
- {
- //
- // Special case -- both chroma channels are 0. To avoid
- // rounding errors, we explicitly set the output R, G and B
- // channels equal to the input luminance.
- //
- // The special cases here and in RGBAtoYCA() ensure that
- // converting black-and white images from RGBA to YCA and
- // back is lossless.
- //
-
- out.r = in.g;
- out.g = in.g;
- out.b = in.g;
- out.a = in.a;
- }
- else
- {
- float Y = in.g;
- float r = (in.r + 1) * Y;
- float b = (in.b + 1) * Y;
- float g = (Y - r * yw.x - b * yw.z) / yw.y;
-
- out.r = r;
- out.g = g;
- out.b = b;
- out.a = in.a;
- }
+ const Rgba &in = ycaIn[i];
+ Rgba &out = rgbaOut[i];
+
+ if (in.r == 0 && in.b == 0)
+ {
+ //
+ // Special case -- both chroma channels are 0. To avoid
+ // rounding errors, we explicitly set the output R, G and B
+ // channels equal to the input luminance.
+ //
+ // The special cases here and in RGBAtoYCA() ensure that
+ // converting black-and white images from RGBA to YCA and
+ // back is lossless.
+ //
+
+ out.r = in.g;
+ out.g = in.g;
+ out.b = in.g;
+ out.a = in.a;
+ }
+ else
+ {
+ float Y = in.g;
+ float r = (in.r + 1) * Y;
+ float b = (in.b + 1) * Y;
+ float g = (Y - r * yw.x - b * yw.z) / yw.y;
+
+ out.r = r;
+ out.g = g;
+ out.b = b;
+ out.a = in.a;
+ }
}
}
float rgbMin = min (in.r, min (in.g, in.b));
if (rgbMax > 0)
- return 1 - rgbMin / rgbMax;
+ return 1 - rgbMin / rgbMax;
else
- return 0;
+ return 0;
}
if (Yout > 0)
{
- out.r *= Yin / Yout;
- out.g *= Yin / Yout;
- out.b *= Yin / Yout;
+ out.r *= Yin / Yout;
+ out.g *= Yin / Yout;
+ out.b *= Yin / Yout;
}
}
} // namespace
-
+
void
-fixSaturation (const Imath::V3f &yw,
- int n,
- const Rgba * const rgbaIn[3],
- Rgba rgbaOut[/*n*/])
+fixSaturation (const IMATH_NAMESPACE::V3f &yw,
+ int n,
+ const Rgba * const rgbaIn[3],
+ Rgba rgbaOut[/*n*/])
{
float neighborA2 = saturation (rgbaIn[0][0]);
float neighborA1 = neighborA2;
for (int i = 0; i < n; ++i)
{
- float neighborA0 = neighborA1;
- neighborA1 = neighborA2;
+ float neighborA0 = neighborA1;
+ neighborA1 = neighborA2;
- float neighborB0 = neighborB1;
- neighborB1 = neighborB2;
+ float neighborB0 = neighborB1;
+ neighborB1 = neighborB2;
- if (i < n - 1)
- {
- neighborA2 = saturation (rgbaIn[0][i + 1]);
- neighborB2 = saturation (rgbaIn[2][i + 1]);
- }
+ if (i < n - 1)
+ {
+ neighborA2 = saturation (rgbaIn[0][i + 1]);
+ neighborB2 = saturation (rgbaIn[2][i + 1]);
+ }
- //
- // A0 A1 A2
- // rgbaOut[i]
- // B0 B1 B2
- //
+ //
+ // A0 A1 A2
+ // rgbaOut[i]
+ // B0 B1 B2
+ //
- float sMean = min (1.0f, 0.25f * (neighborA0 + neighborA2 +
- neighborB0 + neighborB2));
+ float sMean = min (1.0f, 0.25f * (neighborA0 + neighborA2 +
+ neighborB0 + neighborB2));
- const Rgba &in = rgbaIn[1][i];
- Rgba &out = rgbaOut[i];
+ const Rgba &in = rgbaIn[1][i];
+ Rgba &out = rgbaOut[i];
- float s = saturation (in);
+ float s = saturation (in);
- if (s > sMean)
- {
- float sMax = min (1.0f, 1 - (1 - sMean) * 0.25f);
+ if (s > sMean)
+ {
+ float sMax = min (1.0f, 1 - (1 - sMean) * 0.25f);
- if (s > sMax)
- {
- desaturate (in, sMax / s, yw, out);
- continue;
- }
- }
+ if (s > sMax)
+ {
+ desaturate (in, sMax / s, yw, out);
+ continue;
+ }
+ }
- out = in;
+ out = in;
}
}
} // namespace RgbaYca
-} // namespace Imf
+OPENEXR_IMF_INTERNAL_NAMESPACE_SOURCE_EXIT
// Next, decimateChomaHoriz() eliminates the chroma values from
// the odd-numbered pixels in every scan line:
//
-// YCA YA YCA YA ... YCA YA
-// YCA YA YCA YA ... YCA YA
-// YCA YA YCA YA ... YCA YA
-// YCA YA YCA YA ... YCA YA
+// YCA YA YCA YA ... YCA YA
+// YCA YA YCA YA ... YCA YA
+// YCA YA YCA YA ... YCA YA
+// YCA YA YCA YA ... YCA YA
// ...
-// YCA YA YCA YA ... YCA YA
-// YCA YA YCA YA ... YCA YA
+// YCA YA YCA YA ... YCA YA
+// YCA YA YCA YA ... YCA YA
//
// decimateChromaVert() eliminates all chroma values from the
// odd-numbered scan lines:
//
-// YCA YA YCA YA ... YCA YA
-// YA YA YA YA ... YA YA
-// YCA YA YCA YA ... YCA YA
-// YA YA YA YA ... YA YA
+// YCA YA YCA YA ... YCA YA
+// YA YA YA YA ... YA YA
+// YCA YA YCA YA ... YCA YA
+// YA YA YA YA ... YA YA
// ...
-// YCA YA YCA YA ... YCA YA
-// YA YA YA YA ... YA YA
+// YCA YA YCA YA ... YCA YA
+// YA YA YA YA ... YA YA
//
// Finally, roundYCA() reduces the precision of the luminance
// and chroma values so that the pixel data shrink more when
//
//-----------------------------------------------------------------------------
-#include <ImfRgba.h>
-#include <ImfChromaticities.h>
+#include "ImfRgba.h"
+#include "ImfChromaticities.h"
+#include "ImfNamespace.h"
+
+OPENEXR_IMF_INTERNAL_NAMESPACE_HEADER_ENTER
-namespace Imf {
namespace RgbaYca {
// Convert a set of primary chromaticities into a set of weighting
// factors for computing a pixels's luminance, Y, from R, G and B
//
-
-Imath::V3f computeYw (const Chromaticities &cr);
+
+IMF_EXPORT
+IMATH_NAMESPACE::V3f computeYw (const Chromaticities &cr);
//
// yw is a set of RGB-to-Y weighting factors, as computed by computeYw().
//
-void RGBAtoYCA (const Imath::V3f &yw,
- int n,
- bool aIsValid,
- const Rgba rgbaIn[/*n*/],
- Rgba ycaOut[/*n*/]);
+IMF_EXPORT
+void RGBAtoYCA (const IMATH_NAMESPACE::V3f &yw,
+ int n,
+ bool aIsValid,
+ const Rgba rgbaIn[/*n*/],
+ Rgba ycaOut[/*n*/]);
//
// Perform horizontal low-pass filtering and subsampling of
// "real" input pixel.
//
+IMF_EXPORT
void decimateChromaHoriz (int n,
- const Rgba ycaIn[/*n+N-1*/],
- Rgba ycaOut[/*n*/]);
+ const Rgba ycaIn[/*n+N-1*/],
+ Rgba ycaOut[/*n*/]);
//
// Perform vertical chroma channel low-pass filtering and subsampling.
// of output pixels.
//
+IMF_EXPORT
void decimateChromaVert (int n,
- const Rgba * const ycaIn[N],
- Rgba ycaOut[/*n*/]);
+ const Rgba * const ycaIn[N],
+ Rgba ycaOut[/*n*/]);
//
// Round the luminance and chroma channels of an array of YCA
// are rounded to roundY and roundC bits respectively.
//
+IMF_EXPORT
void roundYCA (int n,
- unsigned int roundY,
- unsigned int roundC,
- const Rgba ycaIn[/*n*/],
- Rgba ycaOut[/*n*/]);
+ unsigned int roundY,
+ unsigned int roundC,
+ const Rgba ycaIn[/*n*/],
+ Rgba ycaOut[/*n*/]);
//
// For a scan line that has valid chroma data only for every other pixel,
// reconstruct the missing chroma values.
//
+IMF_EXPORT
void reconstructChromaHoriz (int n,
- const Rgba ycaIn[/*n+N-1*/],
- Rgba ycaOut[/*n*/]);
+ const Rgba ycaIn[/*n+N-1*/],
+ Rgba ycaOut[/*n*/]);
//
// For a scan line that has only luminance and no valid chroma data,
// reconstruct chroma from the surronding N scan lines.
//
+IMF_EXPORT
void reconstructChromaVert (int n,
- const Rgba * const ycaIn[N],
- Rgba ycaOut[/*n*/]);
-
+ const Rgba * const ycaIn[N],
+ Rgba ycaOut[/*n*/]);
+
//
// Convert an array of n YCA (luminance/chroma/alpha) pixels to RGBA.
// This function is the inverse of RGBAtoYCA().
// yw is a set of RGB-to-Y weighting factors, as computed by computeYw().
//
-void YCAtoRGBA (const Imath::V3f &yw,
- int n,
- const Rgba ycaIn[/*n*/],
- Rgba rgbaOut[/*n*/]);
-
+IMF_EXPORT
+void YCAtoRGBA (const IMATH_NAMESPACE::V3f &yw,
+ int n,
+ const Rgba ycaIn[/*n*/],
+ Rgba rgbaOut[/*n*/]);
+
//
// Eliminate super-saturated pixels:
//
// saturation of rgbaIn[1], and stores the result in rgbaOut.
//
-void fixSaturation (const Imath::V3f &yw,
- int n,
- const Rgba * const rgbaIn[3],
- Rgba rgbaOut[/*n*/]);
+IMF_EXPORT
+void fixSaturation (const IMATH_NAMESPACE::V3f &yw,
+ int n,
+ const Rgba * const rgbaIn[3],
+ Rgba rgbaOut[/*n*/]);
} // namespace RgbaYca
-} // namespace Imf
+OPENEXR_IMF_INTERNAL_NAMESPACE_HEADER_EXIT
#endif
--- /dev/null
+///////////////////////////////////////////////////////////////////////////
+//
+// Copyright (c) 2002, Industrial Light & Magic, a division of Lucas
+// Digital Ltd. LLC
+//
+// All rights reserved.
+//
+// Redistribution and use in source and binary forms, with or without
+// modification, are permitted provided that the following conditions are
+// met:
+// * Redistributions of source code must retain the above copyright
+// notice, this list of conditions and the following disclaimer.
+// * Redistributions in binary form must reproduce the above
+// copyright notice, this list of conditions and the following disclaimer
+// in the documentation and/or other materials provided with the
+// distribution.
+// * Neither the name of Industrial Light & Magic nor the names of
+// its contributors may be used to endorse or promote products derived
+// from this software without specific prior written permission.
+//
+// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+//
+///////////////////////////////////////////////////////////////////////////
+
+#include <string.h>
+#include "ImfRle.h"
+#include "ImfNamespace.h"
+
+OPENEXR_IMF_INTERNAL_NAMESPACE_SOURCE_ENTER
+
+namespace {
+
+const int MIN_RUN_LENGTH = 3;
+const int MAX_RUN_LENGTH = 127;
+
+}
+
+//
+// Compress an array of bytes, using run-length encoding,
+// and return the length of the compressed data.
+//
+
+int
+rleCompress (int inLength, const char in[], signed char out[])
+{
+ const char *inEnd = in + inLength;
+ const char *runStart = in;
+ const char *runEnd = in + 1;
+ signed char *outWrite = out;
+
+ while (runStart < inEnd)
+ {
+ while (runEnd < inEnd &&
+ *runStart == *runEnd &&
+ runEnd - runStart - 1 < MAX_RUN_LENGTH)
+ {
+ ++runEnd;
+ }
+
+ if (runEnd - runStart >= MIN_RUN_LENGTH)
+ {
+ //
+ // Compressable run
+ //
+
+ *outWrite++ = (runEnd - runStart) - 1;
+ *outWrite++ = *(signed char *) runStart;
+ runStart = runEnd;
+ }
+ else
+ {
+ //
+ // Uncompressable run
+ //
+
+ while (runEnd < inEnd &&
+ ((runEnd + 1 >= inEnd ||
+ *runEnd != *(runEnd + 1)) ||
+ (runEnd + 2 >= inEnd ||
+ *(runEnd + 1) != *(runEnd + 2))) &&
+ runEnd - runStart < MAX_RUN_LENGTH)
+ {
+ ++runEnd;
+ }
+
+ *outWrite++ = runStart - runEnd;
+
+ while (runStart < runEnd)
+ {
+ *outWrite++ = *(signed char *) (runStart++);
+ }
+ }
+
+ ++runEnd;
+ }
+
+ return outWrite - out;
+}
+
+
+//
+// Uncompress an array of bytes compressed with rleCompress().
+// Returns the length of the oncompressed data, or 0 if the
+// length of the uncompressed data would be more than maxLength.
+//
+
+int
+rleUncompress (int inLength, int maxLength, const signed char in[], char out[])
+{
+ char *outStart = out;
+
+ while (inLength > 0)
+ {
+ if (*in < 0)
+ {
+ int count = -((int)*in++);
+ inLength -= count + 1;
+
+ if (0 > (maxLength -= count))
+ return 0;
+
+ memcpy(out, in, count);
+ out += count;
+ in += count;
+ }
+ else
+ {
+ int count = *in++;
+ inLength -= 2;
+
+ if (0 > (maxLength -= count + 1))
+ return 0;
+
+ memset(out, *(char*)in, count+1);
+ out += count+1;
+
+ in++;
+ }
+ }
+
+ return out - outStart;
+}
+
+
+
+
+OPENEXR_IMF_INTERNAL_NAMESPACE_SOURCE_EXIT
--- /dev/null
+///////////////////////////////////////////////////////////////////////////
+//
+// Copyright (c) 2002, Industrial Light & Magic, a division of Lucas
+// Digital Ltd. LLC
+//
+// All rights reserved.
+//
+// Redistribution and use in source and binary forms, with or without
+// modification, are permitted provided that the following conditions are
+// met:
+// * Redistributions of source code must retain the above copyright
+// notice, this list of conditions and the following disclaimer.
+// * Redistributions in binary form must reproduce the above
+// copyright notice, this list of conditions and the following disclaimer
+// in the documentation and/or other materials provided with the
+// distribution.
+// * Neither the name of Industrial Light & Magic nor the names of
+// its contributors may be used to endorse or promote products derived
+// from this software without specific prior written permission.
+//
+// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+//
+///////////////////////////////////////////////////////////////////////////
+
+#ifndef INCLUDED_IMF_RLE_H_
+#define INCLUDED_IMF_RLE_H_
+
+#include "ImfNamespace.h"
+#include "ImfExport.h"
+
+OPENEXR_IMF_INTERNAL_NAMESPACE_HEADER_ENTER
+
+//
+// Compress an array of bytes, using run-length encoding,
+// and return the length of the compressed data.
+//
+
+IMF_EXPORT
+int rleCompress (int inLength, const char in[], signed char out[]);
+
+//
+// Uncompress an array of bytes compressed with rleCompress().
+// Returns the length of the uncompressed data, or 0 if the
+// length of the uncompressed data would be more than maxLength.
+//
+
+IMF_EXPORT
+int rleUncompress (int inLength, int maxLength,
+ const signed char in[], char out[]);
+
+OPENEXR_IMF_INTERNAL_NAMESPACE_HEADER_EXIT
+
+#endif
//
// Copyright (c) 2002, Industrial Light & Magic, a division of Lucas
// Digital Ltd. LLC
-//
+//
// All rights reserved.
-//
+//
// Redistribution and use in source and binary forms, with or without
// modification, are permitted provided that the following conditions are
// met:
// distribution.
// * Neither the name of Industrial Light & Magic nor the names of
// its contributors may be used to endorse or promote products derived
-// from this software without specific prior written permission.
-//
+// from this software without specific prior written permission.
+//
// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
//
//-----------------------------------------------------------------------------
-#include <ImfRleCompressor.h>
-#include <ImfCheckedArithmetic.h>
+#include "ImfRleCompressor.h"
+#include "ImfCheckedArithmetic.h"
+#include "ImfRle.h"
#include "Iex.h"
+#include "ImfNamespace.h"
-namespace Imf {
-namespace {
-
-const int MIN_RUN_LENGTH = 3;
-const int MAX_RUN_LENGTH = 127;
-
-
-//
-// Compress an array of bytes, using run-length encoding,
-// and return the length of the compressed data.
-//
-
-int
-rleCompress (int inLength, const char in[], signed char out[])
-{
- const char *inEnd = in + inLength;
- const char *runStart = in;
- const char *runEnd = in + 1;
- signed char *outWrite = out;
-
- while (runStart < inEnd)
- {
- while (runEnd < inEnd &&
- *runStart == *runEnd &&
- runEnd - runStart - 1 < MAX_RUN_LENGTH)
- {
- ++runEnd;
- }
-
- if (runEnd - runStart >= MIN_RUN_LENGTH)
- {
- //
- // Compressable run
- //
-
- *outWrite++ = (runEnd - runStart) - 1;
- *outWrite++ = *(signed char *) runStart;
- runStart = runEnd;
- }
- else
- {
- //
- // Uncompressable run
- //
-
- while (runEnd < inEnd &&
- ((runEnd + 1 >= inEnd ||
- *runEnd != *(runEnd + 1)) ||
- (runEnd + 2 >= inEnd ||
- *(runEnd + 1) != *(runEnd + 2))) &&
- runEnd - runStart < MAX_RUN_LENGTH)
- {
- ++runEnd;
- }
-
- *outWrite++ = runStart - runEnd;
-
- while (runStart < runEnd)
- {
- *outWrite++ = *(signed char *) (runStart++);
- }
- }
-
- ++runEnd;
- }
-
- return outWrite - out;
-}
-
-
-//
-// Uncompress an array of bytes compressed with rleCompress().
-// Returns the length of the oncompressed data, or 0 if the
-// length of the uncompressed data would be more than maxLength.
-//
-
-int
-rleUncompress (int inLength, int maxLength, const signed char in[], char out[])
-{
- char *outStart = out;
-
- while (inLength > 0)
- {
- if (*in < 0)
- {
- int count = -((int)*in++);
- inLength -= count + 1;
-
- if (0 > (maxLength -= count))
- return 0;
-
- while (count-- > 0)
- *out++ = *(char *) (in++);
- }
- else
- {
- int count = *in++;
- inLength -= 2;
-
- if (0 > (maxLength -= count + 1))
- return 0;
-
- while (count-- >= 0)
- *out++ = *(char *) in;
-
- in++;
- }
- }
-
- return out - outStart;
-}
-
-} // namespace
-
+OPENEXR_IMF_INTERNAL_NAMESPACE_SOURCE_ENTER
RleCompressor::RleCompressor (const Header &hdr, size_t maxScanLineSize):
Compressor (hdr),
int
RleCompressor::compress (const char *inPtr,
- int inSize,
- int /*minY*/,
- const char *&outPtr)
+ int inSize,
+ int minY,
+ const char *&outPtr)
{
//
- // Special case Â- empty input buffer
+ // Special case �- empty input buffer
//
if (inSize == 0)
{
- outPtr = _outBuffer;
- return 0;
+ outPtr = _outBuffer;
+ return 0;
}
//
//
{
- char *t1 = _tmpBuffer;
- char *t2 = _tmpBuffer + (inSize + 1) / 2;
- const char *stop = inPtr + inSize;
+ char *t1 = _tmpBuffer;
+ char *t2 = _tmpBuffer + (inSize + 1) / 2;
+ const char *stop = inPtr + inSize;
- while (true)
- {
- if (inPtr < stop)
- *(t1++) = *(inPtr++);
- else
- break;
-
- if (inPtr < stop)
- *(t2++) = *(inPtr++);
- else
- break;
- }
+ while (true)
+ {
+ if (inPtr < stop)
+ *(t1++) = *(inPtr++);
+ else
+ break;
+
+ if (inPtr < stop)
+ *(t2++) = *(inPtr++);
+ else
+ break;
+ }
}
//
//
{
- unsigned char *t = (unsigned char *) _tmpBuffer + 1;
- unsigned char *stop = (unsigned char *) _tmpBuffer + inSize;
- int p = t[-1];
+ unsigned char *t = (unsigned char *) _tmpBuffer + 1;
+ unsigned char *stop = (unsigned char *) _tmpBuffer + inSize;
+ int p = t[-1];
- while (t < stop)
- {
- int d = int (t[0]) - p + (128 + 256);
- p = t[0];
- t[0] = d;
- ++t;
- }
+ while (t < stop)
+ {
+ int d = int (t[0]) - p + (128 + 256);
+ p = t[0];
+ t[0] = d;
+ ++t;
+ }
}
//
int
RleCompressor::uncompress (const char *inPtr,
- int inSize,
- int /*minY*/,
- const char *&outPtr)
+ int inSize,
+ int minY,
+ const char *&outPtr)
{
//
- // Special case Â- empty input buffer
+ // Special case �- empty input buffer
//
if (inSize == 0)
{
- outPtr = _outBuffer;
- return 0;
+ outPtr = _outBuffer;
+ return 0;
}
//
int outSize;
if (0 == (outSize = rleUncompress (inSize, _maxScanLineSize,
- (const signed char *) inPtr,
- _tmpBuffer)))
+ (const signed char *) inPtr,
+ _tmpBuffer)))
{
- throw Iex::InputExc ("Data decoding (rle) failed.");
+ throw IEX_NAMESPACE::InputExc ("Data decoding (rle) failed.");
}
//
//
{
- unsigned char *t = (unsigned char *) _tmpBuffer + 1;
- unsigned char *stop = (unsigned char *) _tmpBuffer + outSize;
+ unsigned char *t = (unsigned char *) _tmpBuffer + 1;
+ unsigned char *stop = (unsigned char *) _tmpBuffer + outSize;
- while (t < stop)
- {
- int d = int (t[-1]) + int (t[0]) - 128;
- t[0] = d;
- ++t;
- }
+ while (t < stop)
+ {
+ int d = int (t[-1]) + int (t[0]) - 128;
+ t[0] = d;
+ ++t;
+ }
}
//
//
{
- const char *t1 = _tmpBuffer;
- const char *t2 = _tmpBuffer + (outSize + 1) / 2;
- char *s = _outBuffer;
- char *stop = s + outSize;
+ const char *t1 = _tmpBuffer;
+ const char *t2 = _tmpBuffer + (outSize + 1) / 2;
+ char *s = _outBuffer;
+ char *stop = s + outSize;
- while (true)
- {
- if (s < stop)
- *(s++) = *(t1++);
- else
- break;
-
- if (s < stop)
- *(s++) = *(t2++);
- else
- break;
- }
+ while (true)
+ {
+ if (s < stop)
+ *(s++) = *(t1++);
+ else
+ break;
+
+ if (s < stop)
+ *(s++) = *(t2++);
+ else
+ break;
+ }
}
outPtr = _outBuffer;
}
-} // namespace Imf
+OPENEXR_IMF_INTERNAL_NAMESPACE_SOURCE_EXIT
//
// Copyright (c) 2002, Industrial Light & Magic, a division of Lucas
// Digital Ltd. LLC
-//
+//
// All rights reserved.
-//
+//
// Redistribution and use in source and binary forms, with or without
// modification, are permitted provided that the following conditions are
// met:
// distribution.
// * Neither the name of Industrial Light & Magic nor the names of
// its contributors may be used to endorse or promote products derived
-// from this software without specific prior written permission.
-//
+// from this software without specific prior written permission.
+//
// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
//
//-----------------------------------------------------------------------------
-#include <ImfCompressor.h>
+#include "ImfCompressor.h"
+#include "ImfNamespace.h"
-namespace Imf {
+OPENEXR_IMF_INTERNAL_NAMESPACE_HEADER_ENTER
class RleCompressor: public Compressor
{
public:
+ IMF_EXPORT
RleCompressor (const Header &hdr, size_t maxScanLineSize);
+ IMF_EXPORT
virtual ~RleCompressor ();
+ IMF_EXPORT
virtual int numScanLines () const;
+ IMF_EXPORT
virtual int compress (const char *inPtr,
- int inSize,
- int minY,
- const char *&outPtr);
+ int inSize,
+ int minY,
+ const char *&outPtr);
+ IMF_EXPORT
virtual int uncompress (const char *inPtr,
- int inSize,
- int minY,
- const char *&outPtr);
+ int inSize,
+ int minY,
+ const char *&outPtr);
private:
int _maxScanLineSize;
};
-} // namespace Imf
+OPENEXR_IMF_INTERNAL_NAMESPACE_HEADER_EXIT
#endif
//
// Copyright (c) 2004, Industrial Light & Magic, a division of Lucas
// Digital Ltd. LLC
-//
+//
// All rights reserved.
-//
+//
// Redistribution and use in source and binary forms, with or without
// modification, are permitted provided that the following conditions are
// met:
// distribution.
// * Neither the name of Industrial Light & Magic nor the names of
// its contributors may be used to endorse or promote products derived
-// from this software without specific prior written permission.
-//
+// from this software without specific prior written permission.
+//
// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
//
//-----------------------------------------------------------------------------
-#include <ImfScanLineInputFile.h>
-#include <ImfChannelList.h>
-#include <ImfMisc.h>
-#include <ImfStdIO.h>
-#include <ImfCompressor.h>
+#include "ImfScanLineInputFile.h"
+#include "ImfChannelList.h"
+#include "ImfMisc.h"
+#include "ImfStdIO.h"
+#include "ImfCompressor.h"
#include "ImathBox.h"
#include "ImathFun.h"
#include <ImfXdr.h>
#include <ImfConvert.h>
#include <ImfThreading.h>
+#include <ImfPartType.h>
#include "IlmThreadPool.h"
#include "IlmThreadSemaphore.h"
#include "IlmThreadMutex.h"
#include "Iex.h"
+#include "ImfVersion.h"
+#include "ImfOptimizedPixelReading.h"
+#include "ImfNamespace.h"
+#include "ImfStandardAttributes.h"
+
+#include <algorithm>
#include <string>
#include <vector>
#include <assert.h>
-#include <algorithm> // for std::max()
+#include <cstring>
+OPENEXR_IMF_INTERNAL_NAMESPACE_SOURCE_ENTER
-namespace Imf {
-using Imath::Box2i;
-using Imath::divp;
-using Imath::modp;
+using IMATH_NAMESPACE::Box2i;
+using IMATH_NAMESPACE::divp;
+using IMATH_NAMESPACE::modp;
using std::string;
using std::vector;
using std::ifstream;
using std::min;
using std::max;
-using IlmThread::Mutex;
-using IlmThread::Lock;
-using IlmThread::Semaphore;
-using IlmThread::Task;
-using IlmThread::TaskGroup;
-using IlmThread::ThreadPool;
+using std::sort;
+using ILMTHREAD_NAMESPACE::Mutex;
+using ILMTHREAD_NAMESPACE::Lock;
+using ILMTHREAD_NAMESPACE::Semaphore;
+using ILMTHREAD_NAMESPACE::Task;
+using ILMTHREAD_NAMESPACE::TaskGroup;
+using ILMTHREAD_NAMESPACE::ThreadPool;
namespace {
double fillValue;
InSliceInfo (PixelType typeInFrameBuffer = HALF,
- PixelType typeInFile = HALF,
- char *base = 0,
- size_t xStride = 0,
- size_t yStride = 0,
- int xSampling = 1,
- int ySampling = 1,
- bool fill = false,
- bool skip = false,
- double fillValue = 0.0);
+ PixelType typeInFile = HALF,
+ char *base = 0,
+ size_t xStride = 0,
+ size_t yStride = 0,
+ int xSampling = 1,
+ int ySampling = 1,
+ bool fill = false,
+ bool skip = false,
+ double fillValue = 0.0);
};
InSliceInfo::InSliceInfo (PixelType tifb,
- PixelType tifl,
- char *b,
- size_t xs, size_t ys,
- int xsm, int ysm,
- bool f, bool s,
- double fv)
+ PixelType tifl,
+ char *b,
+ size_t xs, size_t ys,
+ int xsm, int ysm,
+ bool f, bool s,
+ double fv)
:
typeInFrameBuffer (tifb),
typeInFile (tifl),
delete compressor;
}
+/// helper struct used to detect the order that the channels are stored
+
+struct sliceOptimizationData
+{
+ const char * base; ///< pointer to pixel data
+ bool fill; ///< is this channel being filled with constant, instead of read?
+ half fillValue; ///< if filling, the value to use
+ size_t offset; ///< position this channel will be in the read buffer, accounting for previous channels, as well as their type
+ PixelType type; ///< type of channel
+ size_t xStride; ///< x-stride of channel in buffer (must be set to cause channels to interleave)
+ size_t yStride; ///< y-stride of channel in buffer (must be same in all channels, else order will change, which is bad)
+ int xSampling; ///< channel x sampling
+ int ySampling; ///< channel y sampling
+
+
+ /// we need to keep the list sorted in the order they'll be written to memory
+ bool operator<(const sliceOptimizationData& other ) const
+ {
+ return base < other.base;
+ }
+};
+
+
} // namespace
int minY; // data window's min y coord
int maxY; // data window's max x coord
vector<Int64> lineOffsets; // stores offsets in file for
- // each line
+ // each line
bool fileIsComplete; // True if no scanlines are missing
- // in the file
+ // in the file
int nextLineBufferMinY; // minimum y of the next linebuffer
vector<size_t> bytesPerLine; // combined size of a line over all
// channels
vector<size_t> offsetInLineBuffer; // offset for each scanline in its
// linebuffer
vector<InSliceInfo> slices; // info about channels in file
- IStream * is; // file stream to read from
-
+
vector<LineBuffer*> lineBuffers; // each holds one line buffer
int linesInBuffer; // number of scanlines each buffer
// holds
size_t lineBufferSize; // size of the line buffer
+ int partNumber; // part number
- Data (IStream *is, int numThreads);
+ bool memoryMapped; // if the stream is memory mapped
+ OptimizationMode optimizationMode; // optimizibility of the input file
+ vector<sliceOptimizationData> optimizationData; ///< channel ordering for optimized reading
+
+ Data (int numThreads);
~Data ();
-
+
inline LineBuffer * getLineBuffer (int number); // hash function from line
- // buffer indices into our
- // vector of line buffers
+ // buffer indices into our
+ // vector of line buffers
+
+
};
-ScanLineInputFile::Data::Data (IStream *is, int numThreads):
- is (is)
+ScanLineInputFile::Data::Data (int numThreads):
+ partNumber(-1),
+ memoryMapped(false)
{
//
// We need at least one lineBuffer, but if threading is used,
void
-reconstructLineOffsets (IStream &is,
- LineOrder lineOrder,
- vector<Int64> &lineOffsets)
+reconstructLineOffsets (OPENEXR_IMF_INTERNAL_NAMESPACE::IStream &is,
+ LineOrder lineOrder,
+ vector<Int64> &lineOffsets)
{
Int64 position = is.tellg();
try
{
- for (unsigned int i = 0; i < lineOffsets.size(); i++)
- {
- Int64 lineOffset = is.tellg();
+ for (unsigned int i = 0; i < lineOffsets.size(); i++)
+ {
+ Int64 lineOffset = is.tellg();
- int y;
- Xdr::read <StreamIO> (is, y);
+ int y;
+ OPENEXR_IMF_INTERNAL_NAMESPACE::Xdr::read <OPENEXR_IMF_INTERNAL_NAMESPACE::StreamIO> (is, y);
- int dataSize;
- Xdr::read <StreamIO> (is, dataSize);
+ int dataSize;
+ OPENEXR_IMF_INTERNAL_NAMESPACE::Xdr::read <OPENEXR_IMF_INTERNAL_NAMESPACE::StreamIO> (is, dataSize);
- Xdr::skip <StreamIO> (is, dataSize);
+ Xdr::skip <StreamIO> (is, dataSize);
- if (lineOrder == INCREASING_Y)
- lineOffsets[i] = lineOffset;
- else
- lineOffsets[lineOffsets.size() - i - 1] = lineOffset;
- }
+ if (lineOrder == INCREASING_Y)
+ lineOffsets[i] = lineOffset;
+ else
+ lineOffsets[lineOffsets.size() - i - 1] = lineOffset;
+ }
}
catch (...)
{
- //
- // Suppress all exceptions. This functions is
- // called only to reconstruct the line offset
- // table for incomplete files, and exceptions
- // are likely.
- //
+ //
+ // Suppress all exceptions. This functions is
+ // called only to reconstruct the line offset
+ // table for incomplete files, and exceptions
+ // are likely.
+ //
}
is.clear();
void
-readLineOffsets (IStream &is,
- LineOrder lineOrder,
- vector<Int64> &lineOffsets,
- bool &complete)
+readLineOffsets (OPENEXR_IMF_INTERNAL_NAMESPACE::IStream &is,
+ LineOrder lineOrder,
+ vector<Int64> &lineOffsets,
+ bool &complete)
{
for (unsigned int i = 0; i < lineOffsets.size(); i++)
{
- Xdr::read <StreamIO> (is, lineOffsets[i]);
+ OPENEXR_IMF_INTERNAL_NAMESPACE::Xdr::read <OPENEXR_IMF_INTERNAL_NAMESPACE::StreamIO> (is, lineOffsets[i]);
}
complete = true;
for (unsigned int i = 0; i < lineOffsets.size(); i++)
{
- if (lineOffsets[i] <= 0)
- {
- //
- // Invalid data in the line offset table mean that
- // the file is probably incomplete (the table is
- // the last thing written to the file). Either
- // some process is still busy writing the file,
- // or writing the file was aborted.
- //
- // We should still be able to read the existing
- // parts of the file. In order to do this, we
- // have to make a sequential scan over the scan
- // line data to reconstruct the line offset table.
- //
-
- complete = false;
- reconstructLineOffsets (is, lineOrder, lineOffsets);
- break;
- }
+ if (lineOffsets[i] <= 0)
+ {
+ //
+ // Invalid data in the line offset table mean that
+ // the file is probably incomplete (the table is
+ // the last thing written to the file). Either
+ // some process is still busy writing the file,
+ // or writing the file was aborted.
+ //
+ // We should still be able to read the existing
+ // parts of the file. In order to do this, we
+ // have to make a sequential scan over the scan
+ // line data to reconstruct the line offset table.
+ //
+
+ complete = false;
+ reconstructLineOffsets (is, lineOrder, lineOffsets);
+ break;
+ }
}
}
void
-readPixelData (ScanLineInputFile::Data *ifd,
- int minY,
- char *&buffer,
- int &dataSize)
+readPixelData (InputStreamMutex *streamData,
+ ScanLineInputFile::Data *ifd,
+ int minY,
+ char *&buffer,
+ int &dataSize)
{
//
// Read a single line buffer from the input file.
// array (hence buffer needs to be a reference to a char *).
//
- Int64 lineOffset =
- ifd->lineOffsets[(minY - ifd->minY) / ifd->linesInBuffer];
+ int lineBufferNumber = (minY - ifd->minY) / ifd->linesInBuffer;
+ if (lineBufferNumber < 0 || lineBufferNumber >= int(ifd->lineOffsets.size()))
+ THROW (IEX_NAMESPACE::InputExc, "Invalid scan line " << minY << " requested or missing.");
+
+ Int64 lineOffset = ifd->lineOffsets[lineBufferNumber];
if (lineOffset == 0)
- THROW (Iex::InputExc, "Scan line " << minY << " is missing.");
+ THROW (IEX_NAMESPACE::InputExc, "Scan line " << minY << " is missing.");
//
// Seek to the start of the scan line in the file,
// if necessary.
//
- if (ifd->nextLineBufferMinY != minY)
- ifd->is->seekg (lineOffset);
+ if ( !isMultiPart(ifd->version) )
+ {
+ if (ifd->nextLineBufferMinY != minY)
+ streamData->is->seekg (lineOffset);
+ }
+ else
+ {
+ //
+ // In a multi-part file, the file pointer may have been moved by
+ // other parts, so we have to ask tellg() where we are.
+ //
+ if (streamData->is->tellg() != ifd->lineOffsets[lineBufferNumber])
+ streamData->is->seekg (lineOffset);
+ }
//
// Read the data block's header.
int yInFile;
- Xdr::read <StreamIO> (*ifd->is, yInFile);
- Xdr::read <StreamIO> (*ifd->is, dataSize);
+ //
+ // Read the part number when we are dealing with a multi-part file.
+ //
+ if (isMultiPart(ifd->version))
+ {
+ int partNumber;
+ OPENEXR_IMF_INTERNAL_NAMESPACE::Xdr::read <OPENEXR_IMF_INTERNAL_NAMESPACE::StreamIO> (*streamData->is, partNumber);
+ if (partNumber != ifd->partNumber)
+ {
+ THROW (IEX_NAMESPACE::ArgExc, "Unexpected part number " << partNumber
+ << ", should be " << ifd->partNumber << ".");
+ }
+ }
+ OPENEXR_IMF_INTERNAL_NAMESPACE::Xdr::read <OPENEXR_IMF_INTERNAL_NAMESPACE::StreamIO> (*streamData->is, yInFile);
+ OPENEXR_IMF_INTERNAL_NAMESPACE::Xdr::read <OPENEXR_IMF_INTERNAL_NAMESPACE::StreamIO> (*streamData->is, dataSize);
+
if (yInFile != minY)
- throw Iex::InputExc ("Unexpected data block y coordinate.");
+ throw IEX_NAMESPACE::InputExc ("Unexpected data block y coordinate.");
if (dataSize > (int) ifd->lineBufferSize)
- throw Iex::InputExc ("Unexpected data block length.");
+ throw IEX_NAMESPACE::InputExc ("Unexpected data block length.");
//
// Read the pixel data.
//
- if (ifd->is->isMemoryMapped ())
- buffer = ifd->is->readMemoryMapped (dataSize);
+ if (streamData->is->isMemoryMapped ())
+ buffer = streamData->is->readMemoryMapped (dataSize);
else
- ifd->is->read (buffer, dataSize);
+ streamData->is->read (buffer, dataSize);
//
// Keep track of which scan line is the next one in
//
if (ifd->lineOrder == INCREASING_Y)
- ifd->nextLineBufferMinY = minY + ifd->linesInBuffer;
+ ifd->nextLineBufferMinY = minY + ifd->linesInBuffer;
else
- ifd->nextLineBufferMinY = minY - ifd->linesInBuffer;
+ ifd->nextLineBufferMinY = minY - ifd->linesInBuffer;
}
+
//
// A LineBufferTask encapsulates the task uncompressing a set of
LineBufferTask (TaskGroup *group,
ScanLineInputFile::Data *ifd,
- LineBuffer *lineBuffer,
+ LineBuffer *lineBuffer,
int scanLineMin,
- int scanLineMax);
+ int scanLineMax,
+ OptimizationMode optimizationMode);
virtual ~LineBufferTask ();
LineBuffer * _lineBuffer;
int _scanLineMin;
int _scanLineMax;
+ OptimizationMode _optimizationMode;
};
ScanLineInputFile::Data *ifd,
LineBuffer *lineBuffer,
int scanLineMin,
- int scanLineMax)
+ int scanLineMax,OptimizationMode optimizationMode)
:
Task (group),
_ifd (ifd),
_lineBuffer (lineBuffer),
_scanLineMin (scanLineMin),
- _scanLineMax (scanLineMax)
+ _scanLineMax (scanLineMax),
+ _optimizationMode(optimizationMode)
{
// empty
}
//
// Uncompress the data, if necessary
//
-
+
if (_lineBuffer->uncompressedData == 0)
{
int uncompressedSize = 0;
int maxY = min (_lineBuffer->maxY, _ifd->maxY);
-
+
for (int i = _lineBuffer->minY - _ifd->minY;
i <= maxY - _ifd->minY;
- ++i)
- {
+ ++i)
+ {
uncompressedSize += (int) _ifd->bytesPerLine[i];
- }
-
+ }
+
if (_lineBuffer->compressor &&
_lineBuffer->dataSize < uncompressedSize)
{
_lineBuffer->format = _lineBuffer->compressor->format();
_lineBuffer->dataSize = _lineBuffer->compressor->uncompress
- (_lineBuffer->buffer, _lineBuffer->dataSize,
- _lineBuffer->minY, _lineBuffer->uncompressedData);
+ (_lineBuffer->buffer,
+ _lineBuffer->dataSize,
+ _lineBuffer->minY,
+ _lineBuffer->uncompressedData);
}
else
{
// If the line is uncompressed, it's in XDR format,
// regardless of the compressor's output format.
//
-
+
_lineBuffer->format = Compressor::XDR;
_lineBuffer->uncompressedData = _lineBuffer->buffer;
}
}
-
+
int yStart, yStop, dy;
if (_ifd->lineOrder == INCREASING_Y)
yStop = _scanLineMin - 1;
dy = -1;
}
-
+
for (int y = yStart; y != yStop; y += dy)
{
//
// from the machine-independent representation, and
// store the result in the frame buffer.
//
-
+
const char *readPtr = _lineBuffer->uncompressedData +
_ifd->offsetInLineBuffer[y - _ifd->minY];
-
+
//
// Iterate over all image channels.
//
-
+
for (unsigned int i = 0; i < _ifd->slices.size(); ++i)
{
//
// Test if scan line y of this channel contains any data
- // (the scan line contains data only if y % ySampling == 0).
+ // (the scan line contains data only if y % ySampling == 0).
//
-
+
const InSliceInfo &slice = _ifd->slices[i];
-
+
if (modp (y, slice.ySampling) != 0)
continue;
-
+
//
// Find the x coordinates of the leftmost and rightmost
// sampled pixels (i.e. pixels within the data window
// for which x % xSampling == 0).
//
-
+
int dMinX = divp (_ifd->minX, slice.xSampling);
int dMaxX = divp (_ifd->maxX, slice.xSampling);
-
+
//
- // Fill the frame buffer with pixel data.
+ // Fill the frame buffer with pixel data.
//
-
+
if (slice.skip)
{
//
// The file contains data for this channel, but
// the frame buffer contains no slice for this channel.
//
-
+
skipChannel (readPtr, slice.typeInFile, dMaxX - dMinX + 1);
}
else
//
// The frame buffer contains a slice for this channel.
//
-
+
char *linePtr = slice.base +
divp (y, slice.ySampling) *
slice.yStride;
-
+
char *writePtr = linePtr + dMinX * slice.xStride;
char *endPtr = linePtr + dMaxX * slice.xStride;
-
+
copyIntoFrameBuffer (readPtr, writePtr, endPtr,
slice.xStride, slice.fill,
slice.fillValue, _lineBuffer->format,
}
-LineBufferTask *
-newLineBufferTask
+#ifdef IMF_HAVE_SSE2
+//
+// IIF format is more restricted than a perfectly generic one,
+// so it is possible to perform some optimizations.
+//
+class LineBufferTaskIIF : public Task
+{
+ public:
+
+ LineBufferTaskIIF (TaskGroup *group,
+ ScanLineInputFile::Data *ifd,
+ LineBuffer *lineBuffer,
+ int scanLineMin,
+ int scanLineMax,
+ OptimizationMode optimizationMode);
+
+ virtual ~LineBufferTaskIIF ();
+
+ virtual void execute ();
+
+ template<typename TYPE>
+ void getWritePointer (int y,
+ unsigned short*& pOutWritePointerRight,
+ size_t& outPixelsToCopySSE,
+ size_t& outPixelsToCopyNormal,int bank=0) const;
+
+ template<typename TYPE>
+ void getWritePointerStereo (int y,
+ unsigned short*& outWritePointerRight,
+ unsigned short*& outWritePointerLeft,
+ size_t& outPixelsToCopySSE,
+ size_t& outPixelsToCopyNormal) const;
+
+ private:
+
+ ScanLineInputFile::Data * _ifd;
+ LineBuffer * _lineBuffer;
+ int _scanLineMin;
+ int _scanLineMax;
+ OptimizationMode _optimizationMode;
+
+};
+
+LineBufferTaskIIF::LineBufferTaskIIF
(TaskGroup *group,
ScanLineInputFile::Data *ifd,
- int number,
+ LineBuffer *lineBuffer,
int scanLineMin,
- int scanLineMax)
+ int scanLineMax,
+ OptimizationMode optimizationMode
+ )
+ :
+ Task (group),
+ _ifd (ifd),
+ _lineBuffer (lineBuffer),
+ _scanLineMin (scanLineMin),
+ _scanLineMax (scanLineMax),
+ _optimizationMode (optimizationMode)
{
- //
- // Wait for a line buffer to become available, fill the line
- // buffer with raw data from the file if necessary, and create
- // a new LineBufferTask whose execute() method will uncompress
- // the contents of the buffer and copy the pixels into the
- // frame buffer.
- //
+ /*
+ //
+ // indicates the optimised path has been taken
+ //
+ static bool could_optimise=false;
+ if(could_optimise==false)
+ {
+ std::cerr << " optimised path\n";
+ could_optimise=true;
+ }
+ */
+}
+
+LineBufferTaskIIF::~LineBufferTaskIIF ()
+{
+ //
+ // Signal that the line buffer is now free
+ //
+
+ _lineBuffer->post ();
+}
+
+// Return 0 if we are to skip because of sampling
+// channelBank is 0 for the first group of channels, 1 for the second
+template<typename TYPE>
+void LineBufferTaskIIF::getWritePointer
+ (int y,
+ unsigned short*& outWritePointerRight,
+ size_t& outPixelsToCopySSE,
+ size_t& outPixelsToCopyNormal,
+ int channelBank
+ ) const
+{
+ // Channels are saved alphabetically, so the order is B G R.
+ // The last slice (R) will give us the location of our write pointer.
+ // The only slice that we support skipping is alpha, i.e. the first one.
+ // This does not impact the write pointer or the pixels to copy at all.
+
+ size_t nbSlicesInBank = _ifd->optimizationData.size();
+
+ int sizeOfSingleValue = sizeof(TYPE);
+
+ if(_ifd->optimizationData.size()>4)
+ {
+ // there are two banks - we only copy one at once
+ nbSlicesInBank/=2;
+ }
+
+
+ size_t firstChannel = 0;
+ if(channelBank==1)
+ {
+ firstChannel = _ifd->optimizationData.size()/2;
+ }
+
+ sliceOptimizationData& firstSlice = _ifd->optimizationData[firstChannel];
+
+ if (modp (y, firstSlice.ySampling) != 0)
+ {
+ outPixelsToCopySSE = 0;
+ outPixelsToCopyNormal = 0;
+ outWritePointerRight = 0;
+ }
+
+ const char* linePtr1 = firstSlice.base +
+ divp (y, firstSlice.ySampling) *
+ firstSlice.yStride;
+
+ int dMinX1 = divp (_ifd->minX, firstSlice.xSampling);
+ int dMaxX1 = divp (_ifd->maxX, firstSlice.xSampling);
+
+ // Construct the writePtr so that we start writing at
+ // linePtr + Min offset in the line.
+ outWritePointerRight = (unsigned short*)(linePtr1 +
+ dMinX1 * firstSlice.xStride );
+
+ size_t bytesToCopy = ((linePtr1 + dMaxX1 * firstSlice.xStride ) -
+ (linePtr1 + dMinX1 * firstSlice.xStride )) + 2;
+ size_t shortsToCopy = bytesToCopy / sizeOfSingleValue;
+ size_t pixelsToCopy = (shortsToCopy / nbSlicesInBank ) + 1;
+
+ // We only support writing to SSE if we have no pixels to copy normally
+ outPixelsToCopySSE = pixelsToCopy / 8;
+ outPixelsToCopyNormal = pixelsToCopy % 8;
+
+}
- LineBuffer *lineBuffer = ifd->getLineBuffer (number);
- try
- {
- lineBuffer->wait ();
+template<typename TYPE>
+void LineBufferTaskIIF::getWritePointerStereo
+ (int y,
+ unsigned short*& outWritePointerRight,
+ unsigned short*& outWritePointerLeft,
+ size_t& outPixelsToCopySSE,
+ size_t& outPixelsToCopyNormal) const
+{
+ getWritePointer<TYPE>(y,outWritePointerRight,outPixelsToCopySSE,outPixelsToCopyNormal,0);
+
+
+ if(outWritePointerRight)
+ {
+ getWritePointer<TYPE>(y,outWritePointerLeft,outPixelsToCopySSE,outPixelsToCopyNormal,1);
+ }
+
+}
- if (lineBuffer->number != number)
+void
+LineBufferTaskIIF::execute()
+{
+ try
{
- lineBuffer->minY = ifd->minY + number * ifd->linesInBuffer;
- lineBuffer->maxY = lineBuffer->minY + ifd->linesInBuffer - 1;
-
- lineBuffer->number = number;
- lineBuffer->uncompressedData = 0;
-
- readPixelData (ifd, lineBuffer->minY,
- lineBuffer->buffer,
- lineBuffer->dataSize);
- }
+ //
+ // Uncompress the data, if necessary
+ //
+
+ if (_lineBuffer->uncompressedData == 0)
+ {
+ int uncompressedSize = 0;
+ int maxY = min (_lineBuffer->maxY, _ifd->maxY);
+
+ for (int i = _lineBuffer->minY - _ifd->minY;
+ i <= maxY - _ifd->minY;
+ ++i)
+ {
+ uncompressedSize += (int) _ifd->bytesPerLine[i];
+ }
+
+ if (_lineBuffer->compressor &&
+ _lineBuffer->dataSize < uncompressedSize)
+ {
+ _lineBuffer->format = _lineBuffer->compressor->format();
+
+ _lineBuffer->dataSize =
+ _lineBuffer->compressor->uncompress (_lineBuffer->buffer,
+ _lineBuffer->dataSize,
+ _lineBuffer->minY,
+ _lineBuffer->uncompressedData);
+ }
+ else
+ {
+ //
+ // If the line is uncompressed, it's in XDR format,
+ // regardless of the compressor's output format.
+ //
+
+ _lineBuffer->format = Compressor::XDR;
+ _lineBuffer->uncompressedData = _lineBuffer->buffer;
+ }
+ }
+
+ int yStart, yStop, dy;
+
+ if (_ifd->lineOrder == INCREASING_Y)
+ {
+ yStart = _scanLineMin;
+ yStop = _scanLineMax + 1;
+ dy = 1;
+ }
+ else
+ {
+ yStart = _scanLineMax;
+ yStop = _scanLineMin - 1;
+ dy = -1;
+ }
+
+ for (int y = yStart; y != yStop; y += dy)
+ {
+ if (modp (y, _optimizationMode._ySampling) != 0)
+ continue;
+
+ //
+ // Convert one scan line's worth of pixel data back
+ // from the machine-independent representation, and
+ // store the result in the frame buffer.
+ //
+
+ // Set the readPtr to read at the start of uncompressedData
+ // but with an offet based on calculated array.
+ // _ifd->offsetInLineBuffer contains offsets based on which
+ // line we are currently processing.
+ // Stride will be taken into consideration later.
+
+
+ const char* readPtr = _lineBuffer->uncompressedData +
+ _ifd->offsetInLineBuffer[y - _ifd->minY];
+
+ size_t pixelsToCopySSE = 0;
+ size_t pixelsToCopyNormal = 0;
+
+ unsigned short* writePtrLeft = 0;
+ unsigned short* writePtrRight = 0;
+
+ size_t channels = _ifd->optimizationData.size();
+
+ if(channels>4)
+ {
+ getWritePointerStereo<half>(y, writePtrRight, writePtrLeft, pixelsToCopySSE, pixelsToCopyNormal);
+ }
+ else
+ {
+ getWritePointer<half>(y, writePtrRight, pixelsToCopySSE, pixelsToCopyNormal);
+ }
+
+ if (writePtrRight == 0 && pixelsToCopySSE == 0 && pixelsToCopyNormal == 0)
+ {
+ continue;
+ }
+
+
+ //
+ // support reading up to eight channels
+ //
+ unsigned short* readPointers[8];
+
+ for (size_t i = 0; i < channels ; ++i)
+ {
+ readPointers[i] = (unsigned short*)readPtr + (_ifd->optimizationData[i].offset * (pixelsToCopySSE * 8 + pixelsToCopyNormal));
+ }
+
+ //RGB only
+ if(channels==3 || channels == 6 )
+ {
+ optimizedWriteToRGB(readPointers[0], readPointers[1], readPointers[2], writePtrRight, pixelsToCopySSE, pixelsToCopyNormal);
+
+ //stereo RGB
+ if( channels == 6)
+ {
+ optimizedWriteToRGB(readPointers[3], readPointers[4], readPointers[5], writePtrLeft, pixelsToCopySSE, pixelsToCopyNormal);
+ }
+ //RGBA
+ }else if(channels==4 || channels==8)
+ {
+
+ if(_ifd->optimizationData[3].fill)
+ {
+ optimizedWriteToRGBAFillA(readPointers[0], readPointers[1], readPointers[2], _ifd->optimizationData[3].fillValue.bits() , writePtrRight, pixelsToCopySSE, pixelsToCopyNormal);
+ }else{
+ optimizedWriteToRGBA(readPointers[0], readPointers[1], readPointers[2], readPointers[3] , writePtrRight, pixelsToCopySSE, pixelsToCopyNormal);
+ }
+
+ //stereo RGBA
+ if( channels == 8)
+ {
+ if(_ifd->optimizationData[7].fill)
+ {
+ optimizedWriteToRGBAFillA(readPointers[4], readPointers[5], readPointers[6], _ifd->optimizationData[7].fillValue.bits() , writePtrLeft, pixelsToCopySSE, pixelsToCopyNormal);
+ }else{
+ optimizedWriteToRGBA(readPointers[4], readPointers[5], readPointers[6], readPointers[7] , writePtrLeft, pixelsToCopySSE, pixelsToCopyNormal);
+ }
+ }
+ }
+ else {
+ throw(IEX_NAMESPACE::LogicExc("IIF mode called with incorrect channel pattern"));
+ }
+
+ // If we are in NO_OPTIMIZATION mode, this class will never
+ // get instantiated, so no need to check for it and duplicate
+ // the code.
+ }
}
catch (std::exception &e)
{
- if (!lineBuffer->hasException)
- {
- lineBuffer->exception = e.what();
- lineBuffer->hasException = true;
- }
- lineBuffer->number = -1;
- lineBuffer->post();\
- throw;
+ if (!_lineBuffer->hasException)
+ {
+ _lineBuffer->exception = e.what();
+ _lineBuffer->hasException = true;
+ }
}
catch (...)
{
- //
- // Reading from the file caused an exception.
- // Signal that the line buffer is free, and
- // re-throw the exception.
- //
-
- lineBuffer->exception = "unrecognized exception";
- lineBuffer->hasException = true;
- lineBuffer->number = -1;
- lineBuffer->post();
- throw;
+ if (!_lineBuffer->hasException)
+ {
+ _lineBuffer->exception = "unrecognized exception";
+ _lineBuffer->hasException = true;
+ }
}
+}
+#endif
- scanLineMin = max (lineBuffer->minY, scanLineMin);
- scanLineMax = min (lineBuffer->maxY, scanLineMax);
- return new LineBufferTask (group, ifd, lineBuffer,
- scanLineMin, scanLineMax);
-}
+Task *
+newLineBufferTask (TaskGroup *group,
+ InputStreamMutex *streamData,
+ ScanLineInputFile::Data *ifd,
+ int number,
+ int scanLineMin,
+ int scanLineMax,
+ OptimizationMode optimizationMode)
+{
+ //
+ // Wait for a line buffer to become available, fill the line
+ // buffer with raw data from the file if necessary, and create
+ // a new LineBufferTask whose execute() method will uncompress
+ // the contents of the buffer and copy the pixels into the
+ // frame buffer.
+ //
+
+ LineBuffer *lineBuffer = ifd->getLineBuffer (number);
+
+ try
+ {
+ lineBuffer->wait ();
+
+ if (lineBuffer->number != number)
+ {
+ lineBuffer->minY = ifd->minY + number * ifd->linesInBuffer;
+ lineBuffer->maxY = lineBuffer->minY + ifd->linesInBuffer - 1;
+
+ lineBuffer->number = number;
+ lineBuffer->uncompressedData = 0;
+
+ readPixelData (streamData, ifd, lineBuffer->minY,
+ lineBuffer->buffer,
+ lineBuffer->dataSize);
+ }
+ }
+ catch (std::exception &e)
+ {
+ if (!lineBuffer->hasException)
+ {
+ lineBuffer->exception = e.what();
+ lineBuffer->hasException = true;
+ }
+ lineBuffer->number = -1;
+ lineBuffer->post();
+ throw;
+ }
+ catch (...)
+ {
+ //
+ // Reading from the file caused an exception.
+ // Signal that the line buffer is free, and
+ // re-throw the exception.
+ //
+
+ lineBuffer->exception = "unrecognized exception";
+ lineBuffer->hasException = true;
+ lineBuffer->number = -1;
+ lineBuffer->post();
+ throw;
+ }
+
+ scanLineMin = max (lineBuffer->minY, scanLineMin);
+ scanLineMax = min (lineBuffer->maxY, scanLineMax);
+
+
+ Task* retTask = 0;
+
+#ifdef IMF_HAVE_SSE2
+ if (optimizationMode._optimizable)
+ {
+
+ retTask = new LineBufferTaskIIF (group, ifd, lineBuffer,
+ scanLineMin, scanLineMax,
+ optimizationMode);
+
+ }
+ else
+#endif
+ {
+ retTask = new LineBufferTask (group, ifd, lineBuffer,
+ scanLineMin, scanLineMax,
+ optimizationMode);
+ }
+
+ return retTask;
+
+ }
+
+
+
} // namespace
-ScanLineInputFile::ScanLineInputFile
- (const Header &header,
- IStream *is,
- int numThreads)
-:
- _data (new Data (is, numThreads))
+void ScanLineInputFile::initialize(const Header& header)
{
try
{
- _data->header = header;
+ _data->header = header;
- _data->lineOrder = _data->header.lineOrder();
+ _data->lineOrder = _data->header.lineOrder();
- const Box2i &dataWindow = _data->header.dataWindow();
+ const Box2i &dataWindow = _data->header.dataWindow();
- _data->minX = dataWindow.min.x;
- _data->maxX = dataWindow.max.x;
- _data->minY = dataWindow.min.y;
- _data->maxY = dataWindow.max.y;
+ _data->minX = dataWindow.min.x;
+ _data->maxX = dataWindow.max.x;
+ _data->minY = dataWindow.min.y;
+ _data->maxY = dataWindow.max.y;
- size_t maxBytesPerLine = bytesPerLineTable (_data->header,
+ size_t maxBytesPerLine = bytesPerLineTable (_data->header,
_data->bytesPerLine);
for (size_t i = 0; i < _data->lineBuffers.size(); i++)
}
_data->linesInBuffer =
- numLinesInBuffer (_data->lineBuffers[0]->compressor);
+ numLinesInBuffer (_data->lineBuffers[0]->compressor);
_data->lineBufferSize = maxBytesPerLine * _data->linesInBuffer;
- if (!_data->is->isMemoryMapped())
+ if (!_streamData->is->isMemoryMapped())
+ {
for (size_t i = 0; i < _data->lineBuffers.size(); i++)
- _data->lineBuffers[i]->buffer = new char[_data->lineBufferSize];
-
- _data->nextLineBufferMinY = _data->minY - 1;
-
- offsetInLineBufferTable (_data->bytesPerLine,
- _data->linesInBuffer,
- _data->offsetInLineBuffer);
+ {
+ _data->lineBuffers[i]->buffer = (char *) EXRAllocAligned(_data->lineBufferSize*sizeof(char),16);
+ }
+ }
+ _data->nextLineBufferMinY = _data->minY - 1;
- int lineOffsetSize = (dataWindow.max.y - dataWindow.min.y +
- _data->linesInBuffer) / _data->linesInBuffer;
+ offsetInLineBufferTable (_data->bytesPerLine,
+ _data->linesInBuffer,
+ _data->offsetInLineBuffer);
- _data->lineOffsets.resize (lineOffsetSize);
+ int lineOffsetSize = (dataWindow.max.y - dataWindow.min.y +
+ _data->linesInBuffer) / _data->linesInBuffer;
- readLineOffsets (*_data->is,
- _data->lineOrder,
- _data->lineOffsets,
- _data->fileIsComplete);
+ _data->lineOffsets.resize (lineOffsetSize);
}
catch (...)
{
- delete _data;
- throw;
+ delete _data;
+ _data=NULL;
+ throw;
}
}
+ScanLineInputFile::ScanLineInputFile(InputPartData* part)
+{
+ if (part->header.type() != SCANLINEIMAGE)
+ throw IEX_NAMESPACE::ArgExc("Can't build a ScanLineInputFile from a type-mismatched part.");
+
+ _data = new Data(part->numThreads);
+ _streamData = part->mutex;
+ _data->memoryMapped = _streamData->is->isMemoryMapped();
+
+ _data->version = part->version;
+
+ initialize(part->header);
+
+ _data->lineOffsets = part->chunkOffsets;
+
+ _data->partNumber = part->partNumber;
+ //
+ // (TODO) change this code later.
+ // The completeness of the file should be detected in MultiPartInputFile.
+ //
+ _data->fileIsComplete = true;
+}
+
+
+ScanLineInputFile::ScanLineInputFile
+ (const Header &header,
+ OPENEXR_IMF_INTERNAL_NAMESPACE::IStream *is,
+ int numThreads)
+:
+ _data (new Data (numThreads)),
+ _streamData (new InputStreamMutex())
+{
+ _streamData->is = is;
+ _data->memoryMapped = is->isMemoryMapped();
+
+ initialize(header);
+
+ //
+ // (TODO) this is nasty - we need a better way of working out what type of file has been used.
+ // in any case I believe this constructor only gets used with single part files
+ // and 'version' currently only tracks multipart state, so setting to 0 (not multipart) works for us
+ //
+
+ _data->version=0;
+ readLineOffsets (*_streamData->is,
+ _data->lineOrder,
+ _data->lineOffsets,
+ _data->fileIsComplete);
+}
+
+
ScanLineInputFile::~ScanLineInputFile ()
{
- if (!_data->is->isMemoryMapped())
+ if (!_data->memoryMapped)
+ {
for (size_t i = 0; i < _data->lineBuffers.size(); i++)
- delete [] _data->lineBuffers[i]->buffer;
+ {
+ EXRFreeAligned(_data->lineBuffers[i]->buffer);
+ }
+ }
+
+
+ //
+ // ScanLineInputFile should never delete the stream,
+ // because it does not own the stream.
+ // We just delete the Mutex here.
+ //
+ if (_data->partNumber == -1)
+ delete _streamData;
delete _data;
}
const char *
ScanLineInputFile::fileName () const
{
- return _data->is->fileName();
+ return _streamData->is->fileName();
}
}
-void
-ScanLineInputFile::setFrameBuffer (const FrameBuffer &frameBuffer)
+namespace
{
- Lock lock (*_data);
-
+
+
+// returns the optimization state for the given arrangement of frame bufers
+// this assumes:
+// both the file and framebuffer are half float data
+// both the file and framebuffer have xSampling and ySampling=1
+// entries in optData are sorted into their interleave order (i.e. by base address)
+// These tests are done by SetFrameBuffer as it is building optData
+//
+OptimizationMode
+detectOptimizationMode (const vector<sliceOptimizationData>& optData)
+{
+ OptimizationMode w;
+
+ // need to be compiled with SSE optimisations: if not, just returns false
+#ifdef IMF_HAVE_SSE2
+
+
+ // only handle reading 3,4,6 or 8 channels
+ switch(optData.size())
+ {
+ case 3 : break;
+ case 4 : break;
+ case 6 : break;
+ case 8 : break;
+ default :
+ return w;
+ }
+
//
- // Check if the new frame buffer descriptor is
- // compatible with the image file header.
+ // the point at which data switches between the primary and secondary bank
//
+ size_t bankSize = optData.size()>4 ? optData.size()/2 : optData.size();
+
+ for(size_t i=0;i<optData.size();i++)
+ {
+ const sliceOptimizationData& data = optData[i];
+ // can't fill anything other than channel 3 or channel 7
+ if(data.fill)
+ {
+ if(i!=3 && i!=7)
+ {
+ return w;
+ }
+ }
+
+ // cannot have gaps in the channel layout, so the stride must be (number of channels written in the bank)*2
+ if(data.xStride !=bankSize*2)
+ {
+ return w;
+ }
+
+ // each bank of channels must be channel interleaved: each channel base pointer must be (previous channel+2)
+ // this also means channel sampling pattern must be consistent, as must yStride
+ if(i!=0 && i!=bankSize)
+ {
+ if(data.base!=optData[i-1].base+2)
+ {
+ return w;
+ }
+ }
+ if(i!=0)
+ {
+
+ if(data.yStride!=optData[i-1].yStride)
+ {
+ return w;
+ }
+ }
+ }
+
- const ChannelList &channels = _data->header.channels();
+ w._ySampling=optData[0].ySampling;
+ w._optimizable=true;
+
+#endif
+
+ return w;
+}
+
+
+} // Anonymous namespace
+
+void
+ScanLineInputFile::setFrameBuffer (const FrameBuffer &frameBuffer)
+{
+ Lock lock (*_streamData);
+
+
+ const ChannelList &channels = _data->header.channels();
for (FrameBuffer::ConstIterator j = frameBuffer.begin();
- j != frameBuffer.end();
- ++j)
+ j != frameBuffer.end();
+ ++j)
{
- ChannelList::ConstIterator i = channels.find (j.name());
-
- if (i == channels.end())
- continue;
-
- if (i.channel().xSampling != j.slice().xSampling ||
- i.channel().ySampling != j.slice().ySampling)
- THROW (Iex::ArgExc, "X and/or y subsampling factors "
- "of \"" << i.name() << "\" channel "
- "of input file \"" << fileName() << "\" are "
- "not compatible with the frame buffer's "
- "subsampling factors.");
+ ChannelList::ConstIterator i = channels.find (j.name());
+
+ if (i == channels.end())
+ continue;
+
+ if (i.channel().xSampling != j.slice().xSampling ||
+ i.channel().ySampling != j.slice().ySampling)
+ THROW (IEX_NAMESPACE::ArgExc, "X and/or y subsampling factors "
+ "of \"" << i.name() << "\" channel "
+ "of input file \"" << fileName() << "\" are "
+ "not compatible with the frame buffer's "
+ "subsampling factors.");
}
+ // optimization is possible if this is a little endian system
+ // and both inputs and outputs are half floats
+ //
+ bool optimizationPossible = true;
+
+ if (!GLOBAL_SYSTEM_LITTLE_ENDIAN)
+ {
+ optimizationPossible =false;
+ }
+
+ vector<sliceOptimizationData> optData;
+
+
//
// Initialize the slice table for readPixels().
//
vector<InSliceInfo> slices;
ChannelList::ConstIterator i = channels.begin();
-
+
+ // current offset of channel: pixel data starts at offset*width into the
+ // decompressed scanline buffer
+ size_t offset = 0;
+
for (FrameBuffer::ConstIterator j = frameBuffer.begin();
- j != frameBuffer.end();
- ++j)
- {
- while (i != channels.end() && strcmp (i.name(), j.name()) < 0)
- {
- //
- // Channel i is present in the file but not
- // in the frame buffer; data for channel i
- // will be skipped during readPixels().
- //
-
- slices.push_back (InSliceInfo (i.channel().type,
- i.channel().type,
- 0, // base
- 0, // xStride
- 0, // yStride
- i.channel().xSampling,
- i.channel().ySampling,
- false, // fill
- true, // skip
- 0.0)); // fillValue
- ++i;
- }
-
- bool fill = false;
-
- if (i == channels.end() || strcmp (i.name(), j.name()) > 0)
+ j != frameBuffer.end();
+ ++j)
{
- //
- // Channel i is present in the frame buffer, but not in the file.
- // In the frame buffer, slice j will be filled with a default value.
- //
-
- fill = true;
- }
-
- slices.push_back (InSliceInfo (j.slice().type,
- fill? j.slice().type:
- i.channel().type,
- j.slice().base,
- j.slice().xStride,
- j.slice().yStride,
- j.slice().xSampling,
- j.slice().ySampling,
- fill,
- false, // skip
- j.slice().fillValue));
-
- if (i != channels.end() && !fill)
- ++i;
+ while (i != channels.end() && strcmp (i.name(), j.name()) < 0)
+ {
+ //
+ // Channel i is present in the file but not
+ // in the frame buffer; data for channel i
+ // will be skipped during readPixels().
+ //
+
+ slices.push_back (InSliceInfo (i.channel().type,
+ i.channel().type,
+ 0, // base
+ 0, // xStride
+ 0, // yStride
+ i.channel().xSampling,
+ i.channel().ySampling,
+ false, // fill
+ true, // skip
+ 0.0)); // fillValue
+
+ switch(i.channel().type)
+ {
+ case OPENEXR_IMF_INTERNAL_NAMESPACE::HALF :
+ offset++;
+ break;
+ case OPENEXR_IMF_INTERNAL_NAMESPACE::FLOAT :
+ offset+=2;
+ break;
+ case OPENEXR_IMF_INTERNAL_NAMESPACE::UINT :
+ offset+=2;
+ break;
+ }
+ ++i;
+ }
+
+ bool fill = false;
+
+ if (i == channels.end() || strcmp (i.name(), j.name()) > 0)
+ {
+ //
+ // Channel i is present in the frame buffer, but not in the file.
+ // In the frame buffer, slice j will be filled with a default value.
+ //
+
+ fill = true;
+ }
+
+ slices.push_back (InSliceInfo (j.slice().type,
+ fill? j.slice().type:
+ i.channel().type,
+ j.slice().base,
+ j.slice().xStride,
+ j.slice().yStride,
+ j.slice().xSampling,
+ j.slice().ySampling,
+ fill,
+ false, // skip
+ j.slice().fillValue));
+
+ if(!fill && i.channel().type!=OPENEXR_IMF_INTERNAL_NAMESPACE::HALF)
+ {
+ optimizationPossible = false;
+ }
+
+ if(j.slice().type != OPENEXR_IMF_INTERNAL_NAMESPACE::HALF)
+ {
+ optimizationPossible = false;
+ }
+ if(j.slice().xSampling!=1 || j.slice().ySampling!=1)
+ {
+ optimizationPossible = false;
+ }
+
+
+ if(optimizationPossible)
+ {
+ sliceOptimizationData dat;
+ dat.base = j.slice().base;
+ dat.fill = fill;
+ dat.fillValue = j.slice().fillValue;
+ dat.offset = offset;
+ dat.xStride = j.slice().xStride;
+ dat.yStride = j.slice().yStride;
+ dat.xSampling = j.slice().xSampling;
+ dat.ySampling = j.slice().ySampling;
+ optData.push_back(dat);
+ }
+
+ if(!fill)
+ {
+ switch(i.channel().type)
+ {
+ case OPENEXR_IMF_INTERNAL_NAMESPACE::HALF :
+ offset++;
+ break;
+ case OPENEXR_IMF_INTERNAL_NAMESPACE::FLOAT :
+ offset+=2;
+ break;
+ case OPENEXR_IMF_INTERNAL_NAMESPACE::UINT :
+ offset+=2;
+ break;
+ }
+ }
+
+
+
+ if (i != channels.end() && !fill)
+ ++i;
}
+
+ if(optimizationPossible)
+ {
+ //
+ // check optimisibility
+ // based on channel ordering and fill channel positions
+ //
+ sort(optData.begin(),optData.end());
+ _data->optimizationMode = detectOptimizationMode(optData);
+ }
+
+ if(!optimizationPossible || _data->optimizationMode._optimizable==false)
+ {
+ optData = vector<sliceOptimizationData>();
+ _data->optimizationMode._optimizable=false;
+ }
+
//
// Store the new frame buffer.
//
_data->frameBuffer = frameBuffer;
_data->slices = slices;
+ _data->optimizationData = optData;
}
const FrameBuffer &
ScanLineInputFile::frameBuffer () const
{
- Lock lock (*_data);
+ Lock lock (*_streamData);
return _data->frameBuffer;
}
return _data->fileIsComplete;
}
+bool ScanLineInputFile::isOptimizationEnabled() const
+{
+ if (_data->slices.size() == 0)
+ throw IEX_NAMESPACE::ArgExc ("No frame buffer specified "
+ "as pixel data destination.");
+
+ return _data->optimizationMode._optimizable;
+}
-void
+
+void
ScanLineInputFile::readPixels (int scanLine1, int scanLine2)
{
try
{
- Lock lock (*_data);
+ Lock lock (*_streamData);
- if (_data->slices.size() == 0)
- throw Iex::ArgExc ("No frame buffer specified "
- "as pixel data destination.");
+ if (_data->slices.size() == 0)
+ throw IEX_NAMESPACE::ArgExc ("No frame buffer specified "
+ "as pixel data destination.");
- int scanLineMin = min (scanLine1, scanLine2);
- int scanLineMax = max (scanLine1, scanLine2);
+ int scanLineMin = min (scanLine1, scanLine2);
+ int scanLineMax = max (scanLine1, scanLine2);
- if (scanLineMin < _data->minY || scanLineMax > _data->maxY)
- throw Iex::ArgExc ("Tried to read scan line outside "
- "the image file's data window.");
+ if (scanLineMin < _data->minY || scanLineMax > _data->maxY)
+ throw IEX_NAMESPACE::ArgExc ("Tried to read scan line outside "
+ "the image file's data window.");
//
// We impose a numbering scheme on the lineBuffers where the first
//
// Create a task group for all line buffer tasks. When the
- // task group goes out of scope, the destructor waits until
- // all tasks are complete.
+ // task group goes out of scope, the destructor waits until
+ // all tasks are complete.
//
-
+
{
TaskGroup taskGroup;
-
+
//
// Add the line buffer tasks.
//
// The tasks will execute in the order that they are created
// because we lock the line buffers during construction and the
// constructors are called by the main thread. Hence, in order
- // for a successive task to execute the previous task which
- // used that line buffer must have completed already.
+ // for a successive task to execute the previous task which
+ // used that line buffer must have completed already.
//
-
+
for (int l = start; l != stop; l += dl)
{
ThreadPool::addGlobalTask (newLineBufferTask (&taskGroup,
+ _streamData,
_data, l,
scanLineMin,
- scanLineMax));
+ scanLineMax,
+ _data->optimizationMode));
}
-
- //
+
+ //
// finish all tasks
- //
+ //
}
-
- //
- // Exeption handling:
- //
- // LineBufferTask::execute() may have encountered exceptions, but
- // those exceptions occurred in another thread, not in the thread
- // that is executing this call to ScanLineInputFile::readPixels().
- // LineBufferTask::execute() has caught all exceptions and stored
- // the exceptions' what() strings in the line buffers.
- // Now we check if any line buffer contains a stored exception; if
- // this is the case then we re-throw the exception in this thread.
- // (It is possible that multiple line buffers contain stored
- // exceptions. We re-throw the first exception we find and
- // ignore all others.)
- //
-
- const string *exception = 0;
-
- for (int i = 0; i < _data->lineBuffers.size(); ++i)
- {
+
+ //
+ // Exeption handling:
+ //
+ // LineBufferTask::execute() may have encountered exceptions, but
+ // those exceptions occurred in another thread, not in the thread
+ // that is executing this call to ScanLineInputFile::readPixels().
+ // LineBufferTask::execute() has caught all exceptions and stored
+ // the exceptions' what() strings in the line buffers.
+ // Now we check if any line buffer contains a stored exception; if
+ // this is the case then we re-throw the exception in this thread.
+ // (It is possible that multiple line buffers contain stored
+ // exceptions. We re-throw the first exception we find and
+ // ignore all others.)
+ //
+
+ const string *exception = 0;
+
+ for (size_t i = 0; i < _data->lineBuffers.size(); ++i)
+ {
LineBuffer *lineBuffer = _data->lineBuffers[i];
- if (lineBuffer->hasException && !exception)
- exception = &lineBuffer->exception;
+ if (lineBuffer->hasException && !exception)
+ exception = &lineBuffer->exception;
- lineBuffer->hasException = false;
- }
+ lineBuffer->hasException = false;
+ }
- if (exception)
- throw Iex::IoExc (*exception);
+ if (exception)
+ throw IEX_NAMESPACE::IoExc (*exception);
}
- catch (Iex::BaseExc &e)
+ catch (IEX_NAMESPACE::BaseExc &e)
{
- REPLACE_EXC (e, "Error reading pixel data from image "
- "file \"" << fileName() << "\". " << e);
- throw;
+ REPLACE_EXC (e, "Error reading pixel data from image "
+ "file \"" << fileName() << "\". " << e.what());
+ throw;
}
}
-void
+void
ScanLineInputFile::readPixels (int scanLine)
{
readPixels (scanLine, scanLine);
void
ScanLineInputFile::rawPixelData (int firstScanLine,
- const char *&pixelData,
- int &pixelDataSize)
+ const char *&pixelData,
+ int &pixelDataSize)
{
try
{
- Lock lock (*_data);
+ Lock lock (*_streamData);
- if (firstScanLine < _data->minY || firstScanLine > _data->maxY)
- {
- throw Iex::ArgExc ("Tried to read scan line outside "
- "the image file's data window.");
- }
+ if (firstScanLine < _data->minY || firstScanLine > _data->maxY)
+ {
+ throw IEX_NAMESPACE::ArgExc ("Tried to read scan line outside "
+ "the image file's data window.");
+ }
int minY = lineBufferMinY
- (firstScanLine, _data->minY, _data->linesInBuffer);
+ (firstScanLine, _data->minY, _data->linesInBuffer);
- readPixelData
- (_data, minY, _data->lineBuffers[0]->buffer, pixelDataSize);
+ readPixelData
+ (_streamData, _data, minY, _data->lineBuffers[0]->buffer, pixelDataSize);
- pixelData = _data->lineBuffers[0]->buffer;
+ pixelData = _data->lineBuffers[0]->buffer;
+ }
+ catch (IEX_NAMESPACE::BaseExc &e)
+ {
+ REPLACE_EXC (e, "Error reading pixel data from image "
+ "file \"" << fileName() << "\". " << e.what());
+ throw;
}
- catch (Iex::BaseExc &e)
+}
+
+
+void ScanLineInputFile::rawPixelDataToBuffer(int scanLine,
+ char *pixelData,
+ int &pixelDataSize) const
+{
+ if (_data->memoryMapped) {
+ throw IEX_NAMESPACE::ArgExc ("Reading raw pixel data to a buffer "
+ "is not supported for memory mapped "
+ "streams." );
+ }
+
+ try
+ {
+ Lock lock (*_streamData);
+
+ if (scanLine < _data->minY || scanLine > _data->maxY)
{
+ throw IEX_NAMESPACE::ArgExc ("Tried to read scan line outside "
+ "the image file's data window.");
+ }
+
+ readPixelData
+ (_streamData, _data, scanLine, pixelData, pixelDataSize);
+
+ }
+ catch (IEX_NAMESPACE::BaseExc &e)
+ {
REPLACE_EXC (e, "Error reading pixel data from image "
- "file \"" << fileName() << "\". " << e);
+ "file \"" << fileName() << "\". " << e.what());
throw;
- }
+ }
}
-} // namespace Imf
+
+OPENEXR_IMF_INTERNAL_NAMESPACE_SOURCE_EXIT
//
// Copyright (c) 2004, Industrial Light & Magic, a division of Lucas
// Digital Ltd. LLC
-//
+//
// All rights reserved.
-//
+//
// Redistribution and use in source and binary forms, with or without
// modification, are permitted provided that the following conditions are
// met:
// distribution.
// * Neither the name of Industrial Light & Magic nor the names of
// its contributors may be used to endorse or promote products derived
-// from this software without specific prior written permission.
-//
+// from this software without specific prior written permission.
+//
// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
//
//-----------------------------------------------------------------------------
-#include <ImfHeader.h>
-#include <ImfFrameBuffer.h>
-#include <ImfThreading.h>
+#include "ImfHeader.h"
+#include "ImfFrameBuffer.h"
+#include "ImfThreading.h"
+#include "ImfInputStreamMutex.h"
+#include "ImfInputPartData.h"
+#include "ImfGenericInputFile.h"
+#include "ImfExport.h"
+#include "ImfNamespace.h"
-namespace Imf {
+OPENEXR_IMF_INTERNAL_NAMESPACE_HEADER_ENTER
-class ScanLineInputFile
+class ScanLineInputFile : public GenericInputFile
{
public:
// Constructor
//------------
- ScanLineInputFile (const Header &header, IStream *is,
+ IMF_EXPORT
+ ScanLineInputFile (const Header &header, OPENEXR_IMF_INTERNAL_NAMESPACE::IStream *is,
int numThreads = globalThreadCount());
// structures, but does not close the file.
//-----------------------------------------
+ IMF_EXPORT
virtual ~ScanLineInputFile ();
// Access to the file name
//------------------------
+ IMF_EXPORT
const char * fileName () const;
// Access to the file header
//--------------------------
+ IMF_EXPORT
const Header & header () const;
// Access to the file format version
//----------------------------------
+ IMF_EXPORT
int version () const;
// to readPixels().
//-----------------------------------------------------------
+ IMF_EXPORT
void setFrameBuffer (const FrameBuffer &frameBuffer);
// Access to the current frame buffer
//-----------------------------------
+ IMF_EXPORT
const FrameBuffer & frameBuffer () const;
// writing may have been aborted prematurely.)
//---------------------------------------------------------------
+ IMF_EXPORT
bool isComplete () const;
+
+
+ //---------------------------------------------------------------
+ // Check if SSE optimisation is enabled
+ //
+ // Call after setFrameBuffer() to query whether optimised file decoding
+ // is available - decode times will be faster if returns true
+ //
+ // Optimisation depends on the framebuffer channels and channel types
+ // as well as the file/part channels and channel types, as well as
+ // whether SSE2 instruction support was detected at compile time
+ //
+ // Calling before setFrameBuffer will throw an exception
+ //
+ //---------------------------------------------------------------
+
+ IMF_EXPORT
+ bool isOptimizationEnabled () const;
+
+
+
//---------------------------------------------------------------
// Read pixel data:
//
//---------------------------------------------------------------
+ IMF_EXPORT
void readPixels (int scanLine1, int scanLine2);
+ IMF_EXPORT
void readPixels (int scanLine);
// used to implement OutputFile::copyPixels()).
//----------------------------------------------
+ IMF_EXPORT
void rawPixelData (int firstScanLine,
- const char *&pixelData,
- int &pixelDataSize);
+ const char *&pixelData,
+ int &pixelDataSize);
+
+ //----------------------------------------------
+ // Read a scanline's worth of raw pixel data
+ // from the file, without uncompressing it, and
+ // store in an external buffer, pixelData.
+ // pixelData should be pre-allocated with space
+ // for pixelDataSize chars.
+ //
+ // This function can be used to separate the
+ // reading of a raw scan line from the
+ // decompression of that scan line, for
+ // example to allow multiple scan lines to be
+ // decompressed in parallel by an application's
+ // own threads, where it is not convenient to
+ // use the threading within the library.
+ //----------------------------------------------
+
+ IMF_EXPORT
+ void rawPixelDataToBuffer(int scanLine,
+ char *pixelData,
+ int &pixelDataSize) const;
+
+
struct Data;
private:
Data * _data;
+
+ InputStreamMutex* _streamData;
+
+ ScanLineInputFile (InputPartData* part);
+
+ void initialize(const Header& header);
+
+ friend class MultiPartInputFile;
+ friend class InputFile;
};
-} // namespace Imf
+OPENEXR_IMF_INTERNAL_NAMESPACE_HEADER_EXIT
+
+
+
+
#endif
--- /dev/null
+///////////////////////////////////////////////////////////////////////////
+//
+// Copyright (c) 2012, Autodesk, Inc.
+//
+// All rights reserved.
+//
+// Implementation of IIF-specific file format and speed optimizations
+// provided by Innobec Technologies inc on behalf of Autodesk.
+//
+// Redistribution and use in source and binary forms, with or without
+// modification, are permitted provided that the following conditions are
+// met:
+// * Redistributions of source code must retain the above copyright
+// notice, this list of conditions and the following disclaimer.
+// * Redistributions in binary form must reproduce the above
+// copyright notice, this list of conditions and the following disclaimer
+// in the documentation and/or other materials provided with the
+// distribution.
+// * Neither the name of Industrial Light & Magic nor the names of
+// its contributors may be used to endorse or promote products derived
+// from this software without specific prior written permission.
+//
+// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+//
+///////////////////////////////////////////////////////////////////////////
+
+#ifndef INCLUDED_IMF_SIMD_H
+#define INCLUDED_IMF_SIMD_H
+
+//
+// Compile time SSE detection:
+// IMF_HAVE_SSE2 - Defined if it's safe to compile SSE2 optimizations
+// IMF_HAVE_SSE4_1 - Defined if it's safe to compile SSE4.1 optimizations
+//
+
+
+// GCC and Visual Studio SSE2 compiler flags
+#if defined __SSE2__ || (_MSC_VER >= 1300 && !_M_CEE_PURE)
+ #define IMF_HAVE_SSE2 1
+#endif
+
+#if defined __SSE4_1__
+ #define IMF_HAVE_SSE4_1 1
+#endif
+
+extern "C"
+{
+#ifdef IMF_HAVE_SSE2
+ #include <emmintrin.h>
+ #include <mmintrin.h>
+#endif
+
+#ifdef IMF_HAVE_SSE4_1
+ #include <smmintrin.h>
+#endif
+}
+
+#endif
//
// Copyright (c) 2003, Industrial Light & Magic, a division of Lucas
// Digital Ltd. LLC
-//
+//
// All rights reserved.
-//
+//
// Redistribution and use in source and binary forms, with or without
// modification, are permitted provided that the following conditions are
// met:
// distribution.
// * Neither the name of Industrial Light & Magic nor the names of
// its contributors may be used to endorse or promote products derived
-// from this software without specific prior written permission.
-//
+// from this software without specific prior written permission.
+//
// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
#define IMF_STRING(name) #name
#define IMF_STD_ATTRIBUTE_IMP(name,suffix,type) \
- \
+ \
void \
add##suffix (Header &header, const type &value) \
{ \
- header.insert (IMF_STRING (name), TypedAttribute<type> (value)); \
+ header.insert (IMF_STRING (name), TypedAttribute<type> (value)); \
} \
- \
+ \
bool \
has##suffix (const Header &header) \
{ \
- return header.findTypedAttribute <TypedAttribute <type> > \
- (IMF_STRING (name)) != 0; \
+ return header.findTypedAttribute <TypedAttribute <type> > \
+ (IMF_STRING (name)) != 0; \
} \
- \
+ \
const TypedAttribute<type> & \
name##Attribute (const Header &header) \
{ \
- return header.typedAttribute <TypedAttribute <type> > \
- (IMF_STRING (name)); \
+ return header.typedAttribute <TypedAttribute <type> > \
+ (IMF_STRING (name)); \
} \
- \
+ \
TypedAttribute<type> & \
name##Attribute (Header &header) \
{ \
- return header.typedAttribute <TypedAttribute <type> > \
- (IMF_STRING (name)); \
+ return header.typedAttribute <TypedAttribute <type> > \
+ (IMF_STRING (name)); \
} \
- \
+ \
const type & \
name (const Header &header) \
{ \
- return name##Attribute(header).value(); \
+ return name##Attribute(header).value(); \
} \
- \
+ \
type & \
name (Header &header) \
{ \
- return name##Attribute(header).value(); \
+ return name##Attribute(header).value(); \
}
+#include "ImfNamespace.h"
-namespace Imf {
+using namespace IMATH_NAMESPACE;
+using namespace std;
+OPENEXR_IMF_INTERNAL_NAMESPACE_SOURCE_ENTER
+
IMF_STD_ATTRIBUTE_IMP (chromaticities, Chromaticities, Chromaticities)
IMF_STD_ATTRIBUTE_IMP (whiteLuminance, WhiteLuminance, float)
-IMF_STD_ATTRIBUTE_IMP (adoptedNeutral, AdoptedNeutral, Imath::V2f)
-IMF_STD_ATTRIBUTE_IMP (renderingTransform, RenderingTransform, std::string)
-IMF_STD_ATTRIBUTE_IMP (lookModTransform, LookModTransform, std::string)
+IMF_STD_ATTRIBUTE_IMP (adoptedNeutral, AdoptedNeutral, V2f)
+IMF_STD_ATTRIBUTE_IMP (renderingTransform, RenderingTransform, string)
+IMF_STD_ATTRIBUTE_IMP (lookModTransform, LookModTransform, string)
IMF_STD_ATTRIBUTE_IMP (xDensity, XDensity, float)
-IMF_STD_ATTRIBUTE_IMP (owner, Owner, std::string)
-IMF_STD_ATTRIBUTE_IMP (comments, Comments, std::string)
-IMF_STD_ATTRIBUTE_IMP (capDate, CapDate, std::string)
+IMF_STD_ATTRIBUTE_IMP (owner, Owner, string)
+IMF_STD_ATTRIBUTE_IMP (comments, Comments, string)
+IMF_STD_ATTRIBUTE_IMP (capDate, CapDate, string)
IMF_STD_ATTRIBUTE_IMP (utcOffset, UtcOffset, float)
IMF_STD_ATTRIBUTE_IMP (longitude, Longitude, float)
IMF_STD_ATTRIBUTE_IMP (latitude, Latitude, float)
IMF_STD_ATTRIBUTE_IMP (envmap, Envmap, Envmap)
IMF_STD_ATTRIBUTE_IMP (keyCode, KeyCode, KeyCode)
IMF_STD_ATTRIBUTE_IMP (timeCode, TimeCode, TimeCode)
-IMF_STD_ATTRIBUTE_IMP (wrapmodes, Wrapmodes, std::string)
+IMF_STD_ATTRIBUTE_IMP (wrapmodes, Wrapmodes, string)
IMF_STD_ATTRIBUTE_IMP (framesPerSecond, FramesPerSecond, Rational)
IMF_STD_ATTRIBUTE_IMP (multiView, MultiView, StringVector)
-IMF_STD_ATTRIBUTE_IMP (worldToCamera, WorldToCamera, Imath::M44f)
-IMF_STD_ATTRIBUTE_IMP (worldToNDC, WorldToNDC, Imath::M44f)
+IMF_STD_ATTRIBUTE_IMP (worldToCamera, WorldToCamera, M44f)
+IMF_STD_ATTRIBUTE_IMP (worldToNDC, WorldToNDC, M44f)
+IMF_STD_ATTRIBUTE_IMP (deepImageState, DeepImageState, DeepImageState)
+IMF_STD_ATTRIBUTE_IMP (originalDataWindow, OriginalDataWindow, Box2i)
+IMF_STD_ATTRIBUTE_IMP (dwaCompressionLevel, DwaCompressionLevel, float)
-} // namespace Imf
+OPENEXR_IMF_INTERNAL_NAMESPACE_SOURCE_EXIT
//
// Copyright (c) 2004, Industrial Light & Magic, a division of Lucas
// Digital Ltd. LLC
-//
+//
// All rights reserved.
-//
+//
// Redistribution and use in source and binary forms, with or without
// modification, are permitted provided that the following conditions are
// met:
// distribution.
// * Neither the name of Industrial Light & Magic nor the names of
// its contributors may be used to endorse or promote products derived
-// from this software without specific prior written permission.
-//
+// from this software without specific prior written permission.
+//
// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
//
//-----------------------------------------------------------------------------
-#include <ImfHeader.h>
-#include <ImfChromaticitiesAttribute.h>
-#include <ImfEnvmapAttribute.h>
-#include <ImfFloatAttribute.h>
-#include <ImfKeyCodeAttribute.h>
-#include <ImfMatrixAttribute.h>
-#include <ImfRationalAttribute.h>
-#include <ImfStringAttribute.h>
-#include <ImfStringVectorAttribute.h>
-#include <ImfTimeCodeAttribute.h>
-#include <ImfVecAttribute.h>
-
-#define IMF_STD_ATTRIBUTE_DEF(name,suffix,type) \
- \
- void add##suffix (Header &header, const type &v); \
- bool has##suffix (const Header &header); \
- const TypedAttribute<type> & name##Attribute (const Header &header); \
- TypedAttribute<type> & name##Attribute (Header &header); \
- const type & name (const Header &header); \
- type & name (Header &header);
-
-
-namespace Imf {
+#include "ImfHeader.h"
+#include "ImfBoxAttribute.h"
+#include "ImfChromaticitiesAttribute.h"
+#include "ImfEnvmapAttribute.h"
+#include "ImfDeepImageStateAttribute.h"
+#include "ImfFloatAttribute.h"
+#include "ImfKeyCodeAttribute.h"
+#include "ImfMatrixAttribute.h"
+#include "ImfRationalAttribute.h"
+#include "ImfStringAttribute.h"
+#include "ImfStringVectorAttribute.h"
+#include "ImfTimeCodeAttribute.h"
+#include "ImfVecAttribute.h"
+#include "ImfNamespace.h"
+#include "ImfExport.h"
+
+#define IMF_STD_ATTRIBUTE_DEF(name,suffix,object) \
+ \
+ OPENEXR_IMF_INTERNAL_NAMESPACE_HEADER_ENTER \
+ IMF_EXPORT void add##suffix (Header &header, const object &v); \
+ IMF_EXPORT bool has##suffix (const Header &header); \
+ IMF_EXPORT const TypedAttribute<object> & \
+ name##Attribute (const Header &header); \
+ IMF_EXPORT TypedAttribute<object> & \
+ name##Attribute (Header &header); \
+ IMF_EXPORT const object & \
+ name (const Header &header); \
+ IMF_EXPORT object & name (Header &header); \
+ OPENEXR_IMF_INTERNAL_NAMESPACE_HEADER_EXIT \
//
// chromaticities -- for RGB images, specifies the CIE (x,y)
// known, then it is possible to convert the image's pixels from RGB
// to CIE XYZ tristimulus values (see function RGBtoXYZ() in header
// file ImfChromaticities.h).
-//
+//
//
IMF_STD_ATTRIBUTE_DEF (whiteLuminance, WhiteLuminance, float)
// be mapped to neutral values on the display.
//
-IMF_STD_ATTRIBUTE_DEF (adoptedNeutral, AdoptedNeutral, Imath::V2f)
+IMF_STD_ATTRIBUTE_DEF (adoptedNeutral, AdoptedNeutral, IMATH_NAMESPACE::V2f)
//
// renderingTransform, lookModTransform -- specify the names of the
// CTL functions that implements the intended color rendering and look
// modification transforms for this image.
-//
+//
IMF_STD_ATTRIBUTE_DEF (renderingTransform, RenderingTransform, std::string)
IMF_STD_ATTRIBUTE_DEF (lookModTransform, LookModTransform, std::string)
//
IMF_STD_ATTRIBUTE_DEF (owner, Owner, std::string)
-
+
//
// comments -- additional image information in human-readable
IMF_STD_ATTRIBUTE_DEF (multiView , MultiView, StringVector)
-//
+//
// worldToCamera -- for images generated by 3D computer graphics rendering,
// a matrix that transforms 3D points from the world to the camera coordinate
// space of the renderer.
-//
+//
// The camera coordinate space is left-handed. Its origin indicates the
// location of the camera. The positive x and y axes correspond to the
// "right" and "up" directions in the rendered image. The positive z
// axis indicates the camera's viewing direction. (Objects in front of
// the camera have positive z coordinates.)
-//
+//
// Camera coordinate space in OpenEXR is the same as in Pixar's Renderman.
-//
+//
-IMF_STD_ATTRIBUTE_DEF (worldToCamera, WorldToCamera, Imath::M44f)
+IMF_STD_ATTRIBUTE_DEF (worldToCamera, WorldToCamera, IMATH_NAMESPACE::M44f)
-//
+//
// worldToNDC -- for images generated by 3D computer graphics rendering, a
// matrix that transforms 3D points from the world to the Normalized Device
// Coordinate (NDC) space of the renderer.
-//
+//
// NDC is a 2D coordinate space that corresponds to the image plane, with
// positive x and pointing to the right and y positive pointing down. The
// coordinates (0, 0) and (1, 1) correspond to the upper left and lower right
// corners of the OpenEXR display window.
-//
+//
// To transform a 3D point in word space into a 2D point in NDC space,
// multiply the 3D point by the worldToNDC matrix and discard the z
// coordinate.
-//
+//
// NDC space in OpenEXR is the same as in Pixar's Renderman.
+//
+
+IMF_STD_ATTRIBUTE_DEF (worldToNDC, WorldToNDC, IMATH_NAMESPACE::M44f)
+
+
+//
+// deepImageState -- specifies whether the pixels in a deep image are
+// sorted and non-overlapping.
+//
+// Note: this attribute can be set by application code that writes a file
+// in order to tell applications that read the file whether the pixel data
+// must be cleaned up prior to image processing operations such as flattening.
+// The IlmImf library does not verify that the attribute is consistent with
+// the actual state of the pixels. Application software may assume that the
+// attribute is valid, as long as the software will not crash or lock up if
+// any pixels are inconsistent with the deepImageState attribute.
+//
+
+IMF_STD_ATTRIBUTE_DEF (deepImageState, DeepImageState, DeepImageState)
+
+
+//
+// originalDataWindow -- if application software crops an image, then it
+// should save the data window of the original, un-cropped image in the
+// originalDataWindow attribute.
+//
+
+IMF_STD_ATTRIBUTE_DEF
+ (originalDataWindow, OriginalDataWindow, IMATH_NAMESPACE::Box2i)
+
+
+//
+// dwaCompressionLevel -- sets the quality level for images compressed
+// with the DWAA or DWAB method.
//
-IMF_STD_ATTRIBUTE_DEF (worldToNDC, WorldToNDC, Imath::M44f)
+IMF_STD_ATTRIBUTE_DEF (dwaCompressionLevel, DwaCompressionLevel, float)
-} // namespace Imf
#endif
//
// Copyright (c) 2004, Industrial Light & Magic, a division of Lucas
// Digital Ltd. LLC
-//
+//
// All rights reserved.
-//
+//
// Redistribution and use in source and binary forms, with or without
// modification, are permitted provided that the following conditions are
// met:
// distribution.
// * Neither the name of Industrial Light & Magic nor the names of
// its contributors may be used to endorse or promote products derived
-// from this software without specific prior written permission.
-//
+// from this software without specific prior written permission.
+//
// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
#include <ImfStdIO.h>
#include "Iex.h"
#include <errno.h>
+#ifdef _MSC_VER
+# define VC_EXTRALEAN
+# include <Windows.h>
+# include <string.h>
+#endif
using namespace std;
+#include "ImfNamespace.h"
+
+OPENEXR_IMF_INTERNAL_NAMESPACE_SOURCE_ENTER
-namespace Imf {
namespace {
+#ifdef _MSC_VER
+std::wstring WidenFilename (const char *filename)
+{
+ std::wstring ret;
+ int fnlen = static_cast<int>( strlen(filename) );
+ int len = MultiByteToWideChar(CP_UTF8, 0, filename, fnlen, NULL, 0 );
+ if (len > 0)
+ {
+ ret.resize(len);
+ MultiByteToWideChar(CP_UTF8, 0, filename, fnlen, &ret[0], len);
+ }
+ return ret;
+}
+#endif
+
void
clearError ()
{
{
if (!is)
{
- if (errno)
- Iex::throwErrnoExc();
-
- if (is.gcount() < expected)
- {
- THROW (Iex::InputExc, "Early end of file: read " << is.gcount()
- << " out of " << expected << " requested bytes.");
- }
- return false;
+ if (errno)
+ IEX_NAMESPACE::throwErrnoExc();
+
+ if (is.gcount() < expected)
+ {
+ THROW (IEX_NAMESPACE::InputExc, "Early end of file: read " << is.gcount()
+ << " out of " << expected << " requested bytes.");
+ }
+ return false;
}
return true;
{
if (!os)
{
- if (errno)
- Iex::throwErrnoExc();
+ if (errno)
+ IEX_NAMESPACE::throwErrnoExc();
- throw Iex::ErrnoExc ("File output failed.");
+ throw IEX_NAMESPACE::ErrnoExc ("File output failed.");
}
}
StdIFStream::StdIFStream (const char fileName[]):
- IStream (fileName),
- _is (new ifstream (fileName, ios_base::binary)),
+ OPENEXR_IMF_INTERNAL_NAMESPACE::IStream (fileName),
+ _is (new ifstream (
+#ifdef _MSC_VER
+ WidenFilename(fileName).c_str(),
+#else
+ fileName,
+#endif
+ ios_base::binary)),
_deleteStream (true)
{
if (!*_is)
{
- delete _is;
- Iex::throwErrnoExc();
+ delete _is;
+ IEX_NAMESPACE::throwErrnoExc();
}
}
-
+
StdIFStream::StdIFStream (ifstream &is, const char fileName[]):
- IStream (fileName),
+ OPENEXR_IMF_INTERNAL_NAMESPACE::IStream (fileName),
_is (&is),
_deleteStream (false)
{
StdIFStream::~StdIFStream ()
{
if (_deleteStream)
- delete _is;
+ delete _is;
}
StdIFStream::read (char c[/*n*/], int n)
{
if (!*_is)
- throw Iex::InputExc ("Unexpected end of file.");
+ throw IEX_NAMESPACE::InputExc ("Unexpected end of file.");
clearError();
_is->read (c, n);
StdOFStream::StdOFStream (const char fileName[]):
- OStream (fileName),
- _os (new ofstream (fileName, ios_base::binary)),
+ OPENEXR_IMF_INTERNAL_NAMESPACE::OStream (fileName),
+ _os (new ofstream (
+#ifdef _MSC_VER
+ WidenFilename(fileName).c_str(),
+#else
+ fileName,
+#endif
+ ios_base::binary)),
_deleteStream (true)
{
if (!*_os)
{
- delete _os;
- Iex::throwErrnoExc();
+ delete _os;
+ IEX_NAMESPACE::throwErrnoExc();
}
}
StdOFStream::StdOFStream (ofstream &os, const char fileName[]):
- OStream (fileName),
+ OPENEXR_IMF_INTERNAL_NAMESPACE::OStream (fileName),
_os (&os),
_deleteStream (false)
{
StdOFStream::~StdOFStream ()
{
if (_deleteStream)
- delete _os;
+ delete _os;
}
}
-StdOSStream::StdOSStream (): OStream ("(string)")
+StdOSStream::StdOSStream (): OPENEXR_IMF_INTERNAL_NAMESPACE::OStream ("(string)")
{
// empty
}
}
-} // namespace Imf
+OPENEXR_IMF_INTERNAL_NAMESPACE_SOURCE_EXIT
//
// Copyright (c) 2004, Industrial Light & Magic, a division of Lucas
// Digital Ltd. LLC
-//
+//
// All rights reserved.
-//
+//
// Redistribution and use in source and binary forms, with or without
// modification, are permitted provided that the following conditions are
// met:
// distribution.
// * Neither the name of Industrial Light & Magic nor the names of
// its contributors may be used to endorse or promote products derived
-// from this software without specific prior written permission.
-//
+// from this software without specific prior written permission.
+//
// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
//
//-----------------------------------------------------------------------------
-#include <ImfIO.h>
+#include "ImfIO.h"
+#include "ImfNamespace.h"
+#include "ImfExport.h"
+
#include <fstream>
#include <sstream>
-namespace Imf {
+
+OPENEXR_IMF_INTERNAL_NAMESPACE_HEADER_ENTER
//-------------------------------------------
// class StdIFStream -- an implementation of
-// class IStream based on class std::ifstream
+// class OPENEXR_IMF_INTERNAL_NAMESPACE::IStream based on class std::ifstream
//-------------------------------------------
-class StdIFStream: public IStream
+class StdIFStream: public OPENEXR_IMF_INTERNAL_NAMESPACE::IStream
{
public:
// The destructor will close the file.
//-------------------------------------------------------
+ IMF_EXPORT
StdIFStream (const char fileName[]);
-
+
//---------------------------------------------------------
// A constructor that uses a std::ifstream that has already
// been opened by the caller. The StdIFStream's destructor
// will not close the std::ifstream.
//---------------------------------------------------------
+ IMF_EXPORT
StdIFStream (std::ifstream &is, const char fileName[]);
+ IMF_EXPORT
virtual ~StdIFStream ();
+ IMF_EXPORT
virtual bool read (char c[/*n*/], int n);
+ IMF_EXPORT
virtual Int64 tellg ();
+ IMF_EXPORT
virtual void seekg (Int64 pos);
+ IMF_EXPORT
virtual void clear ();
private:
//-------------------------------------------
// class StdOFStream -- an implementation of
-// class OStream based on class std::ofstream
+// class OPENEXR_IMF_INTERNAL_NAMESPACE::OStream based on class std::ofstream
//-------------------------------------------
-class StdOFStream: public OStream
+class StdOFStream: public OPENEXR_IMF_INTERNAL_NAMESPACE::OStream
{
public:
// The destructor will close the file.
//-------------------------------------------------------
+ IMF_EXPORT
StdOFStream (const char fileName[]);
-
+
//---------------------------------------------------------
// A constructor that uses a std::ofstream that has already
// will not close the std::ofstream.
//---------------------------------------------------------
+ IMF_EXPORT
StdOFStream (std::ofstream &os, const char fileName[]);
+ IMF_EXPORT
virtual ~StdOFStream ();
+ IMF_EXPORT
virtual void write (const char c[/*n*/], int n);
+ IMF_EXPORT
virtual Int64 tellp ();
+ IMF_EXPORT
virtual void seekp (Int64 pos);
private:
//------------------------------------------------
// class StdOSStream -- an implementation of class
-// OStream, based on class std::ostringstream
+// OPENEXR_IMF_INTERNAL_NAMESPACE::OStream, based on class std::ostringstream
//------------------------------------------------
-class StdOSStream: public OStream
+class StdOSStream: public OPENEXR_IMF_INTERNAL_NAMESPACE::OStream
{
public:
+ IMF_EXPORT
StdOSStream ();
+ IMF_EXPORT
virtual void write (const char c[/*n*/], int n);
+ IMF_EXPORT
virtual Int64 tellp ();
+ IMF_EXPORT
virtual void seekp (Int64 pos);
+ IMF_EXPORT
std::string str () const {return _os.str();}
private:
};
-} // namespace Imf
+OPENEXR_IMF_INTERNAL_NAMESPACE_HEADER_EXIT
#endif
//
// Copyright (c) 2004, Industrial Light & Magic, a division of Lucas
// Digital Ltd. LLC
-//
+//
// All rights reserved.
-//
+//
// Redistribution and use in source and binary forms, with or without
// modification, are permitted provided that the following conditions are
// met:
// distribution.
// * Neither the name of Industrial Light & Magic nor the names of
// its contributors may be used to endorse or promote products derived
-// from this software without specific prior written permission.
-//
+// from this software without specific prior written permission.
+//
// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
#include <ImfStringAttribute.h>
-namespace Imf {
+OPENEXR_IMF_INTERNAL_NAMESPACE_SOURCE_ENTER
+using namespace OPENEXR_IMF_INTERNAL_NAMESPACE;
template <>
const char *
template <>
void
-StringAttribute::writeValueTo (OStream &os, int) const
+StringAttribute::writeValueTo (OPENEXR_IMF_INTERNAL_NAMESPACE::OStream &os, int version) const
{
int size = _value.size();
for (int i = 0; i < size; i++)
- Xdr::write <StreamIO> (os, _value[i]);
+ Xdr::write <StreamIO> (os, _value[i]);
}
template <>
void
-StringAttribute::readValueFrom (IStream &is, int size, int)
+StringAttribute::readValueFrom (OPENEXR_IMF_INTERNAL_NAMESPACE::IStream &is, int size, int version)
{
_value.resize (size);
for (int i = 0; i < size; i++)
- Xdr::read <StreamIO> (is, _value[i]);
+ Xdr::read <StreamIO> (is, _value[i]);
}
-} // namespace Imf
+OPENEXR_IMF_INTERNAL_NAMESPACE_SOURCE_EXIT
//
// Copyright (c) 2004, Industrial Light & Magic, a division of Lucas
// Digital Ltd. LLC
-//
+//
// All rights reserved.
-//
+//
// Redistribution and use in source and binary forms, with or without
// modification, are permitted provided that the following conditions are
// met:
// distribution.
// * Neither the name of Industrial Light & Magic nor the names of
// its contributors may be used to endorse or promote products derived
-// from this software without specific prior written permission.
-//
+// from this software without specific prior written permission.
+//
// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
//
//-----------------------------------------------------------------------------
-#include <ImfAttribute.h>
+#include "ImfAttribute.h"
#include <string>
-
-namespace Imf {
+OPENEXR_IMF_INTERNAL_NAMESPACE_HEADER_ENTER
typedef TypedAttribute<std::string> StringAttribute;
-template <> const char *StringAttribute::staticTypeName ();
-template <> void StringAttribute::writeValueTo (OStream &, int) const;
-template <> void StringAttribute::readValueFrom (IStream &, int, int);
+template <>
+IMF_EXPORT
+const char *StringAttribute::staticTypeName ();
-} // namespace Imf
+template <>
+IMF_EXPORT
+void StringAttribute::writeValueTo (OPENEXR_IMF_INTERNAL_NAMESPACE::OStream &,
+ int) const;
-// Metrowerks compiler wants the .cpp file inlined, too
-#ifdef __MWERKS__
-#include <ImfStringAttribute.cpp>
-#endif
+template <>
+IMF_EXPORT
+void StringAttribute::readValueFrom (OPENEXR_IMF_INTERNAL_NAMESPACE::IStream &,
+ int, int);
+
+
+OPENEXR_IMF_INTERNAL_NAMESPACE_HEADER_EXIT
#endif
///////////////////////////////////////////////////////////////////////////
//
// Copyright (c) 2007, Weta Digital Ltd
-//
+//
// All rights reserved.
-//
+//
// Redistribution and use in source and binary forms, with or without
// modification, are permitted provided that the following conditions are
// met:
// distribution.
// * Neither the name of Weta Digital nor the names of
// its contributors may be used to endorse or promote products derived
-// from this software without specific prior written permission.
-//
+// from this software without specific prior written permission.
+//
// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
///////////////////////////////////////////////////////////////////////////
-
//-----------------------------------------------------------------------------
//
-// class StringAttribute
+// class StringVectorAttribute
//
//-----------------------------------------------------------------------------
#include <ImfStringVectorAttribute.h>
-namespace Imf {
+OPENEXR_IMF_INTERNAL_NAMESPACE_SOURCE_ENTER
+
+
+using namespace OPENEXR_IMF_INTERNAL_NAMESPACE;
template <>
template <>
void
-StringVectorAttribute::writeValueTo (OStream &os, int) const
+StringVectorAttribute::writeValueTo (OPENEXR_IMF_INTERNAL_NAMESPACE::OStream &os, int version) const
{
int size = _value.size();
{
int strSize = _value[i].size();
Xdr::write <StreamIO> (os, strSize);
- Xdr::write <StreamIO> (os, &_value[i][0], strSize);
+ Xdr::write <StreamIO> (os, &_value[i][0], strSize);
}
}
template <>
void
-StringVectorAttribute::readValueFrom (IStream &is, int size, int)
+StringVectorAttribute::readValueFrom (OPENEXR_IMF_INTERNAL_NAMESPACE::IStream &is, int size, int version)
{
int read = 0;
while (read < size)
- {
+ {
int strSize;
Xdr::read <StreamIO> (is, strSize);
- read += Xdr::size<int>();
+ read += Xdr::size<int>();
std::string str;
str.resize (strSize);
-
- Xdr::read<StreamIO> (is, &str[0], strSize);
+
+ if( strSize>0 )
+ {
+ Xdr::read<StreamIO> (is, &str[0], strSize);
+ }
+
read += strSize;
_value.push_back (str);
}
-} // namespace Imf
+OPENEXR_IMF_INTERNAL_NAMESPACE_SOURCE_EXIT
///////////////////////////////////////////////////////////////////////////
//
// Copyright (c) 2007, Weta Digital Ltd
-//
+//
// All rights reserved.
-//
+//
// Redistribution and use in source and binary forms, with or without
// modification, are permitted provided that the following conditions are
// met:
// distribution.
// * Neither the name of Weta Digital nor the names of
// its contributors may be used to endorse or promote products derived
-// from this software without specific prior written permission.
-//
+// from this software without specific prior written permission.
+//
// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
//
//-----------------------------------------------------------------------------
-#include <ImfAttribute.h>
+#include "ImfAttribute.h"
+#include "ImfNamespace.h"
+
#include <string>
#include <vector>
-namespace Imf {
+OPENEXR_IMF_INTERNAL_NAMESPACE_HEADER_ENTER
typedef std::vector<std::string> StringVector;
-typedef TypedAttribute<StringVector> StringVectorAttribute;
-template <> const char *StringVectorAttribute::staticTypeName ();
-template <> void StringVectorAttribute::writeValueTo (OStream &, int) const;
-template <> void StringVectorAttribute::readValueFrom (IStream &, int, int);
+typedef TypedAttribute<OPENEXR_IMF_INTERNAL_NAMESPACE::StringVector> StringVectorAttribute;
+template <>
+IMF_EXPORT
+const char *StringVectorAttribute::staticTypeName ();
-} // namespace Imf
+template <>
+IMF_EXPORT
+void StringVectorAttribute::writeValueTo (OPENEXR_IMF_INTERNAL_NAMESPACE::OStream &,
+ int) const;
-// Metrowerks compiler wants the .cpp file inlined, too
-#ifdef __MWERKS__
-#include <ImfStringVectorAttribute.cpp>
-#endif
+template <>
+IMF_EXPORT
+void StringVectorAttribute::readValueFrom (OPENEXR_IMF_INTERNAL_NAMESPACE::IStream &,
+ int, int);
+
+
+OPENEXR_IMF_INTERNAL_NAMESPACE_HEADER_EXIT
#endif
--- /dev/null
+///////////////////////////////////////////////////////////////////////////
+//
+// Copyright (c) 2009-2014 DreamWorks Animation LLC.
+//
+// All rights reserved.
+//
+// Redistribution and use in source and binary forms, with or without
+// modification, are permitted provided that the following conditions are
+// met:
+// * Redistributions of source code must retain the above copyright
+// notice, this list of conditions and the following disclaimer.
+// * Redistributions in binary form must reproduce the above
+// copyright notice, this list of conditions and the following disclaimer
+// in the documentation and/or other materials provided with the
+// distribution.
+// * Neither the name of DreamWorks Animation nor the names of
+// its contributors may be used to endorse or promote products derived
+// from this software without specific prior written permission.
+//
+// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+//
+///////////////////////////////////////////////////////////////////////////
+
+#include "ImfSimd.h"
+#include "ImfSystemSpecific.h"
+#include "ImfNamespace.h"
+#include "OpenEXRConfig.h"
+
+OPENEXR_IMF_INTERNAL_NAMESPACE_SOURCE_ENTER
+
+namespace {
+#if defined(IMF_HAVE_SSE2) && defined(__GNUC__) && !defined(__ANDROID__)
+
+ // Helper functions for gcc + SSE enabled
+ void cpuid(int n, int &eax, int &ebx, int &ecx, int &edx)
+ {
+ __asm__ __volatile__ (
+ "cpuid"
+ : /* Output */ "=a"(eax), "=b"(ebx), "=c"(ecx), "=d"(edx)
+ : /* Input */ "a"(n)
+ : /* Clobber */);
+ }
+
+#else // IMF_HAVE_SSE2 && __GNUC__
+
+ // Helper functions for generic compiler - all disabled
+ void cpuid(int n, int &eax, int &ebx, int &ecx, int &edx)
+ {
+ eax = ebx = ecx = edx = 0;
+ }
+
+#endif // IMF_HAVE_SSE2 && __GNUC__
+
+
+#ifdef OPENEXR_IMF_HAVE_GCC_INLINE_ASM_AVX
+
+ void xgetbv(int n, int &eax, int &edx)
+ {
+ __asm__ __volatile__ (
+ "xgetbv"
+ : /* Output */ "=a"(eax), "=d"(edx)
+ : /* Input */ "c"(n)
+ : /* Clobber */);
+ }
+
+#else // OPENEXR_IMF_HAVE_GCC_INLINE_ASM_AVX
+
+ void xgetbv(int n, int &eax, int &edx)
+ {
+ eax = edx = 0;
+ }
+
+#endif // OPENEXR_IMF_HAVE_GCC_INLINE_ASM_AVX
+
+} // namespace
+
+CpuId::CpuId():
+ sse2(false),
+ sse3(false),
+ ssse3(false),
+ sse4_1(false),
+ sse4_2(false),
+ avx(false),
+ f16c(false)
+{
+ bool osxsave = false;
+ int max = 0;
+ int eax, ebx, ecx, edx;
+
+ cpuid(0, max, ebx, ecx, edx);
+ if (max > 0)
+ {
+ cpuid(1, eax, ebx, ecx, edx);
+ sse2 = ( edx & (1<<26) );
+ sse3 = ( ecx & (1<< 0) );
+ ssse3 = ( ecx & (1<< 9) );
+ sse4_1 = ( ecx & (1<<19) );
+ sse4_2 = ( ecx & (1<<20) );
+ osxsave = ( ecx & (1<<27) );
+ avx = ( ecx & (1<<28) );
+ f16c = ( ecx & (1<<29) );
+
+ if (!osxsave)
+ {
+ avx = f16c = false;
+ }
+ else
+ {
+ xgetbv(0, eax, edx);
+ // eax bit 1 - SSE managed, bit 2 - AVX managed
+ if ((eax & 6) != 6)
+ {
+ avx = f16c = false;
+ }
+ }
+ }
+
+#if defined(IMF_HAVE_SSE2) && defined(__ANDROID__)
+ sse2 = true;
+ sse3 = true;
+#ifdef __x86_64__
+ ssse3 = true;
+ sse4_1 = true;
+#endif
+#endif
+}
+
+OPENEXR_IMF_INTERNAL_NAMESPACE_SOURCE_EXIT
--- /dev/null
+///////////////////////////////////////////////////////////////////////////
+//
+// Copyright (c) 2012, Industrial Light & Magic, a division of Lucas
+// Digital Ltd. LLC
+//
+// All rights reserved.
+//
+// Redistribution and use in source and binary forms, with or without
+// modification, are permitted provided that the following conditions are
+// met:
+// * Redistributions of source code must retain the above copyright
+// notice, this list of conditions and the following disclaimer.
+// * Redistributions in binary form must reproduce the above
+// copyright notice, this list of conditions and the following disclaimer
+// in the documentation and/or other materials provided with the
+// distribution.
+// * Neither the name of Industrial Light & Magic nor the names of
+// its contributors may be used to endorse or promote products derived
+// from this software without specific prior written permission.
+//
+// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+//
+///////////////////////////////////////////////////////////////////////////
+
+#ifndef INCLUDED_IMF_COMPILER_SPECIFIC_H
+#define INCLUDED_IMF_COMPILER_SPECIFIC_H
+
+#include "ImfNamespace.h"
+#include "ImfSimd.h"
+#include <stdlib.h>
+#include "ImfExport.h"
+
+OPENEXR_IMF_INTERNAL_NAMESPACE_HEADER_ENTER
+
+
+static unsigned long systemEndianCheckValue = 0x12345678;
+static unsigned long* systemEndianCheckPointer = &systemEndianCheckValue;
+
+// EXR files are little endian - check processor architecture is too
+// (optimisation currently not supported for big endian machines)
+static bool GLOBAL_SYSTEM_LITTLE_ENDIAN =
+ (*(unsigned char*)systemEndianCheckPointer == 0x78 ? true : false);
+
+
+#ifdef IMF_HAVE_SSE2
+
+#if defined(__GNUC__)
+// Causes issues on certain gcc versions
+//#define EXR_FORCEINLINE inline __attribute__((always_inline))
+#define EXR_FORCEINLINE inline
+#define EXR_RESTRICT __restrict
+
+static void* EXRAllocAligned(size_t size, size_t alignment)
+{
+ // GNUC is used for things like mingw to (cross-)compile for windows
+#ifdef _WIN32
+ return _aligned_malloc(size, alignment);
+#elif defined(__ANDROID__)
+ return memalign(alignment, size);
+#else
+ void* ptr = 0;
+ posix_memalign(&ptr, alignment, size);
+ return ptr;
+#endif
+}
+
+
+static void EXRFreeAligned(void* ptr)
+{
+#ifdef _WIN32
+ _aligned_free(ptr);
+#else
+ free(ptr);
+#endif
+}
+
+#elif defined _MSC_VER
+
+#define EXR_FORCEINLINE __forceinline
+#define EXR_RESTRICT __restrict
+
+static void* EXRAllocAligned(size_t size, size_t alignment)
+{
+ return _aligned_malloc(size, alignment);
+}
+
+
+static void EXRFreeAligned(void* ptr)
+{
+ _aligned_free(ptr);
+}
+
+#elif defined (__INTEL_COMPILER) || \
+ defined(__ICL) || \
+ defined(__ICC) || \
+ defined(__ECC)
+
+#define EXR_FORCEINLINE inline
+#define EXR_RESTRICT restrict
+
+static void* EXRAllocAligned(size_t size, size_t alignment)
+{
+ return _mm_malloc(size, alignment);
+}
+
+
+static void EXRFreeAligned(void* ptr)
+{
+ _mm_free(ptr);
+}
+
+#else
+
+// generic compiler
+#define EXR_FORCEINLINE inline
+#define EXR_RESTRICT
+
+static void* EXRAllocAligned(size_t size, size_t alignment)
+{
+ return malloc(size);
+}
+
+
+static void EXRFreeAligned(void* ptr)
+{
+ free(ptr);
+}
+
+#endif // compiler switch
+
+
+#else // IMF_HAVE_SSE2
+
+
+#define EXR_FORCEINLINE inline
+#define EXR_RESTRICT
+
+static void* EXRAllocAligned(size_t size, size_t alignment)
+{
+ return malloc(size);
+}
+
+
+static void EXRFreeAligned(void* ptr)
+{
+ free(ptr);
+}
+
+
+#endif // IMF_HAVE_SSE2
+
+//
+// Simple CPUID based runtime detection of various capabilities
+//
+class IMF_EXPORT CpuId
+{
+ public:
+ CpuId();
+
+ bool sse2;
+ bool sse3;
+ bool ssse3;
+ bool sse4_1;
+ bool sse4_2;
+ bool avx;
+ bool f16c;
+};
+
+
+OPENEXR_IMF_INTERNAL_NAMESPACE_HEADER_EXIT
+
+
+#endif //include guard
//
// Copyright (c) 2004, Industrial Light & Magic, a division of Lucas
// Digital Ltd. LLC
-//
+//
// All rights reserved.
-//
+//
// Redistribution and use in source and binary forms, with or without
// modification, are permitted provided that the following conditions are
// met:
// distribution.
// * Neither the name of Industrial Light & Magic nor the names of
// its contributors may be used to endorse or promote products derived
-// from this software without specific prior written permission.
-//
+// from this software without specific prior written permission.
+//
// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
#include <ImfStdIO.h>
#include <ImfXdr.h>
#include <ImfVersion.h>
+#include "ImfNamespace.h"
-namespace Imf {
+OPENEXR_IMF_INTERNAL_NAMESPACE_SOURCE_ENTER
bool
-isOpenExrFile (const char fileName[], bool &tiled)
+isOpenExrFile
+ (const char fileName[],
+ bool &tiled,
+ bool &deep,
+ bool &multiPart)
{
try
{
- StdIFStream is (fileName);
+ StdIFStream is (fileName);
- int magic, version;
- Xdr::read <StreamIO> (is, magic);
- Xdr::read <StreamIO> (is, version);
+ int magic, version;
+ Xdr::read <StreamIO> (is, magic);
+ Xdr::read <StreamIO> (is, version);
- tiled = isTiled (version);
- return magic == MAGIC;
+ tiled = isTiled (version);
+ deep = isNonImage (version);
+ multiPart = isMultiPart (version);
+ return magic == MAGIC;
}
catch (...)
{
- tiled = false;
- return false;
+ tiled = false;
+ return false;
}
}
bool
+isOpenExrFile (const char fileName[], bool &tiled, bool &deep)
+{
+ bool multiPart;
+ return isOpenExrFile (fileName, tiled, deep, multiPart);
+}
+
+
+bool
+isOpenExrFile (const char fileName[], bool &tiled)
+{
+ bool deep, multiPart;
+ return isOpenExrFile (fileName, tiled, deep, multiPart);
+}
+
+
+bool
isOpenExrFile (const char fileName[])
{
- bool tiled;
- return isOpenExrFile (fileName, tiled);
+ bool tiled, deep, multiPart;
+ return isOpenExrFile (fileName, tiled, deep, multiPart);
}
bool
isTiledOpenExrFile (const char fileName[])
{
- bool exr, tiled;
- exr = isOpenExrFile (fileName, tiled);
+ bool exr, tiled, deep, multiPart;
+ exr = isOpenExrFile (fileName, tiled, deep, multiPart);
return exr && tiled;
}
bool
-isOpenExrFile (IStream &is, bool &tiled)
+isDeepOpenExrFile (const char fileName[])
+{
+ bool exr, tiled, deep, multiPart;
+ exr = isOpenExrFile (fileName, tiled, deep, multiPart);
+ return exr && deep;
+}
+
+
+bool
+isMultiPartOpenExrFile (const char fileName[])
+{
+ bool exr, tiled, deep, multiPart;
+ exr = isOpenExrFile (fileName, tiled, deep, multiPart);
+ return exr && multiPart;
+}
+
+
+bool
+isOpenExrFile
+ (IStream &is,
+ bool &tiled,
+ bool &deep,
+ bool &multiPart)
{
try
{
- Int64 pos = is.tellg();
+ Int64 pos = is.tellg();
- if (pos != 0)
- is.seekg (0);
+ if (pos != 0)
+ is.seekg (0);
- int magic, version;
- Xdr::read <StreamIO> (is, magic);
- Xdr::read <StreamIO> (is, version);
+ int magic, version;
+ Xdr::read <StreamIO> (is, magic);
+ Xdr::read <StreamIO> (is, version);
- is.seekg (pos);
+ is.seekg (pos);
- tiled = isTiled (version);
- return magic == MAGIC;
+ tiled = isTiled (version);
+ deep = isNonImage (version);
+ multiPart = isMultiPart (version);
+ return magic == MAGIC;
}
catch (...)
{
- is.clear();
- tiled = false;
- return false;
+ is.clear();
+ tiled = false;
+ return false;
}
}
bool
-isOpenExrFile (IStream &is)
+isOpenExrFile (IStream &is, bool &tiled, bool &deep)
+{
+ bool multiPart;
+ return isOpenExrFile (is, tiled, deep, multiPart);
+}
+
+
+bool
+isOpenExrFile (IStream &is, bool &tiled)
{
- bool tiled;
- return isOpenExrFile (is, tiled);
+ bool deep, multiPart;
+ return isOpenExrFile (is, tiled, deep, multiPart);
}
bool
-isTiledOpenExrFile (IStream &is)
+isOpenExrFile (OPENEXR_IMF_INTERNAL_NAMESPACE::IStream &is)
{
- bool exr, tiled;
- exr = isOpenExrFile (is, tiled);
+ bool tiled, deep, multiPart;
+ return isOpenExrFile (is, tiled, deep, multiPart);
+}
+
+
+bool
+isTiledOpenExrFile (OPENEXR_IMF_INTERNAL_NAMESPACE::IStream &is)
+{
+ bool exr, tiled, deep, multiPart;
+ exr = isOpenExrFile (is, tiled, deep, multiPart);
return exr && tiled;
}
-} // namespace Imf
+
+bool
+isDeepOpenExrFile (OPENEXR_IMF_INTERNAL_NAMESPACE::IStream &is)
+{
+ bool exr, tiled, deep, multiPart;
+ exr = isOpenExrFile (is, tiled, deep, multiPart);
+ return exr && deep;
+}
+
+
+bool
+isMultiPartOpenExrFile (OPENEXR_IMF_INTERNAL_NAMESPACE::IStream &is)
+{
+ bool exr, tiled, deep, multiPart;
+ exr = isOpenExrFile (is, tiled, deep, multiPart);
+ return exr && multiPart;
+}
+
+OPENEXR_IMF_INTERNAL_NAMESPACE_SOURCE_EXIT
//
// Copyright (c) 2004, Industrial Light & Magic, a division of Lucas
// Digital Ltd. LLC
-//
+//
// All rights reserved.
-//
+//
// Redistribution and use in source and binary forms, with or without
// modification, are permitted provided that the following conditions are
// met:
// distribution.
// * Neither the name of Industrial Light & Magic nor the names of
// its contributors may be used to endorse or promote products derived
-// from this software without specific prior written permission.
-//
+// from this software without specific prior written permission.
+//
// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
//
//-----------------------------------------------------------------------------
+#include "ImfForward.h"
+#include "ImfExport.h"
+#include "ImfNamespace.h"
+
+OPENEXR_IMF_INTERNAL_NAMESPACE_HEADER_ENTER
+
+
+IMF_EXPORT bool isOpenExrFile (const char fileName[]);
+
+IMF_EXPORT bool isOpenExrFile (const char fileName[],
+ bool &isTiled);
+
+IMF_EXPORT bool isOpenExrFile (const char fileName[],
+ bool &isTiled,
+ bool &isDeep);
+
+IMF_EXPORT bool isOpenExrFile (const char fileName[],
+ bool &isTiled,
+ bool &isDeep,
+ bool &isMultiPart);
+
+IMF_EXPORT bool isTiledOpenExrFile (const char fileName[]);
+
+IMF_EXPORT bool isDeepOpenExrFile (const char fileName[]);
+
+IMF_EXPORT bool isMultiPartOpenExrFile (const char fileName[]);
+
+IMF_EXPORT bool isOpenExrFile (IStream &is);
+
+IMF_EXPORT bool isOpenExrFile (IStream &is,
+ bool &isTiled);
+
+IMF_EXPORT bool isOpenExrFile (IStream &is,
+ bool &isTiled,
+ bool &isDeep);
-namespace Imf {
+IMF_EXPORT bool isOpenExrFile (IStream &is,
+ bool &isTiled,
+ bool &isDeep,
+ bool &isMultiPart);
-class IStream;
+IMF_EXPORT bool isTiledOpenExrFile (IStream &is);
+IMF_EXPORT bool isDeepOpenExrFile (IStream &is);
-bool isOpenExrFile (const char fileName[], bool &isTiled);
-bool isOpenExrFile (const char fileName[]);
-bool isTiledOpenExrFile (const char fileName[]);
-bool isOpenExrFile (IStream &is, bool &isTiled);
-bool isOpenExrFile (IStream &is);
-bool isTiledOpenExrFile (IStream &is);
+IMF_EXPORT bool isMultiPartOpenExrFile (IStream &is);
-} // namespace Imf
+OPENEXR_IMF_INTERNAL_NAMESPACE_HEADER_EXIT
#endif
//
// Copyright (c) 2005, Industrial Light & Magic, a division of Lucas
// Digital Ltd. LLC
-//
+//
// All rights reserved.
-//
+//
// Redistribution and use in source and binary forms, with or without
// modification, are permitted provided that the following conditions are
// met:
// distribution.
// * Neither the name of Industrial Light & Magic nor the names of
// its contributors may be used to endorse or promote products derived
-// from this software without specific prior written permission.
-//
+// from this software without specific prior written permission.
+//
// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
//
//-----------------------------------------------------------------------------
-#include "IlmThreadPool.h"
#include "ImfThreading.h"
+#include "IlmThreadPool.h"
+#include "ImfNamespace.h"
-namespace Imf {
+OPENEXR_IMF_INTERNAL_NAMESPACE_SOURCE_ENTER
int
globalThreadCount ()
{
- return IlmThread::ThreadPool::globalThreadPool().numThreads();
+ return ILMTHREAD_NAMESPACE::ThreadPool::globalThreadPool().numThreads();
}
void
setGlobalThreadCount (int count)
{
- IlmThread::ThreadPool::globalThreadPool().setNumThreads (count);
+ ILMTHREAD_NAMESPACE::ThreadPool::globalThreadPool().setNumThreads (count);
}
-} // namespace Imf
+OPENEXR_IMF_INTERNAL_NAMESPACE_SOURCE_EXIT
//
// Copyright (c) 2005, Industrial Light & Magic, a division of Lucas
// Digital Ltd. LLC
-//
+//
// All rights reserved.
-//
+//
// Redistribution and use in source and binary forms, with or without
// modification, are permitted provided that the following conditions are
// met:
// distribution.
// * Neither the name of Industrial Light & Magic nor the names of
// its contributors may be used to endorse or promote products derived
-// from this software without specific prior written permission.
-//
+// from this software without specific prior written permission.
+//
// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
#ifndef INCLUDED_IMF_THREADING_H
#define INCLUDED_IMF_THREADING_H
+#include "ImfExport.h"
+#include "ImfNamespace.h"
+
//-----------------------------------------------------------------------------
//
// Threading support for the IlmImf library
// done concurrently through pinelining. If there are two or more
// worker threads, then pipelining as well as concurrent compression
// of multiple blocks can be performed.
-//
+//
// Threading in the Imf library is controllable at two granularities:
//
// * The functions in this file query and control the total number
//
//-----------------------------------------------------------------------------
-namespace Imf {
+OPENEXR_IMF_INTERNAL_NAMESPACE_HEADER_ENTER
//-----------------------------------------------------------------------------
// Return the number of Imf-global worker threads used for parallel
// compression and decompression of OpenEXR files.
//-----------------------------------------------------------------------------
-
-int globalThreadCount ();
+
+IMF_EXPORT int globalThreadCount ();
//-----------------------------------------------------------------------------
// Change the number of Imf-global worker threads
//-----------------------------------------------------------------------------
-void setGlobalThreadCount (int count);
+IMF_EXPORT void setGlobalThreadCount (int count);
-} // namespace Imf
+OPENEXR_IMF_INTERNAL_NAMESPACE_HEADER_EXIT
#endif
//
// Copyright (c) 2004, Industrial Light & Magic, a division of Lucas
// Digital Ltd. LLC
-//
+//
// All rights reserved.
-//
+//
// Redistribution and use in source and binary forms, with or without
// modification, are permitted provided that the following conditions are
// met:
// distribution.
// * Neither the name of Industrial Light & Magic nor the names of
// its contributors may be used to endorse or promote products derived
-// from this software without specific prior written permission.
-//
+// from this software without specific prior written permission.
+//
// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
// class TileDescription and enum LevelMode
//
//-----------------------------------------------------------------------------
+#include "ImfNamespace.h"
-namespace Imf {
+OPENEXR_IMF_INTERNAL_NAMESPACE_HEADER_ENTER
enum LevelMode
ONE_LEVEL = 0,
MIPMAP_LEVELS = 1,
RIPMAP_LEVELS = 2,
-
+
NUM_LEVELMODES // number of different level modes
};
unsigned int ySize; // size of a tile in the y dimension
LevelMode mode;
LevelRoundingMode roundingMode;
-
+
TileDescription (unsigned int xs = 32,
- unsigned int ys = 32,
+ unsigned int ys = 32,
LevelMode m = ONE_LEVEL,
- LevelRoundingMode r = ROUND_DOWN)
+ LevelRoundingMode r = ROUND_DOWN)
:
xSize (xs),
- ySize (ys),
- mode (m),
- roundingMode (r)
+ ySize (ys),
+ mode (m),
+ roundingMode (r)
{
- // empty
+ // empty
}
bool
operator == (const TileDescription &other) const
{
- return xSize == other.xSize &&
- ySize == other.ySize &&
- mode == other.mode &&
- roundingMode == other.roundingMode;
+ return xSize == other.xSize &&
+ ySize == other.ySize &&
+ mode == other.mode &&
+ roundingMode == other.roundingMode;
}
};
-} // namespace Imf
+OPENEXR_IMF_INTERNAL_NAMESPACE_HEADER_EXIT
+
+
+
+
#endif
//
// Copyright (c) 2004, Industrial Light & Magic, a division of Lucas
// Digital Ltd. LLC
-//
+//
// All rights reserved.
-//
+//
// Redistribution and use in source and binary forms, with or without
// modification, are permitted provided that the following conditions are
// met:
// distribution.
// * Neither the name of Industrial Light & Magic nor the names of
// its contributors may be used to endorse or promote products derived
-// from this software without specific prior written permission.
-//
+// from this software without specific prior written permission.
+//
// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
#include <ImfTileDescriptionAttribute.h>
-namespace Imf {
+OPENEXR_IMF_INTERNAL_NAMESPACE_SOURCE_ENTER
+using namespace OPENEXR_IMF_INTERNAL_NAMESPACE;
template <>
const char *
template <>
void
-TileDescriptionAttribute::writeValueTo (OStream &os, int) const
+TileDescriptionAttribute::writeValueTo (OPENEXR_IMF_INTERNAL_NAMESPACE::OStream &os, int version) const
{
Xdr::write <StreamIO> (os, _value.xSize);
Xdr::write <StreamIO> (os, _value.ySize);
template <>
void
-TileDescriptionAttribute::readValueFrom (IStream &is,
- int,
- int)
+TileDescriptionAttribute::readValueFrom (OPENEXR_IMF_INTERNAL_NAMESPACE::IStream &is,
+ int size,
+ int version)
{
Xdr::read <StreamIO> (is, _value.xSize);
Xdr::read <StreamIO> (is, _value.ySize);
Xdr::read <StreamIO> (is, tmp);
_value.mode = LevelMode (tmp & 0x0f);
_value.roundingMode = LevelRoundingMode ((tmp >> 4) & 0x0f);
-
+
}
-} // namespace Imf
+OPENEXR_IMF_INTERNAL_NAMESPACE_SOURCE_EXIT
//
// Copyright (c) 2004, Industrial Light & Magic, a division of Lucas
// Digital Ltd. LLC
-//
+//
// All rights reserved.
-//
+//
// Redistribution and use in source and binary forms, with or without
// modification, are permitted provided that the following conditions are
// met:
// distribution.
// * Neither the name of Industrial Light & Magic nor the names of
// its contributors may be used to endorse or promote products derived
-// from this software without specific prior written permission.
-//
+// from this software without specific prior written permission.
+//
// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
//
//-----------------------------------------------------------------------------
-#include <ImfAttribute.h>
-#include <ImfTileDescription.h>
+#include "ImfAttribute.h"
+#include "ImfTileDescription.h"
-namespace Imf {
+OPENEXR_IMF_INTERNAL_NAMESPACE_HEADER_ENTER
-
-typedef TypedAttribute<TileDescription> TileDescriptionAttribute;
+typedef TypedAttribute<OPENEXR_IMF_INTERNAL_NAMESPACE::TileDescription> TileDescriptionAttribute;
template <>
+IMF_EXPORT
const char *
TileDescriptionAttribute::staticTypeName ();
template <>
+IMF_EXPORT
void
-TileDescriptionAttribute::writeValueTo (OStream &, int) const;
+TileDescriptionAttribute::writeValueTo (OPENEXR_IMF_INTERNAL_NAMESPACE::OStream &,
+ int) const;
template <>
+IMF_EXPORT
void
-TileDescriptionAttribute::readValueFrom (IStream &, int, int);
-
+TileDescriptionAttribute::readValueFrom (OPENEXR_IMF_INTERNAL_NAMESPACE::IStream &,
+ int, int);
-} // namespace Imf
-// Metrowerks compiler wants the .cpp file inlined, too
-#ifdef __MWERKS__
-#include <ImfTileDescriptionAttribute.cpp>
-#endif
+OPENEXR_IMF_INTERNAL_NAMESPACE_HEADER_EXIT
#endif
//
// Copyright (c) 2004, Industrial Light & Magic, a division of Lucas
// Digital Ltd. LLC
-//
+//
// All rights reserved.
-//
+//
// Redistribution and use in source and binary forms, with or without
// modification, are permitted provided that the following conditions are
// met:
// distribution.
// * Neither the name of Industrial Light & Magic nor the names of
// its contributors may be used to endorse or promote products derived
-// from this software without specific prior written permission.
-//
+// from this software without specific prior written permission.
+//
// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
#include <ImfXdr.h>
#include <ImfIO.h>
#include "Iex.h"
+#include "ImfNamespace.h"
+#include <algorithm>
-namespace Imf {
+OPENEXR_IMF_INTERNAL_NAMESPACE_SOURCE_ENTER
TileOffsets::TileOffsets (LevelMode mode,
- int numXLevels, int numYLevels,
- const int *numXTiles, const int *numYTiles)
+ int numXLevels, int numYLevels,
+ const int *numXTiles, const int *numYTiles)
:
_mode (mode),
_numXLevels (numXLevels),
_offsets[l].resize (numYTiles[l]);
for (unsigned int dy = 0; dy < _offsets[l].size(); ++dy)
- {
+ {
_offsets[l][dy].resize (numXTiles[l]);
}
}
_offsets.resize (_numXLevels * _numYLevels);
- for (unsigned int ly = 0; ly < _numYLevels; ++ly)
+ for (int ly = 0; ly < _numYLevels; ++ly)
{
- for (unsigned int lx = 0; lx < _numXLevels; ++lx)
+ for (int lx = 0; lx < _numXLevels; ++lx)
{
int l = ly * _numXLevels + lx;
_offsets[l].resize (numYTiles[ly]);
- for (unsigned int dy = 0; dy < _offsets[l].size(); ++dy)
+ for (size_t dy = 0; dy < _offsets[l].size(); ++dy)
{
_offsets[l][dy].resize (numXTiles[lx]);
}
}
}
break;
+
+ case NUM_LEVELMODES :
+ throw IEX_NAMESPACE::ArgExc("Bad initialisation of TileOffsets object");
}
}
TileOffsets::anyOffsetsAreInvalid () const
{
for (unsigned int l = 0; l < _offsets.size(); ++l)
- for (unsigned int dy = 0; dy < _offsets[l].size(); ++dy)
- for (unsigned int dx = 0; dx < _offsets[l][dy].size(); ++dx)
- if (_offsets[l][dy][dx] <= 0)
- return true;
-
+ for (unsigned int dy = 0; dy < _offsets[l].size(); ++dy)
+ for (unsigned int dx = 0; dx < _offsets[l][dy].size(); ++dx)
+ if (_offsets[l][dy][dx] <= 0)
+ return true;
+
return false;
}
void
-TileOffsets::findTiles (IStream &is)
+TileOffsets::findTiles (OPENEXR_IMF_INTERNAL_NAMESPACE::IStream &is, bool isMultiPartFile, bool isDeep, bool skipOnly)
{
for (unsigned int l = 0; l < _offsets.size(); ++l)
{
- for (unsigned int dy = 0; dy < _offsets[l].size(); ++dy)
- {
- for (unsigned int dx = 0; dx < _offsets[l][dy].size(); ++dx)
- {
- Int64 tileOffset = is.tellg();
+ for (unsigned int dy = 0; dy < _offsets[l].size(); ++dy)
+ {
+ for (unsigned int dx = 0; dx < _offsets[l][dy].size(); ++dx)
+ {
+ Int64 tileOffset = is.tellg();
- int tileX;
- Xdr::read <StreamIO> (is, tileX);
+ if (isMultiPartFile)
+ {
+ int partNumber;
+ OPENEXR_IMF_INTERNAL_NAMESPACE::Xdr::read <OPENEXR_IMF_INTERNAL_NAMESPACE::StreamIO> (is, partNumber);
+ }
- int tileY;
- Xdr::read <StreamIO> (is, tileY);
+ int tileX;
+ OPENEXR_IMF_INTERNAL_NAMESPACE::Xdr::read <OPENEXR_IMF_INTERNAL_NAMESPACE::StreamIO> (is, tileX);
- int levelX;
- Xdr::read <StreamIO> (is, levelX);
+ int tileY;
+ OPENEXR_IMF_INTERNAL_NAMESPACE::Xdr::read <OPENEXR_IMF_INTERNAL_NAMESPACE::StreamIO> (is, tileY);
- int levelY;
- Xdr::read <StreamIO> (is, levelY);
+ int levelX;
+ OPENEXR_IMF_INTERNAL_NAMESPACE::Xdr::read <OPENEXR_IMF_INTERNAL_NAMESPACE::StreamIO> (is, levelX);
- int dataSize;
- Xdr::read <StreamIO> (is, dataSize);
+ int levelY;
+ OPENEXR_IMF_INTERNAL_NAMESPACE::Xdr::read <OPENEXR_IMF_INTERNAL_NAMESPACE::StreamIO> (is, levelY);
- Xdr::skip <StreamIO> (is, dataSize);
+ if(isDeep)
+ {
+ Int64 packed_offset_table_size;
+ Int64 packed_sample_size;
+
+ OPENEXR_IMF_INTERNAL_NAMESPACE::Xdr::read <OPENEXR_IMF_INTERNAL_NAMESPACE::StreamIO> (is, packed_offset_table_size);
+ OPENEXR_IMF_INTERNAL_NAMESPACE::Xdr::read <OPENEXR_IMF_INTERNAL_NAMESPACE::StreamIO> (is, packed_sample_size);
+
+ // next Int64 is unpacked sample size - skip that too
+ Xdr::skip <StreamIO> (is, packed_offset_table_size+packed_sample_size+8);
+
+ }else{
+
+ int dataSize;
+ OPENEXR_IMF_INTERNAL_NAMESPACE::Xdr::read <OPENEXR_IMF_INTERNAL_NAMESPACE::StreamIO> (is, dataSize);
+
+ Xdr::skip <StreamIO> (is, dataSize);
+ }
+ if (skipOnly) continue;
- if (!isValidTile(tileX, tileY, levelX, levelY))
- return;
+ if (!isValidTile(tileX, tileY, levelX, levelY))
+ return;
- operator () (tileX, tileY, levelX, levelY) = tileOffset;
- }
- }
+ operator () (tileX, tileY, levelX, levelY) = tileOffset;
+ }
+ }
}
}
void
-TileOffsets::reconstructFromFile (IStream &is)
+TileOffsets::reconstructFromFile (OPENEXR_IMF_INTERNAL_NAMESPACE::IStream &is,bool isMultiPart,bool isDeep)
{
//
// Try to reconstruct a missing tile offset table by sequentially
try
{
- findTiles (is);
+ findTiles (is,isMultiPart,isDeep,false);
}
catch (...)
{
//
// Suppress all exceptions. This function is called only to
- // reconstruct the tile offset table for incomplete files,
- // and exceptions are likely.
+ // reconstruct the tile offset table for incomplete files,
+ // and exceptions are likely.
//
}
void
-TileOffsets::readFrom (IStream &is, bool &complete)
+TileOffsets::readFrom (OPENEXR_IMF_INTERNAL_NAMESPACE::IStream &is, bool &complete,bool isMultiPartFile, bool isDeep)
{
//
// Read in the tile offsets from the file's tile offset table
//
for (unsigned int l = 0; l < _offsets.size(); ++l)
- for (unsigned int dy = 0; dy < _offsets[l].size(); ++dy)
- for (unsigned int dx = 0; dx < _offsets[l][dy].size(); ++dx)
- Xdr::read <StreamIO> (is, _offsets[l][dy][dx]);
+ for (unsigned int dy = 0; dy < _offsets[l].size(); ++dy)
+ for (unsigned int dx = 0; dx < _offsets[l][dy].size(); ++dx)
+ OPENEXR_IMF_INTERNAL_NAMESPACE::Xdr::read <OPENEXR_IMF_INTERNAL_NAMESPACE::StreamIO> (is, _offsets[l][dy][dx]);
//
// Check if any tile offsets are invalid.
if (anyOffsetsAreInvalid())
{
- complete = false;
- reconstructFromFile (is);
+ complete = false;
+ reconstructFromFile (is,isMultiPartFile,isDeep);
}
else
{
- complete = true;
+ complete = true;
}
}
+void
+TileOffsets::readFrom (std::vector<Int64> chunkOffsets,bool &complete)
+{
+ size_t totalSize = 0;
+
+ for (unsigned int l = 0; l < _offsets.size(); ++l)
+ for (unsigned int dy = 0; dy < _offsets[l].size(); ++dy)
+ totalSize += _offsets[l][dy].size();
+
+ if (chunkOffsets.size() != totalSize)
+ throw IEX_NAMESPACE::ArgExc ("Wrong offset count, not able to read from this array");
+
+
+
+ int pos = 0;
+ for (size_t l = 0; l < _offsets.size(); ++l)
+ for (size_t dy = 0; dy < _offsets[l].size(); ++dy)
+ for (size_t dx = 0; dx < _offsets[l][dy].size(); ++dx)
+ {
+ _offsets[l][dy][dx] = chunkOffsets[pos];
+ pos++;
+ }
+
+ complete = !anyOffsetsAreInvalid();
+
+}
+
+
Int64
-TileOffsets::writeTo (OStream &os) const
+TileOffsets::writeTo (OPENEXR_IMF_INTERNAL_NAMESPACE::OStream &os) const
{
//
// Write the tile offset table to the file, and
// return the position of the start of the table
// in the file.
//
-
+
Int64 pos = os.tellp();
if (pos == -1)
- Iex::throwErrnoExc ("Cannot determine current file position (%T).");
+ IEX_NAMESPACE::throwErrnoExc ("Cannot determine current file position (%T).");
for (unsigned int l = 0; l < _offsets.size(); ++l)
- for (unsigned int dy = 0; dy < _offsets[l].size(); ++dy)
- for (unsigned int dx = 0; dx < _offsets[l][dy].size(); ++dx)
- Xdr::write <StreamIO> (os, _offsets[l][dy][dx]);
+ for (unsigned int dy = 0; dy < _offsets[l].size(); ++dy)
+ for (unsigned int dx = 0; dx < _offsets[l][dy].size(); ++dx)
+ OPENEXR_IMF_INTERNAL_NAMESPACE::Xdr::write <OPENEXR_IMF_INTERNAL_NAMESPACE::StreamIO> (os, _offsets[l][dy][dx]);
return pos;
}
+namespace {
+struct tilepos{
+ Int64 filePos;
+ int dx;
+ int dy;
+ int l;
+ bool operator <(const tilepos & other) const
+ {
+ return filePos < other.filePos;
+ }
+};
+}
+//-------------------------------------
+// fill array with tile coordinates in the order they appear in the file
+//
+// each input array must be of size (totalTiles)
+//
+//
+// if the tile order is not RANDOM_Y, it is more efficient to compute the
+// tile ordering rather than using this function
+//
+//-------------------------------------
+void TileOffsets::getTileOrder(int dx_table[],int dy_table[],int lx_table[],int ly_table[]) const
+{
+ //
+ // helper class
+ //
+
+ // how many entries?
+ size_t entries=0;
+ for (unsigned int l = 0; l < _offsets.size(); ++l)
+ for (unsigned int dy = 0; dy < _offsets[l].size(); ++dy)
+ entries+=_offsets[l][dy].size();
+
+ std::vector<struct tilepos> table(entries);
+
+ size_t i = 0;
+ for (unsigned int l = 0; l < _offsets.size(); ++l)
+ for (unsigned int dy = 0; dy < _offsets[l].size(); ++dy)
+ for (unsigned int dx = 0; dx < _offsets[l][dy].size(); ++dx)
+ {
+ table[i].filePos = _offsets[l][dy][dx];
+ table[i].dx = dx;
+ table[i].dy = dy;
+ table[i].l = l;
+
+ ++i;
+
+ }
+
+ std::sort(table.begin(),table.end());
+
+ //
+ // write out the values
+ //
+
+ // pass 1: write out dx and dy, since these are independent of level mode
+
+ for(size_t i=0;i<entries;i++)
+ {
+ dx_table[i] = table[i].dx;
+ dy_table[i] = table[i].dy;
+ }
+
+ // now write out the levels, which depend on the level mode
+
+ switch (_mode)
+ {
+ case ONE_LEVEL:
+ {
+ for(size_t i=0;i<entries;i++)
+ {
+ lx_table[i] = 0;
+ ly_table[i] = 0;
+ }
+ break;
+ }
+ case MIPMAP_LEVELS:
+ {
+ for(size_t i=0;i<entries;i++)
+ {
+ lx_table[i]= table[i].l;
+ ly_table[i] =table[i].l;
+
+ }
+ break;
+ }
+
+ case RIPMAP_LEVELS:
+ {
+ for(size_t i=0;i<entries;i++)
+ {
+ lx_table[i]= table[i].l % _numXLevels;
+ ly_table[i] = table[i].l / _numXLevels;
+
+ }
+ break;
+ }
+ case NUM_LEVELMODES :
+ throw IEX_NAMESPACE::LogicExc("Bad level mode getting tile order");
+ }
+
+
+
+}
+
bool
TileOffsets::isEmpty () const
{
for (unsigned int l = 0; l < _offsets.size(); ++l)
- for (unsigned int dy = 0; dy < _offsets[l].size(); ++dy)
- for (unsigned int dx = 0; dx < _offsets[l][dy].size(); ++dx)
- if (_offsets[l][dy][dx] != 0)
- return false;
+ for (unsigned int dy = 0; dy < _offsets[l].size(); ++dy)
+ for (unsigned int dx = 0; dx < _offsets[l][dy].size(); ++dx)
+ if (_offsets[l][dy][dx] != 0)
+ return false;
return true;
}
bool
TileOffsets::isValidTile (int dx, int dy, int lx, int ly) const
{
+ if(lx<0 || ly < 0 || dx<0 || dy < 0) return false;
switch (_mode)
{
case ONE_LEVEL:
if (lx == 0 &&
- ly == 0 &&
- _offsets.size() > 0 &&
- _offsets[0].size() > dy &&
- _offsets[0][dy].size() > dx)
- {
+ ly == 0 &&
+ _offsets.size() > 0 &&
+ int(_offsets[0].size()) > dy &&
+ int(_offsets[0][dy].size()) > dx)
+ {
return true;
- }
+ }
break;
case MIPMAP_LEVELS:
if (lx < _numXLevels &&
- ly < _numYLevels &&
- _offsets.size() > lx &&
- _offsets[lx].size() > dy &&
- _offsets[lx][dy].size() > dx)
- {
+ ly < _numYLevels &&
+ int(_offsets.size()) > lx &&
+ int(_offsets[lx].size()) > dy &&
+ int(_offsets[lx][dy].size()) > dx)
+ {
return true;
- }
+ }
break;
case RIPMAP_LEVELS:
if (lx < _numXLevels &&
- ly < _numYLevels &&
- _offsets.size() > lx + ly * _numXLevels &&
- _offsets[lx + ly * _numXLevels].size() > dy &&
- _offsets[lx + ly * _numXLevels][dy].size() > dx)
- {
+ ly < _numYLevels &&
+ (_offsets.size() > (size_t) lx+ ly * (size_t) _numXLevels) &&
+ int(_offsets[lx + ly * _numXLevels].size()) > dy &&
+ int(_offsets[lx + ly * _numXLevels][dy].size()) > dx)
+ {
return true;
- }
+ }
break;
return false;
}
-
+
return false;
}
default:
- throw Iex::ArgExc ("Unknown LevelMode format.");
+ throw IEX_NAMESPACE::ArgExc ("Unknown LevelMode format.");
}
}
default:
- throw Iex::ArgExc ("Unknown LevelMode format.");
+ throw IEX_NAMESPACE::ArgExc ("Unknown LevelMode format.");
}
}
return operator () (dx, dy, l, l);
}
+const std::vector<std::vector<std::vector <Int64> > >&
+TileOffsets::getOffsets() const
+{
+ return _offsets;
+}
+
-} // namespace Imf
+OPENEXR_IMF_INTERNAL_NAMESPACE_SOURCE_EXIT
//
// Copyright (c) 2004, Industrial Light & Magic, a division of Lucas
// Digital Ltd. LLC
-//
+//
// All rights reserved.
-//
+//
// Redistribution and use in source and binary forms, with or without
// modification, are permitted provided that the following conditions are
// met:
// distribution.
// * Neither the name of Industrial Light & Magic nor the names of
// its contributors may be used to endorse or promote products derived
-// from this software without specific prior written permission.
-//
+// from this software without specific prior written permission.
+//
// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
//
//-----------------------------------------------------------------------------
-#include <ImfTileDescription.h>
-#include <ImfInt64.h>
+#include "ImfTileDescription.h"
+#include "ImfInt64.h"
#include <vector>
+#include "ImfNamespace.h"
+#include "ImfForward.h"
+#include "ImfExport.h"
-namespace Imf {
-
-class IStream;
-class OStream;
+OPENEXR_IMF_INTERNAL_NAMESPACE_HEADER_ENTER
class TileOffsets
{
public:
+ IMF_EXPORT
TileOffsets (LevelMode mode = ONE_LEVEL,
- int numXLevels = 0,
- int numYLevels = 0,
- const int *numXTiles = 0,
- const int *numYTiles = 0);
+ int numXLevels = 0,
+ int numYLevels = 0,
+ const int *numXTiles = 0,
+ const int *numYTiles = 0);
// --------
// File I/O
// --------
- void readFrom (IStream &is, bool &complete);
- Int64 writeTo (OStream &os) const;
+ IMF_EXPORT
+ void readFrom (OPENEXR_IMF_INTERNAL_NAMESPACE::IStream &is, bool &complete,bool isMultiPart,bool isDeep);
+ IMF_EXPORT
+ void readFrom (std::vector<Int64> chunkOffsets,bool &complete);
+ IMF_EXPORT
+ Int64 writeTo (OPENEXR_IMF_INTERNAL_NAMESPACE::OStream &os) const;
//-----------------------------------------------------------
// Test if the tileOffsets array is empty (all entries are 0)
//-----------------------------------------------------------
+ IMF_EXPORT
bool isEmpty () const;
-
-
+
+
+
+ //-----------------------------------------------------------
+ // populate 'list' with tiles coordinates in the order they appear
+ // in the offset table (assumes full table!
+ // each array myst be at leat totalTiles long
+ //-----------------------------------------------------------
+ IMF_EXPORT
+ void getTileOrder(int dx_table[], int dy_table[], int lx_table[], int ly_table[]) const;
+
+
//-----------------------
// Access to the elements
//-----------------------
+ IMF_EXPORT
Int64 & operator () (int dx, int dy, int lx, int ly);
+ IMF_EXPORT
Int64 & operator () (int dx, int dy, int l);
+ IMF_EXPORT
const Int64 & operator () (int dx, int dy, int lx, int ly) const;
+ IMF_EXPORT
const Int64 & operator () (int dx, int dy, int l) const;
-
+ IMF_EXPORT
+ bool isValidTile (int dx, int dy, int lx, int ly) const;
+ IMF_EXPORT
+ const std::vector<std::vector<std::vector <Int64> > >& getOffsets() const;
+
private:
- void findTiles (IStream &is);
- void reconstructFromFile (IStream &is);
- bool readTile (IStream &is);
+ void findTiles (OPENEXR_IMF_INTERNAL_NAMESPACE::IStream &is, bool isMultiPartFile,
+ bool isDeep,
+ bool skipOnly);
+ void reconstructFromFile (OPENEXR_IMF_INTERNAL_NAMESPACE::IStream &is,bool isMultiPartFile,bool isDeep);
+ bool readTile (OPENEXR_IMF_INTERNAL_NAMESPACE::IStream &is);
bool anyOffsetsAreInvalid () const;
- bool isValidTile (int dx, int dy, int lx, int ly) const;
LevelMode _mode;
int _numXLevels;
int _numYLevels;
std::vector<std::vector<std::vector <Int64> > > _offsets;
+
};
-} // namespace Imf
+OPENEXR_IMF_INTERNAL_NAMESPACE_HEADER_EXIT
+
+
+
+
#endif
//
// Copyright (c) 2004, Industrial Light & Magic, a division of Lucas
// Digital Ltd. LLC
-//
+//
// All rights reserved.
-//
+//
// Redistribution and use in source and binary forms, with or without
// modification, are permitted provided that the following conditions are
// met:
// distribution.
// * Neither the name of Industrial Light & Magic nor the names of
// its contributors may be used to endorse or promote products derived
-// from this software without specific prior written permission.
-//
+// from this software without specific prior written permission.
+//
// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
//
//-----------------------------------------------------------------------------
-#include <ImfTiledInputFile.h>
-#include <ImfTileDescriptionAttribute.h>
-#include <ImfChannelList.h>
-#include <ImfMisc.h>
-#include <ImfTiledMisc.h>
-#include <ImfStdIO.h>
-#include <ImfCompressor.h>
-#include "ImathBox.h"
-#include <ImfXdr.h>
-#include <ImfConvert.h>
-#include <ImfVersion.h>
-#include <ImfTileOffsets.h>
-#include <ImfThreading.h>
+#include "ImfTiledInputFile.h"
+#include "ImfTileDescriptionAttribute.h"
+#include "ImfChannelList.h"
+#include "ImfMisc.h"
+#include "ImfTiledMisc.h"
+#include "ImfStdIO.h"
+#include "ImfCompressor.h"
+#include "ImfXdr.h"
+#include "ImfConvert.h"
+#include "ImfVersion.h"
+#include "ImfTileOffsets.h"
+#include "ImfThreading.h"
+#include "ImfPartType.h"
+#include "ImfMultiPartInputFile.h"
+#include "ImfInputStreamMutex.h"
#include "IlmThreadPool.h"
#include "IlmThreadSemaphore.h"
#include "IlmThreadMutex.h"
#include <vector>
#include <algorithm>
#include <assert.h>
+#include "ImfInputPartData.h"
+#include "ImfNamespace.h"
+OPENEXR_IMF_INTERNAL_NAMESPACE_SOURCE_ENTER
-namespace Imf {
-
-using Imath::Box2i;
-using Imath::V2i;
+using IMATH_NAMESPACE::Box2i;
+using IMATH_NAMESPACE::V2i;
using std::string;
using std::vector;
using std::min;
using std::max;
-using IlmThread::Mutex;
-using IlmThread::Lock;
-using IlmThread::Semaphore;
-using IlmThread::Task;
-using IlmThread::TaskGroup;
-using IlmThread::ThreadPool;
+using ILMTHREAD_NAMESPACE::Mutex;
+using ILMTHREAD_NAMESPACE::Lock;
+using ILMTHREAD_NAMESPACE::Semaphore;
+using ILMTHREAD_NAMESPACE::Task;
+using ILMTHREAD_NAMESPACE::TaskGroup;
+using ILMTHREAD_NAMESPACE::ThreadPool;
namespace {
TileBuffer::TileBuffer (Compressor *comp):
uncompressedData (0),
+ buffer (0),
dataSize (0),
compressor (comp),
format (defaultFormat (compressor)),
} // namespace
+class MultiPartInputFile;
+
+
//
// struct TiledInputFile::Data stores things that will be
// needed between calls to readTile()
struct TiledInputFile::Data: public Mutex
{
- Header header; // the image header
- TileDescription tileDesc; // describes the tile layout
- int version; // file's version
- FrameBuffer frameBuffer; // framebuffer to write into
- LineOrder lineOrder; // the file's lineorder
- int minX; // data window's min x coord
- int maxX; // data window's max x coord
- int minY; // data window's min y coord
- int maxY; // data window's max x coord
+ Header header; // the image header
+ TileDescription tileDesc; // describes the tile layout
+ int version; // file's version
+ FrameBuffer frameBuffer; // framebuffer to write into
+ LineOrder lineOrder; // the file's lineorder
+ int minX; // data window's min x coord
+ int maxX; // data window's max x coord
+ int minY; // data window's min y coord
+ int maxY; // data window's max x coord
- int numXLevels; // number of x levels
- int numYLevels; // number of y levels
- int * numXTiles; // number of x tiles at a level
- int * numYTiles; // number of y tiles at a level
+ int numXLevels; // number of x levels
+ int numYLevels; // number of y levels
+ int * numXTiles; // number of x tiles at a level
+ int * numYTiles; // number of y tiles at a level
- TileOffsets tileOffsets; // stores offsets in file for
- // each tile
+ TileOffsets tileOffsets; // stores offsets in file for
+ // each tile
- bool fileIsComplete; // True if no tiles are missing
- // in the file
+ bool fileIsComplete; // True if no tiles are missing
+ // in the file
- Int64 currentPosition; // file offset for current tile,
- // used to prevent unnecessary
- // seeking
+ vector<TInSliceInfo> slices; // info about channels in file
- vector<TInSliceInfo> slices; // info about channels in file
- IStream * is; // file stream to read from
+ size_t bytesPerPixel; // size of an uncompressed pixel
- bool deleteStream; // should we delete the stream
- // ourselves? or does someone
- // else do it?
+ size_t maxBytesPerTileLine; // combined size of a line
+ // over all channels
- size_t bytesPerPixel; // size of an uncompressed pixel
+ int partNumber; // part number
- size_t maxBytesPerTileLine; // combined size of a line
- // over all channels
+ bool multiPartBackwardSupport; // if we are reading a multipart file
+ // using OpenEXR 1.7 API
+ int numThreads; // number of threads
- vector<TileBuffer*> tileBuffers; // each holds a single tile
- size_t tileBufferSize; // size of the tile buffers
+ MultiPartInputFile* multiPartFile; // the MultiPartInputFile used to
+ // support backward compatibility
+
+ vector<TileBuffer*> tileBuffers; // each holds a single tile
+ size_t tileBufferSize; // size of the tile buffers
- Data (bool deleteStream, int numThreads);
+ bool memoryMapped; // if the stream is memory mapped
+
+ InputStreamMutex * _streamData;
+ bool _deleteStream;
+
+ Data (int numThreads);
~Data ();
inline TileBuffer * getTileBuffer (int number);
- // hash function from tile indices
- // into our vector of tile buffers
+ // hash function from tile indices
+ // into our vector of tile buffers
};
-TiledInputFile::Data::Data (bool del, int numThreads):
+TiledInputFile::Data::Data (int numThreads):
numXTiles (0),
numYTiles (0),
- is (0),
- deleteStream (del)
+ partNumber (-1),
+ multiPartBackwardSupport(false),
+ numThreads(numThreads),
+ memoryMapped(false),
+ _streamData(NULL),
+ _deleteStream(false)
{
//
// We need at least one tileBuffer, but if threading is used,
delete [] numXTiles;
delete [] numYTiles;
- if (deleteStream)
- delete is;
-
for (size_t i = 0; i < tileBuffers.size(); i++)
delete tileBuffers[i];
+
+ if (multiPartBackwardSupport)
+ delete multiPartFile;
}
namespace {
void
-readTileData (TiledInputFile::Data *ifd,
- int dx, int dy,
- int lx, int ly,
+readTileData (InputStreamMutex *streamData,
+ TiledInputFile::Data *ifd,
+ int dx, int dy,
+ int lx, int ly,
char *&buffer,
int &dataSize)
{
// Look up the location for this tile in the Index and
// seek to that position if necessary
//
-
+
Int64 tileOffset = ifd->tileOffsets (dx, dy, lx, ly);
if (tileOffset == 0)
{
- THROW (Iex::InputExc, "Tile (" << dx << ", " << dy << ", " <<
- lx << ", " << ly << ") is missing.");
+ THROW (IEX_NAMESPACE::InputExc, "Tile (" << dx << ", " << dy << ", " <<
+ lx << ", " << ly << ") is missing.");
}
- if (ifd->currentPosition != tileOffset)
- ifd->is->seekg (tileOffset);
+
+ //
+ // In a multi-part file, the next chunk does not need to
+ // belong to the same part, so we have to compare the
+ // offset here.
+ //
+
+ if (!isMultiPart(ifd->version))
+ {
+ if (streamData->currentPosition != tileOffset)
+ streamData->is->seekg (tileOffset);
+ }
+ else
+ {
+ //
+ // In a multi-part file, the file pointer may be moved by other
+ // parts, so we have to ask tellg() where we are.
+ //
+ if (streamData->is->tellg() != tileOffset)
+ streamData->is->seekg (tileOffset);
+ }
//
// Read the first few bytes of the tile (the header).
// Verify that the tile coordinates and the level number
// are correct.
//
-
+
int tileXCoord, tileYCoord, levelX, levelY;
- Xdr::read <StreamIO> (*ifd->is, tileXCoord);
- Xdr::read <StreamIO> (*ifd->is, tileYCoord);
- Xdr::read <StreamIO> (*ifd->is, levelX);
- Xdr::read <StreamIO> (*ifd->is, levelY);
- Xdr::read <StreamIO> (*ifd->is, dataSize);
+ if (isMultiPart(ifd->version))
+ {
+ int partNumber;
+ Xdr::read <StreamIO> (*streamData->is, partNumber);
+ if (partNumber != ifd->partNumber)
+ {
+ THROW (IEX_NAMESPACE::ArgExc, "Unexpected part number " << partNumber
+ << ", should be " << ifd->partNumber << ".");
+ }
+ }
+
+ OPENEXR_IMF_INTERNAL_NAMESPACE::Xdr::read <OPENEXR_IMF_INTERNAL_NAMESPACE::StreamIO> (*streamData->is, tileXCoord);
+ OPENEXR_IMF_INTERNAL_NAMESPACE::Xdr::read <OPENEXR_IMF_INTERNAL_NAMESPACE::StreamIO> (*streamData->is, tileYCoord);
+ OPENEXR_IMF_INTERNAL_NAMESPACE::Xdr::read <OPENEXR_IMF_INTERNAL_NAMESPACE::StreamIO> (*streamData->is, levelX);
+ OPENEXR_IMF_INTERNAL_NAMESPACE::Xdr::read <OPENEXR_IMF_INTERNAL_NAMESPACE::StreamIO> (*streamData->is, levelY);
+ OPENEXR_IMF_INTERNAL_NAMESPACE::Xdr::read <OPENEXR_IMF_INTERNAL_NAMESPACE::StreamIO> (*streamData->is, dataSize);
if (tileXCoord != dx)
- throw Iex::InputExc ("Unexpected tile x coordinate.");
+ throw IEX_NAMESPACE::InputExc ("Unexpected tile x coordinate.");
if (tileYCoord != dy)
- throw Iex::InputExc ("Unexpected tile y coordinate.");
+ throw IEX_NAMESPACE::InputExc ("Unexpected tile y coordinate.");
if (levelX != lx)
- throw Iex::InputExc ("Unexpected tile x level number coordinate.");
+ throw IEX_NAMESPACE::InputExc ("Unexpected tile x level number coordinate.");
if (levelY != ly)
- throw Iex::InputExc ("Unexpected tile y level number coordinate.");
+ throw IEX_NAMESPACE::InputExc ("Unexpected tile y level number coordinate.");
if (dataSize > (int) ifd->tileBufferSize)
- throw Iex::InputExc ("Unexpected tile block length.");
+ throw IEX_NAMESPACE::InputExc ("Unexpected tile block length.");
//
// Read the pixel data.
//
- if (ifd->is->isMemoryMapped ())
- buffer = ifd->is->readMemoryMapped (dataSize);
+ if (streamData->is->isMemoryMapped ())
+ buffer = streamData->is->readMemoryMapped (dataSize);
else
- ifd->is->read (buffer, dataSize);
+ streamData->is->read (buffer, dataSize);
//
// Keep track of which tile is the next one in
// the file, so that we can avoid redundant seekg()
// operations (seekg() can be fairly expensive).
//
-
- ifd->currentPosition = tileOffset + 5 * Xdr::size<int>() + dataSize;
+
+ streamData->currentPosition = tileOffset + 5 * Xdr::size<int>() + dataSize;
}
void
-readNextTileData (TiledInputFile::Data *ifd,
- int &dx, int &dy,
- int &lx, int &ly,
+readNextTileData (InputStreamMutex *streamData,
+ TiledInputFile::Data *ifd,
+ int &dx, int &dy,
+ int &lx, int &ly,
char * & buffer,
- int &dataSize)
+ int &dataSize)
{
//
// Read the next tile block from the file
//
+ if(isMultiPart(ifd->version))
+ {
+ int part;
+ Xdr::read <StreamIO> (*streamData->is, part);
+ if(part!=ifd->partNumber)
+ {
+ throw IEX_NAMESPACE::InputExc("Unexpected part number in readNextTileData");
+ }
+ }
+
//
// Read the first few bytes of the tile (the header).
//
- Xdr::read <StreamIO> (*ifd->is, dx);
- Xdr::read <StreamIO> (*ifd->is, dy);
- Xdr::read <StreamIO> (*ifd->is, lx);
- Xdr::read <StreamIO> (*ifd->is, ly);
- Xdr::read <StreamIO> (*ifd->is, dataSize);
+ Xdr::read <StreamIO> (*streamData->is, dx);
+ Xdr::read <StreamIO> (*streamData->is, dy);
+ Xdr::read <StreamIO> (*streamData->is, lx);
+ Xdr::read <StreamIO> (*streamData->is, ly);
+ Xdr::read <StreamIO> (*streamData->is, dataSize);
if (dataSize > (int) ifd->tileBufferSize)
- throw Iex::InputExc ("Unexpected tile block length.");
-
+ throw IEX_NAMESPACE::InputExc ("Unexpected tile block length.");
+
//
// Read the pixel data.
//
- ifd->is->read (buffer, dataSize);
-
+ streamData->is->read (buffer, dataSize);
+
//
// Keep track of which tile is the next one in
// the file, so that we can avoid redundant seekg()
// operations (seekg() can be fairly expensive).
//
- ifd->currentPosition += 5 * Xdr::size<int>() + dataSize;
+ streamData->currentPosition += 5 * Xdr::size<int>() + dataSize;
}
TileBufferTask (TaskGroup *group,
TiledInputFile::Data *ifd,
- TileBuffer *tileBuffer);
-
+ TileBuffer *tileBuffer);
+
virtual ~TileBufferTask ();
virtual void execute ();
-
+
private:
TiledInputFile::Data * _ifd;
//
// Calculate information about the tile
//
-
- Box2i tileRange = Imf::dataWindowForTile (_ifd->tileDesc,
- _ifd->minX, _ifd->maxX,
- _ifd->minY, _ifd->maxY,
- _tileBuffer->dx,
- _tileBuffer->dy,
- _tileBuffer->lx,
- _tileBuffer->ly);
+
+ Box2i tileRange = OPENEXR_IMF_INTERNAL_NAMESPACE::dataWindowForTile (
+ _ifd->tileDesc,
+ _ifd->minX, _ifd->maxX,
+ _ifd->minY, _ifd->maxY,
+ _tileBuffer->dx,
+ _tileBuffer->dy,
+ _tileBuffer->lx,
+ _tileBuffer->ly);
int numPixelsPerScanLine = tileRange.max.x - tileRange.min.x + 1;
-
+
int numPixelsInTile = numPixelsPerScanLine *
(tileRange.max.y - tileRange.min.y + 1);
-
+
int sizeOfTile = _ifd->bytesPerPixel * numPixelsInTile;
-
-
+
+
//
// Uncompress the data, if necessary
//
-
+
if (_tileBuffer->compressor && _tileBuffer->dataSize < sizeOfTile)
{
_tileBuffer->format = _tileBuffer->compressor->format();
_tileBuffer->dataSize = _tileBuffer->compressor->uncompressTile
- (_tileBuffer->buffer, _tileBuffer->dataSize,
- tileRange, _tileBuffer->uncompressedData);
+ (_tileBuffer->buffer, _tileBuffer->dataSize,
+ tileRange, _tileBuffer->uncompressedData);
}
else
{
// If the line is uncompressed, it's in XDR format,
// regardless of the compressor's output format.
//
-
+
_tileBuffer->format = Compressor::XDR;
_tileBuffer->uncompressedData = _tileBuffer->buffer;
}
-
+
//
// Convert the tile of pixel data back from the machine-independent
- // representation, and store the result in the frame buffer.
+ // representation, and store the result in the frame buffer.
//
-
+
const char *readPtr = _tileBuffer->uncompressedData;
// points to where we
// read from in the
// tile block
-
+
//
// Iterate over the scan lines in the tile.
//
-
+
for (int y = tileRange.min.y; y <= tileRange.max.y; ++y)
{
//
// Iterate over all image channels.
//
-
+
for (unsigned int i = 0; i < _ifd->slices.size(); ++i)
{
const TInSliceInfo &slice = _ifd->slices[i];
-
+
//
// These offsets are used to facilitate both
// absolute and tile-relative pixel coordinates.
//
-
+
int xOffset = slice.xTileCoords * tileRange.min.x;
int yOffset = slice.yTileCoords * tileRange.min.y;
-
+
//
// Fill the frame buffer with pixel data.
//
-
+
if (slice.skip)
{
//
// The file contains data for this channel, but
// the frame buffer contains no slice for this channel.
//
-
+
skipChannel (readPtr, slice.typeInFile,
numPixelsPerScanLine);
}
//
// The frame buffer contains a slice for this channel.
//
-
+
char *writePtr = slice.base +
(y - yOffset) * slice.yStride +
(tileRange.min.x - xOffset) *
char *endPtr = writePtr +
(numPixelsPerScanLine - 1) * slice.xStride;
-
+
copyIntoFrameBuffer (readPtr, writePtr, endPtr,
slice.xStride,
slice.fill, slice.fillValue,
TileBufferTask *
newTileBufferTask
(TaskGroup *group,
+ InputStreamMutex *streamData,
TiledInputFile::Data *ifd,
int number,
int dx, int dy,
try
{
- tileBuffer->wait();
-
- tileBuffer->dx = dx;
- tileBuffer->dy = dy;
- tileBuffer->lx = lx;
- tileBuffer->ly = ly;
-
- tileBuffer->uncompressedData = 0;
-
- readTileData (ifd, dx, dy, lx, ly,
- tileBuffer->buffer,
- tileBuffer->dataSize);
+ tileBuffer->wait();
+
+ tileBuffer->dx = dx;
+ tileBuffer->dy = dy;
+ tileBuffer->lx = lx;
+ tileBuffer->ly = ly;
+
+ tileBuffer->uncompressedData = 0;
+
+ readTileData (streamData, ifd, dx, dy, lx, ly,
+ tileBuffer->buffer,
+ tileBuffer->dataSize);
}
catch (...)
{
- //
- // Reading from the file caused an exception.
- // Signal that the tile buffer is free, and
- // re-throw the exception.
- //
-
- tileBuffer->post();
- throw;
+ //
+ // Reading from the file caused an exception.
+ // Signal that the tile buffer is free, and
+ // re-throw the exception.
+ //
+
+ tileBuffer->post();
+ throw;
}
return new TileBufferTask (group, ifd, tileBuffer);
TiledInputFile::TiledInputFile (const char fileName[], int numThreads):
- _data (new Data (true, numThreads))
+ _data (new Data (numThreads))
{
+ _data->_streamData=NULL;
+ _data->_deleteStream=true;
+
//
// This constructor is called when a user
// explicitly wants to read a tiled file.
//
+
+ IStream* is = 0;
try
{
- _data->is = new StdIFStream (fileName);
- _data->header.readFrom (*_data->is, _data->version);
- initialize();
+ is = new StdIFStream (fileName);
+ readMagicNumberAndVersionField(*is, _data->version);
+
+ //
+ // Backward compatibility to read multpart file.
+ //
+ if (isMultiPart(_data->version))
+ {
+ compatibilityInitialize(*is);
+ return;
+ }
+
+ _data->_streamData = new InputStreamMutex();
+ _data->_streamData->is = is;
+ _data->header.readFrom (*_data->_streamData->is, _data->version);
+ initialize();
+ //read tile offsets - we are not multipart or deep
+ _data->tileOffsets.readFrom (*(_data->_streamData->is), _data->fileIsComplete,false,false);
+ _data->_streamData->currentPosition = _data->_streamData->is->tellg();
}
- catch (Iex::BaseExc &e)
+ catch (IEX_NAMESPACE::BaseExc &e)
{
- delete _data;
+ if (_data->_streamData != 0)
+ {
+ if (_data->_streamData->is != 0)
+ {
+ delete _data->_streamData->is;
+ _data->_streamData->is = is = 0;
+ }
- REPLACE_EXC (e, "Cannot open image file "
- "\"" << fileName << "\". " << e);
- throw;
+ delete _data->_streamData;
+ }
+
+ if (is != 0)
+ delete is;
+
+ REPLACE_EXC (e, "Cannot open image file "
+ "\"" << fileName << "\". " << e.what());
+ throw;
}
catch (...)
{
- delete _data;
+ if ( _data->_streamData != 0)
+ {
+ if ( _data->_streamData->is != 0)
+ {
+ delete _data->_streamData->is;
+ _data->_streamData->is = is = 0;
+ }
+
+ delete _data->_streamData;
+ }
+
+ if (is != 0)
+ delete is;
throw;
}
}
-TiledInputFile::TiledInputFile (IStream &is, int numThreads):
- _data (new Data (false, numThreads))
+TiledInputFile::TiledInputFile (OPENEXR_IMF_INTERNAL_NAMESPACE::IStream &is, int numThreads):
+ _data (new Data (numThreads))
{
+ _data->_deleteStream=false;
//
// This constructor is called when a user
// explicitly wants to read a tiled file.
//
+ bool streamDataCreated = false;
+
try
{
- _data->is = &is;
- _data->header.readFrom (*_data->is, _data->version);
- initialize();
+ readMagicNumberAndVersionField(is, _data->version);
+
+ //
+ // Backward compatibility to read multpart file.
+ //
+ if (isMultiPart(_data->version))
+ {
+ compatibilityInitialize(is);
+ return;
+ }
+
+ streamDataCreated = true;
+ _data->_streamData = new InputStreamMutex();
+ _data->_streamData->is = &is;
+ _data->header.readFrom (*_data->_streamData->is, _data->version);
+ initialize();
+ // file is guaranteed to be single part, regular image
+ _data->tileOffsets.readFrom (*(_data->_streamData->is), _data->fileIsComplete,false,false);
+ _data->memoryMapped = _data->_streamData->is->isMemoryMapped();
+ _data->_streamData->currentPosition = _data->_streamData->is->tellg();
}
- catch (Iex::BaseExc &e)
+ catch (IEX_NAMESPACE::BaseExc &e)
{
- delete _data;
+ if (streamDataCreated) delete _data->_streamData;
+ delete _data;
- REPLACE_EXC (e, "Cannot open image file "
- "\"" << is.fileName() << "\". " << e);
- throw;
+ REPLACE_EXC (e, "Cannot open image file "
+ "\"" << is.fileName() << "\". " << e.what());
+ throw;
}
catch (...)
{
- delete _data;
+ if (streamDataCreated) delete _data->_streamData;
+ delete _data;
throw;
}
}
-TiledInputFile::TiledInputFile
- (const Header &header,
- IStream *is,
- int version,
- int numThreads)
-:
- _data (new Data (false, numThreads))
+TiledInputFile::TiledInputFile (const Header &header,
+ OPENEXR_IMF_INTERNAL_NAMESPACE::IStream *is,
+ int version,
+ int numThreads) :
+ _data (new Data (numThreads))
{
+ _data->_deleteStream=false;
+ _data->_streamData = new InputStreamMutex();
//
// This constructor called by class Imf::InputFile
// when a user wants to just read an image file, and
// doesn't care or know if the file is tiled.
+ // No need to have backward compatibility here, because
+ // we have somehow got the header.
//
- _data->is = is;
+ _data->_streamData->is = is;
_data->header = header;
_data->version = version;
initialize();
+ _data->tileOffsets.readFrom (*(_data->_streamData->is),_data->fileIsComplete,false,false);
+ _data->memoryMapped = is->isMemoryMapped();
+ _data->_streamData->currentPosition = _data->_streamData->is->tellg();
+}
+
+
+TiledInputFile::TiledInputFile (InputPartData* part)
+{
+ _data = new Data (part->numThreads);
+ _data->_deleteStream=false;
+ multiPartInitialize(part);
}
void
-TiledInputFile::initialize ()
+TiledInputFile::compatibilityInitialize(OPENEXR_IMF_INTERNAL_NAMESPACE::IStream& is)
{
- if (!isTiled (_data->version))
- throw Iex::ArgExc ("Expected a tiled file but the file is not tiled.");
+ is.seekg(0);
+ //
+ // Construct a MultiPartInputFile, initialize TiledInputFile
+ // with the part 0 data.
+ // (TODO) maybe change the third parameter of the constructor of MultiPartInputFile later.
+ //
+ _data->multiPartBackwardSupport = true;
+ _data->multiPartFile = new MultiPartInputFile(is, _data->numThreads);
+ InputPartData* part = _data->multiPartFile->getPart(0);
+ multiPartInitialize(part);
+}
+
+
+void
+TiledInputFile::multiPartInitialize(InputPartData* part)
+{
+ if (part->header.type() != TILEDIMAGE)
+ throw IEX_NAMESPACE::ArgExc("Can't build a TiledInputFile from a type-mismatched part.");
+
+ _data->_streamData = part->mutex;
+ _data->header = part->header;
+ _data->version = part->version;
+ _data->partNumber = part->partNumber;
+ _data->memoryMapped = _data->_streamData->is->isMemoryMapped();
+ initialize();
+ _data->tileOffsets.readFrom(part->chunkOffsets,_data->fileIsComplete);
+ _data->_streamData->currentPosition = _data->_streamData->is->tellg();
+}
+
+
+void
+TiledInputFile::initialize ()
+{
+ // fix bad types in header (arises when a tool built against an older version of
+ // OpenEXR converts a scanline image to tiled)
+ // only applies when file is a single part, regular image, tiled file
+ //
+ if(!isMultiPart(_data->version) &&
+ !isNonImage(_data->version) &&
+ isTiled(_data->version) &&
+ _data->header.hasType() )
+ {
+ _data->header.setType(TILEDIMAGE);
+ }
+
+ if (_data->partNumber == -1)
+ {
+ if (!isTiled (_data->version))
+ throw IEX_NAMESPACE::ArgExc ("Expected a tiled file but the file is not tiled.");
+
+ }
+ else
+ {
+ if(_data->header.hasType() && _data->header.type()!=TILEDIMAGE)
+ {
+ throw IEX_NAMESPACE::ArgExc ("TiledInputFile used for non-tiledimage part.");
+ }
+ }
+
_data->header.sanityCheck (true);
_data->tileDesc = _data->header.tileDescription();
//
// Save the dataWindow information
//
-
+
const Box2i &dataWindow = _data->header.dataWindow();
_data->minX = dataWindow.min.x;
_data->maxX = dataWindow.max.x;
//
precalculateTileInfo (_data->tileDesc,
- _data->minX, _data->maxX,
- _data->minY, _data->maxY,
- _data->numXTiles, _data->numYTiles,
- _data->numXLevels, _data->numYLevels);
+ _data->minX, _data->maxX,
+ _data->minY, _data->maxY,
+ _data->numXTiles, _data->numYTiles,
+ _data->numXLevels, _data->numYLevels);
_data->bytesPerPixel = calculateBytesPerPixel (_data->header);
for (size_t i = 0; i < _data->tileBuffers.size(); i++)
{
_data->tileBuffers[i] = new TileBuffer (newTileCompressor
- (_data->header.compression(),
- _data->maxBytesPerTileLine,
- _data->tileDesc.ySize,
- _data->header));
+ (_data->header.compression(),
+ _data->maxBytesPerTileLine,
+ _data->tileDesc.ySize,
+ _data->header));
- if (!_data->is->isMemoryMapped ())
+ if (!_data->_streamData->is->isMemoryMapped ())
_data->tileBuffers[i]->buffer = new char [_data->tileBufferSize];
}
_data->tileOffsets = TileOffsets (_data->tileDesc.mode,
- _data->numXLevels,
- _data->numYLevels,
- _data->numXTiles,
- _data->numYTiles);
-
- _data->tileOffsets.readFrom (*(_data->is), _data->fileIsComplete);
-
- _data->currentPosition = _data->is->tellg();
+ _data->numXLevels,
+ _data->numYLevels,
+ _data->numXTiles,
+ _data->numYTiles);
}
TiledInputFile::~TiledInputFile ()
{
- if (!_data->is->isMemoryMapped())
+ if (!_data->memoryMapped)
for (size_t i = 0; i < _data->tileBuffers.size(); i++)
delete [] _data->tileBuffers[i]->buffer;
+ if (_data->_deleteStream)
+ delete _data->_streamData->is;
+
+ if (_data->partNumber == -1)
+ delete _data->_streamData;
+
delete _data;
}
const char *
TiledInputFile::fileName () const
{
- return _data->is->fileName();
+ return _data->_streamData->is->fileName();
}
}
-void
+void
TiledInputFile::setFrameBuffer (const FrameBuffer &frameBuffer)
{
- Lock lock (*_data);
+ Lock lock (*_data->_streamData);
//
// Set the frame buffer
if (i.channel().xSampling != j.slice().xSampling ||
i.channel().ySampling != j.slice().ySampling)
- THROW (Iex::ArgExc, "X and/or y subsampling factors "
- "of \"" << i.name() << "\" channel "
- "of input file \"" << fileName() << "\" are "
- "not compatible with the frame buffer's "
- "subsampling factors.");
+ THROW (IEX_NAMESPACE::ArgExc, "X and/or y subsampling factors "
+ "of \"" << i.name() << "\" channel "
+ "of input file \"" << fileName() << "\" are "
+ "not compatible with the frame buffer's "
+ "subsampling factors.");
}
//
//
slices.push_back (TInSliceInfo (i.channel().type,
- i.channel().type,
- 0, // base
- 0, // xStride
- 0, // yStride
- false, // fill
- true, // skip
- 0.0)); // fillValue
+ i.channel().type,
+ 0, // base
+ 0, // xStride
+ 0, // yStride
+ false, // fill
+ true, // skip
+ 0.0)); // fillValue
++i;
}
while (i != channels.end())
{
- //
- // Channel i is present in the file but not
- // in the frame buffer; data for channel i
- // will be skipped during readPixels().
- //
-
- slices.push_back (TInSliceInfo (i.channel().type,
- i.channel().type,
- 0, // base
- 0, // xStride
- 0, // yStride
- false, // fill
- true, // skip
- 0.0)); // fillValue
- ++i;
+ //
+ // Channel i is present in the file but not
+ // in the frame buffer; data for channel i
+ // will be skipped during readPixels().
+ //
+
+ slices.push_back (TInSliceInfo (i.channel().type,
+ i.channel().type,
+ 0, // base
+ 0, // xStride
+ 0, // yStride
+ false, // fill
+ true, // skip
+ 0.0)); // fillValue
+ ++i;
}
//
const FrameBuffer &
TiledInputFile::frameBuffer () const
{
- Lock lock (*_data);
+ Lock lock (*_data->_streamData);
return _data->frameBuffer;
}
try
{
- Lock lock (*_data);
+ Lock lock (*_data->_streamData);
if (_data->slices.size() == 0)
- throw Iex::ArgExc ("No frame buffer specified "
- "as pixel data destination.");
+ throw IEX_NAMESPACE::ArgExc ("No frame buffer specified "
+ "as pixel data destination.");
+
+ if (!isValidLevel (lx, ly))
+ THROW (IEX_NAMESPACE::ArgExc,
+ "Level coordinate "
+ "(" << lx << ", " << ly << ") "
+ "is invalid.");
//
// Determine the first and last tile coordinates in both dimensions.
// We always attempt to read the range of tiles in the order that
// they are stored in the file.
//
-
+
if (dx1 > dx2)
std::swap (dx1, dx2);
-
+
if (dy1 > dy2)
std::swap (dy1, dy2);
-
+
int dyStart = dy1;
- int dyStop = dy2 + 1;
- int dY = 1;
+ int dyStop = dy2 + 1;
+ int dY = 1;
if (_data->lineOrder == DECREASING_Y)
{
//
// Create a task group for all tile buffer tasks. When the
- // task group goes out of scope, the destructor waits until
- // all tasks are complete.
+ // task group goes out of scope, the destructor waits until
+ // all tasks are complete.
//
-
+
{
TaskGroup taskGroup;
int tileNumber = 0;
-
+
for (int dy = dyStart; dy != dyStop; dy += dY)
{
for (int dx = dx1; dx <= dx2; dx++)
{
if (!isValidTile (dx, dy, lx, ly))
- THROW (Iex::ArgExc,
- "Tile (" << dx << ", " << dy << ", " <<
- lx << "," << ly << ") is not a valid tile.");
-
+ THROW (IEX_NAMESPACE::ArgExc,
+ "Tile (" << dx << ", " << dy << ", " <<
+ lx << "," << ly << ") is not a valid tile.");
+
ThreadPool::addGlobalTask (newTileBufferTask (&taskGroup,
+ _data->_streamData,
_data,
tileNumber++,
dx, dy,
}
}
- //
+ //
// finish all tasks
- //
+ //
}
- //
- // Exeption handling:
- //
- // TileBufferTask::execute() may have encountered exceptions, but
- // those exceptions occurred in another thread, not in the thread
- // that is executing this call to TiledInputFile::readTiles().
- // TileBufferTask::execute() has caught all exceptions and stored
- // the exceptions' what() strings in the tile buffers.
- // Now we check if any tile buffer contains a stored exception; if
- // this is the case then we re-throw the exception in this thread.
- // (It is possible that multiple tile buffers contain stored
- // exceptions. We re-throw the first exception we find and
- // ignore all others.)
- //
-
- const string *exception = 0;
-
- for (int i = 0; i < _data->tileBuffers.size(); ++i)
- {
+ //
+ // Exeption handling:
+ //
+ // TileBufferTask::execute() may have encountered exceptions, but
+ // those exceptions occurred in another thread, not in the thread
+ // that is executing this call to TiledInputFile::readTiles().
+ // TileBufferTask::execute() has caught all exceptions and stored
+ // the exceptions' what() strings in the tile buffers.
+ // Now we check if any tile buffer contains a stored exception; if
+ // this is the case then we re-throw the exception in this thread.
+ // (It is possible that multiple tile buffers contain stored
+ // exceptions. We re-throw the first exception we find and
+ // ignore all others.)
+ //
+
+ const string *exception = 0;
+
+ for (size_t i = 0; i < _data->tileBuffers.size(); ++i)
+ {
TileBuffer *tileBuffer = _data->tileBuffers[i];
- if (tileBuffer->hasException && !exception)
- exception = &tileBuffer->exception;
+ if (tileBuffer->hasException && !exception)
+ exception = &tileBuffer->exception;
- tileBuffer->hasException = false;
- }
+ tileBuffer->hasException = false;
+ }
- if (exception)
- throw Iex::IoExc (*exception);
+ if (exception)
+ throw IEX_NAMESPACE::IoExc (*exception);
}
- catch (Iex::BaseExc &e)
+ catch (IEX_NAMESPACE::BaseExc &e)
{
REPLACE_EXC (e, "Error reading pixel data from image "
- "file \"" << fileName() << "\". " << e);
+ "file \"" << fileName() << "\". " << e.what());
throw;
}
}
-void
+void
TiledInputFile::readTiles (int dx1, int dx2, int dy1, int dy2, int l)
{
readTiles (dx1, dx2, dy1, dy2, l, l);
}
-void
+void
TiledInputFile::readTile (int dx, int dy, int lx, int ly)
{
readTiles (dx, dx, dy, dy, lx, ly);
}
-void
+void
TiledInputFile::readTile (int dx, int dy, int l)
{
readTile (dx, dy, l, l);
void
TiledInputFile::rawTileData (int &dx, int &dy,
- int &lx, int &ly,
+ int &lx, int &ly,
const char *&pixelData,
- int &pixelDataSize)
+ int &pixelDataSize)
{
try
{
- Lock lock (*_data);
+ Lock lock (*_data->_streamData);
if (!isValidTile (dx, dy, lx, ly))
- throw Iex::ArgExc ("Tried to read a tile outside "
- "the image file's data window.");
+ throw IEX_NAMESPACE::ArgExc ("Tried to read a tile outside "
+ "the image file's data window.");
TileBuffer *tileBuffer = _data->getTileBuffer (0);
- readNextTileData (_data, dx, dy, lx, ly,
- tileBuffer->buffer,
+ //
+ // if file is a multipart file, we have to seek to the required tile
+ // since we don't know where the file pointer is
+ //
+ int old_dx=dx;
+ int old_dy=dy;
+ int old_lx=lx;
+ int old_ly=ly;
+ if(isMultiPart(version()))
+ {
+ _data->_streamData->is->seekg(_data->tileOffsets(dx,dy,lx,ly));
+ }
+ readNextTileData (_data->_streamData, _data, dx, dy, lx, ly,
+ tileBuffer->buffer,
pixelDataSize);
-
+ if(isMultiPart(version()))
+ {
+ if (old_dx!=dx || old_dy !=dy || old_lx!=lx || old_ly!=ly)
+ {
+ throw IEX_NAMESPACE::ArgExc ("rawTileData read the wrong tile");
+ }
+ }
pixelData = tileBuffer->buffer;
}
- catch (Iex::BaseExc &e)
+ catch (IEX_NAMESPACE::BaseExc &e)
{
REPLACE_EXC (e, "Error reading pixel data from image "
- "file \"" << fileName() << "\". " << e);
+ "file \"" << fileName() << "\". " << e.what());
throw;
}
}
TiledInputFile::numLevels () const
{
if (levelMode() == RIPMAP_LEVELS)
- THROW (Iex::LogicExc, "Error calling numLevels() on image "
- "file \"" << fileName() << "\" "
- "(numLevels() is not defined for files "
- "with RIPMAP level mode).");
+ THROW (IEX_NAMESPACE::LogicExc, "Error calling numLevels() on image "
+ "file \"" << fileName() << "\" "
+ "(numLevels() is not defined for files "
+ "with RIPMAP level mode).");
return _data->numXLevels;
}
}
-bool
+bool
TiledInputFile::isValidLevel (int lx, int ly) const
{
if (lx < 0 || ly < 0)
- return false;
+ return false;
if (levelMode() == MIPMAP_LEVELS && lx != ly)
- return false;
+ return false;
if (lx >= numXLevels() || ly >= numYLevels())
- return false;
+ return false;
return true;
}
try
{
return levelSize (_data->minX, _data->maxX, lx,
- _data->tileDesc.roundingMode);
+ _data->tileDesc.roundingMode);
}
- catch (Iex::BaseExc &e)
+ catch (IEX_NAMESPACE::BaseExc &e)
{
- REPLACE_EXC (e, "Error calling levelWidth() on image "
- "file \"" << fileName() << "\". " << e);
- throw;
+ REPLACE_EXC (e, "Error calling levelWidth() on image "
+ "file \"" << fileName() << "\". " << e.what());
+ throw;
}
}
return levelSize (_data->minY, _data->maxY, ly,
_data->tileDesc.roundingMode);
}
- catch (Iex::BaseExc &e)
+ catch (IEX_NAMESPACE::BaseExc &e)
{
- REPLACE_EXC (e, "Error calling levelHeight() on image "
- "file \"" << fileName() << "\". " << e);
- throw;
+ REPLACE_EXC (e, "Error calling levelHeight() on image "
+ "file \"" << fileName() << "\". " << e.what());
+ throw;
}
}
{
if (lx < 0 || lx >= _data->numXLevels)
{
- THROW (Iex::ArgExc, "Error calling numXTiles() on image "
- "file \"" << _data->is->fileName() << "\" "
- "(Argument is not in valid range).");
+ THROW (IEX_NAMESPACE::ArgExc, "Error calling numXTiles() on image "
+ "file \"" << _data->_streamData->is->fileName() << "\" "
+ "(Argument is not in valid range).");
}
-
+
return _data->numXTiles[lx];
}
{
if (ly < 0 || ly >= _data->numYLevels)
{
- THROW (Iex::ArgExc, "Error calling numYTiles() on image "
- "file \"" << _data->is->fileName() << "\" "
- "(Argument is not in valid range).");
+ THROW (IEX_NAMESPACE::ArgExc, "Error calling numYTiles() on image "
+ "file \"" << _data->_streamData->is->fileName() << "\" "
+ "(Argument is not in valid range).");
}
-
+
return _data->numYTiles[ly];
}
{
try
{
- return Imf::dataWindowForLevel (_data->tileDesc,
- _data->minX, _data->maxX,
- _data->minY, _data->maxY,
- lx, ly);
+ return OPENEXR_IMF_INTERNAL_NAMESPACE::dataWindowForLevel (
+ _data->tileDesc,
+ _data->minX, _data->maxX,
+ _data->minY, _data->maxY,
+ lx, ly);
}
- catch (Iex::BaseExc &e)
+ catch (IEX_NAMESPACE::BaseExc &e)
{
- REPLACE_EXC (e, "Error calling dataWindowForLevel() on image "
- "file \"" << fileName() << "\". " << e);
- throw;
+ REPLACE_EXC (e, "Error calling dataWindowForLevel() on image "
+ "file \"" << fileName() << "\". " << e.what());
+ throw;
}
}
{
try
{
- if (!isValidTile (dx, dy, lx, ly))
- throw Iex::ArgExc ("Arguments not in valid range.");
-
- return Imf::dataWindowForTile (_data->tileDesc,
- _data->minX, _data->maxX,
- _data->minY, _data->maxY,
- dx, dy, lx, ly);
+ if (!isValidTile (dx, dy, lx, ly))
+ throw IEX_NAMESPACE::ArgExc ("Arguments not in valid range.");
+
+ return OPENEXR_IMF_INTERNAL_NAMESPACE::dataWindowForTile (
+ _data->tileDesc,
+ _data->minX, _data->maxX,
+ _data->minY, _data->maxY,
+ dx, dy, lx, ly);
}
- catch (Iex::BaseExc &e)
+ catch (IEX_NAMESPACE::BaseExc &e)
{
- REPLACE_EXC (e, "Error calling dataWindowForTile() on image "
- "file \"" << fileName() << "\". " << e);
- throw;
+ REPLACE_EXC (e, "Error calling dataWindowForTile() on image "
+ "file \"" << fileName() << "\". " << e.what());
+ throw;
}
}
(dy < _data->numYTiles[ly] && dy >= 0));
}
+void TiledInputFile::tileOrder(int dx[], int dy[], int lx[], int ly[]) const
+{
+ return _data->tileOffsets.getTileOrder(dx,dy,lx,ly);
+}
+
-} // namespace Imf
+OPENEXR_IMF_INTERNAL_NAMESPACE_SOURCE_EXIT
//
// Copyright (c) 2004, Industrial Light & Magic, a division of Lucas
// Digital Ltd. LLC
-//
+//
// All rights reserved.
-//
+//
// Redistribution and use in source and binary forms, with or without
// modification, are permitted provided that the following conditions are
// met:
// distribution.
// * Neither the name of Industrial Light & Magic nor the names of
// its contributors may be used to endorse or promote products derived
-// from this software without specific prior written permission.
-//
+// from this software without specific prior written permission.
+//
// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
//
//-----------------------------------------------------------------------------
-#include <ImfHeader.h>
-#include <ImfFrameBuffer.h>
+#include "ImfHeader.h"
+#include "ImfFrameBuffer.h"
#include "ImathBox.h"
-#include <ImfTileDescription.h>
-#include <ImfThreading.h>
+#include "ImfTileDescription.h"
+#include "ImfThreading.h"
+#include "ImfGenericInputFile.h"
+#include "ImfTiledOutputFile.h"
+#include "ImfNamespace.h"
+#include "ImfExport.h"
-namespace Imf {
+OPENEXR_IMF_INTERNAL_NAMESPACE_HEADER_ENTER
-class TiledInputFile
+class TiledInputFile : public GenericInputFile
{
public:
//--------------------------------------------------------------------
// A constructor that opens the file with the specified name, and
- // reads the file header. The constructor throws an Iex::ArgExc
+ // reads the file header. The constructor throws an IEX_NAMESPACE::ArgExc
// exception if the file is not tiled.
// The numThreads parameter specifies how many worker threads this
// file will try to keep busy when decompressing individual tiles.
// automatically closes the corresponding files.
//--------------------------------------------------------------------
+ IMF_EXPORT
TiledInputFile (const char fileName[],
int numThreads = globalThreadCount ());
-
+
// ----------------------------------------------------------
// A constructor that attaches the new TiledInputFile object
- // to a file that has already been opened.
+ // to a file that has already been opened.
// Destroying TiledInputFile objects constructed with this
// constructor does not automatically close the corresponding
// files.
// ----------------------------------------------------------
- TiledInputFile (IStream &is, int numThreads = globalThreadCount ());
+ IMF_EXPORT
+ TiledInputFile (OPENEXR_IMF_INTERNAL_NAMESPACE::IStream &is, int numThreads = globalThreadCount ());
//-----------
// Destructor
//-----------
+ IMF_EXPORT
virtual ~TiledInputFile ();
// Access to the file name
//------------------------
+ IMF_EXPORT
const char * fileName () const;
// Access to the file header
//--------------------------
+ IMF_EXPORT
const Header & header () const;
// Access to the file format version
//----------------------------------
+ IMF_EXPORT
int version () const;
// to readTile().
//-----------------------------------------------------------
+ IMF_EXPORT
void setFrameBuffer (const FrameBuffer &frameBuffer);
// Access to the current frame buffer
//-----------------------------------
+ IMF_EXPORT
const FrameBuffer & frameBuffer () const;
// prematurely.)
//------------------------------------------------------------
+ IMF_EXPORT
bool isComplete () const;
// fields of the file header's TileDescriptionAttribute.
//---------------------------------------------------------
+ IMF_EXPORT
unsigned int tileXSize () const;
+ IMF_EXPORT
unsigned int tileYSize () const;
+ IMF_EXPORT
LevelMode levelMode () const;
+ IMF_EXPORT
LevelRoundingMode levelRoundingMode () const;
// return value is the same as for numXLevels()
//
// if levelMode() == RIPMAP_LEVELS:
- // an Iex::LogicExc exception is thrown
+ // an IEX_NAMESPACE::LogicExc exception is thrown
//
- // isValidLevel(lx, ly) returns true if the file contains
+ // isValidLevel(lx, ly) returns true if the file contains
// a level with level number (lx, ly), false if not.
//
//--------------------------------------------------------------------
+ IMF_EXPORT
int numLevels () const;
+ IMF_EXPORT
int numXLevels () const;
+ IMF_EXPORT
int numYLevels () const;
+ IMF_EXPORT
bool isValidLevel (int lx, int ly) const;
//
//----------------------------------------------------------
+ IMF_EXPORT
int levelWidth (int lx) const;
+ IMF_EXPORT
int levelHeight (int ly) const;
//
//--------------------------------------------------------------
+ IMF_EXPORT
int numXTiles (int lx = 0) const;
+ IMF_EXPORT
int numYTiles (int ly = 0) const;
//
//---------------------------------------------------------------
- Imath::Box2i dataWindowForLevel (int l = 0) const;
- Imath::Box2i dataWindowForLevel (int lx, int ly) const;
+ IMF_EXPORT
+ IMATH_NAMESPACE::Box2i dataWindowForLevel (int l = 0) const;
+ IMF_EXPORT
+ IMATH_NAMESPACE::Box2i dataWindowForLevel (int lx, int ly) const;
//-------------------------------------------------------------------
//
//-------------------------------------------------------------------
- Imath::Box2i dataWindowForTile (int dx, int dy, int l = 0) const;
+ IMF_EXPORT
+ IMATH_NAMESPACE::Box2i dataWindowForTile (int dx, int dy, int l = 0) const;
- Imath::Box2i dataWindowForTile (int dx, int dy,
+ IMF_EXPORT
+ IMATH_NAMESPACE::Box2i dataWindowForTile (int dx, int dy,
int lx, int ly) const;
//------------------------------------------------------------
//
//------------------------------------------------------------
+ IMF_EXPORT
void readTile (int dx, int dy, int l = 0);
+ IMF_EXPORT
void readTile (int dx, int dy, int lx, int ly);
+ IMF_EXPORT
void readTiles (int dx1, int dx2, int dy1, int dy2,
int lx, int ly);
+ IMF_EXPORT
void readTiles (int dx1, int dx2, int dy1, int dy2,
int l = 0);
// Read a tile of raw pixel data from the file,
// without uncompressing it (this function is
// used to implement TiledOutputFile::copyPixels()).
+ //
+ // for single part files, reads the next tile in the file
+ // for multipart files, reads the tile specified by dx,dy,lx,ly
+ //
//--------------------------------------------------
+ IMF_EXPORT
void rawTileData (int &dx, int &dy,
- int &lx, int &ly,
- const char *&pixelData,
- int &pixelDataSize);
+ int &lx, int &ly,
+ const char *&pixelData,
+ int &pixelDataSize);
struct Data;
private:
friend class InputFile;
+ friend class MultiPartInputFile;
+
+ TiledInputFile (InputPartData* part);
TiledInputFile (const TiledInputFile &); // not implemented
TiledInputFile & operator = (const TiledInputFile &); // not implemented
- TiledInputFile (const Header &header, IStream *is, int version,
+ TiledInputFile (const Header &header, OPENEXR_IMF_INTERNAL_NAMESPACE::IStream *is, int version,
int numThreads);
void initialize ();
+ void multiPartInitialize(InputPartData* part);
+ void compatibilityInitialize(OPENEXR_IMF_INTERNAL_NAMESPACE::IStream& is);
bool isValidTile (int dx, int dy,
- int lx, int ly) const;
+ int lx, int ly) const;
size_t bytesPerLineForTile (int dx, int dy,
- int lx, int ly) const;
+ int lx, int ly) const;
+ void tileOrder(int dx[],int dy[],int lx[],int ly[]) const;
Data * _data;
+
+ friend void TiledOutputFile::copyPixels(TiledInputFile &);
};
-} // namespace Imf
+OPENEXR_IMF_INTERNAL_NAMESPACE_HEADER_EXIT
+
+
+
+
#endif
--- /dev/null
+///////////////////////////////////////////////////////////////////////////
+//
+// Copyright (c) 2011, Industrial Light & Magic, a division of Lucas
+// Digital Ltd. LLC
+//
+// All rights reserved.
+//
+// Redistribution and use in source and binary forms, with or without
+// modification, are permitted provided that the following conditions are
+// met:
+// * Redistributions of source code must retain the above copyright
+// notice, this list of conditions and the following disclaimer.
+// * Redistributions in binary form must reproduce the above
+// copyright notice, this list of conditions and the following disclaimer
+// in the documentation and/or other materials provided with the
+// distribution.
+// * Neither the name of Industrial Light & Magic nor the names of
+// its contributors may be used to endorse or promote products derived
+// from this software without specific prior written permission.
+//
+// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+//
+///////////////////////////////////////////////////////////////////////////
+
+#include "ImfTiledInputPart.h"
+#include "ImfNamespace.h"
+
+OPENEXR_IMF_INTERNAL_NAMESPACE_SOURCE_ENTER
+
+TiledInputPart::TiledInputPart(MultiPartInputFile& multiPartFile, int partNumber)
+{
+ file = multiPartFile.getInputPart<TiledInputFile>(partNumber);
+}
+
+const char *
+TiledInputPart::fileName () const
+{
+ return file->fileName();
+}
+
+const Header &
+TiledInputPart::header () const
+{
+ return file->header();
+}
+
+int
+TiledInputPart::version () const
+{
+ return file->version();
+}
+
+void
+TiledInputPart::setFrameBuffer (const FrameBuffer &frameBuffer)
+{
+ file->setFrameBuffer(frameBuffer);
+}
+
+const FrameBuffer &
+TiledInputPart::frameBuffer () const
+{
+ return file->frameBuffer();
+}
+
+bool
+TiledInputPart::isComplete () const
+{
+ return file->isComplete();
+}
+
+unsigned int
+TiledInputPart::tileXSize () const
+{
+ return file->tileXSize();
+}
+
+unsigned int
+TiledInputPart::tileYSize () const
+{
+ return file->tileYSize();
+}
+
+LevelMode
+TiledInputPart::levelMode () const
+{
+ return file->levelMode();
+}
+
+LevelRoundingMode
+TiledInputPart::levelRoundingMode () const
+{
+ return file->levelRoundingMode();
+}
+
+int
+TiledInputPart::numLevels () const
+{
+ return file->numLevels();
+}
+
+int
+TiledInputPart::numXLevels () const
+{
+ return file->numXLevels();
+}
+
+int
+TiledInputPart::numYLevels () const
+{
+ return file->numYLevels();
+}
+
+bool
+TiledInputPart::isValidLevel (int lx, int ly) const
+{
+ return file->isValidLevel(lx, ly);
+}
+
+int
+TiledInputPart::levelWidth (int lx) const
+{
+ return file->levelWidth(lx);
+}
+
+int
+TiledInputPart::levelHeight (int ly) const
+{
+ return file->levelHeight(ly);
+}
+
+int
+TiledInputPart::numXTiles (int lx) const
+{
+ return file->numXTiles(lx);
+}
+
+int
+TiledInputPart::numYTiles (int ly) const
+{
+ return file->numYTiles(ly);
+}
+
+IMATH_NAMESPACE::Box2i
+TiledInputPart::dataWindowForLevel (int l) const
+{
+ return file->dataWindowForLevel(l);
+}
+
+IMATH_NAMESPACE::Box2i
+TiledInputPart::dataWindowForLevel (int lx, int ly) const
+{
+ return file->dataWindowForLevel(lx, ly);
+}
+
+IMATH_NAMESPACE::Box2i
+TiledInputPart::dataWindowForTile (int dx, int dy, int l) const
+{
+ return file->dataWindowForTile(dx, dy, l);
+}
+
+IMATH_NAMESPACE::Box2i
+TiledInputPart::dataWindowForTile (int dx, int dy, int lx, int ly) const
+{
+ return file->dataWindowForTile(dx, dy, lx, ly);
+}
+
+void
+TiledInputPart::readTile (int dx, int dy, int l)
+{
+ file->readTile(dx, dy, l);
+}
+
+void
+TiledInputPart::readTile (int dx, int dy, int lx, int ly)
+{
+ file->readTile(dx, dy, lx, ly);
+}
+
+void
+TiledInputPart::readTiles (int dx1, int dx2, int dy1, int dy2, int lx, int ly)
+{
+ file->readTiles(dx1, dx2, dy1, dy2, lx, ly);
+}
+
+void
+TiledInputPart::readTiles (int dx1, int dx2, int dy1, int dy2, int l)
+{
+ file->readTiles(dx1, dx2, dy1, dy2, l);
+}
+
+void
+TiledInputPart::rawTileData (int &dx, int &dy, int &lx, int &ly,
+ const char *&pixelData, int &pixelDataSize)
+{
+ file->rawTileData(dx, dy, lx, ly, pixelData, pixelDataSize);
+}
+
+OPENEXR_IMF_INTERNAL_NAMESPACE_SOURCE_EXIT
--- /dev/null
+///////////////////////////////////////////////////////////////////////////
+//
+// Copyright (c) 2011, Industrial Light & Magic, a division of Lucas
+// Digital Ltd. LLC
+//
+// All rights reserved.
+//
+// Redistribution and use in source and binary forms, with or without
+// modification, are permitted provided that the following conditions are
+// met:
+// * Redistributions of source code must retain the above copyright
+// notice, this list of conditions and the following disclaimer.
+// * Redistributions in binary form must reproduce the above
+// copyright notice, this list of conditions and the following disclaimer
+// in the documentation and/or other materials provided with the
+// distribution.
+// * Neither the name of Industrial Light & Magic nor the names of
+// its contributors may be used to endorse or promote products derived
+// from this software without specific prior written permission.
+//
+// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+//
+///////////////////////////////////////////////////////////////////////////
+
+#ifndef IMFTILEDINPUTPART_H_
+#define IMFTILEDINPUTPART_H_
+
+#include "ImfMultiPartInputFile.h"
+#include "ImfTiledInputFile.h"
+#include "ImfNamespace.h"
+#include "ImfForward.h"
+#include "ImfExport.h"
+
+OPENEXR_IMF_INTERNAL_NAMESPACE_HEADER_ENTER
+
+//-----------------------------------------------------------------------------
+// class TiledInputPart:
+//
+// Same interface as TiledInputFile. Please have a reference to TiledInputFile.
+//-----------------------------------------------------------------------------
+
+class TiledInputPart
+{
+ public:
+ IMF_EXPORT
+ TiledInputPart(MultiPartInputFile& multiPartFile, int partNumber);
+
+ IMF_EXPORT
+ const char * fileName () const;
+ IMF_EXPORT
+ const Header & header () const;
+ IMF_EXPORT
+ int version () const;
+ IMF_EXPORT
+ void setFrameBuffer (const FrameBuffer &frameBuffer);
+ IMF_EXPORT
+ const FrameBuffer & frameBuffer () const;
+ IMF_EXPORT
+ bool isComplete () const;
+ IMF_EXPORT
+ unsigned int tileXSize () const;
+ IMF_EXPORT
+ unsigned int tileYSize () const;
+ IMF_EXPORT
+ LevelMode levelMode () const;
+ IMF_EXPORT
+ LevelRoundingMode levelRoundingMode () const;
+ IMF_EXPORT
+ int numLevels () const;
+ IMF_EXPORT
+ int numXLevels () const;
+ IMF_EXPORT
+ int numYLevels () const;
+ IMF_EXPORT
+ bool isValidLevel (int lx, int ly) const;
+ IMF_EXPORT
+ int levelWidth (int lx) const;
+ IMF_EXPORT
+ int levelHeight (int ly) const;
+ IMF_EXPORT
+ int numXTiles (int lx = 0) const;
+ IMF_EXPORT
+ int numYTiles (int ly = 0) const;
+ IMF_EXPORT
+ IMATH_NAMESPACE::Box2i dataWindowForLevel (int l = 0) const;
+ IMF_EXPORT
+ IMATH_NAMESPACE::Box2i dataWindowForLevel (int lx, int ly) const;
+ IMF_EXPORT
+ IMATH_NAMESPACE::Box2i dataWindowForTile (int dx, int dy, int l = 0) const;
+ IMF_EXPORT
+ IMATH_NAMESPACE::Box2i dataWindowForTile (int dx, int dy,
+ int lx, int ly) const;
+ IMF_EXPORT
+ void readTile (int dx, int dy, int l = 0);
+ IMF_EXPORT
+ void readTile (int dx, int dy, int lx, int ly);
+ IMF_EXPORT
+ void readTiles (int dx1, int dx2, int dy1, int dy2,
+ int lx, int ly);
+ IMF_EXPORT
+ void readTiles (int dx1, int dx2, int dy1, int dy2,
+ int l = 0);
+ IMF_EXPORT
+ void rawTileData (int &dx, int &dy,
+ int &lx, int &ly,
+ const char *&pixelData,
+ int &pixelDataSize);
+
+ private:
+ TiledInputFile* file;
+ // for internal use - allow TiledOutputFile access to file for copyPixels
+ friend class TiledOutputFile;
+
+};
+
+OPENEXR_IMF_INTERNAL_NAMESPACE_HEADER_EXIT
+
+#endif /* IMFTILEDINPUTPART_H_ */
//
// Copyright (c) 2004, Industrial Light & Magic, a division of Lucas
// Digital Ltd. LLC
-//
+//
// All rights reserved.
-//
+//
// Redistribution and use in source and binary forms, with or without
// modification, are permitted provided that the following conditions are
// met:
// distribution.
// * Neither the name of Industrial Light & Magic nor the names of
// its contributors may be used to endorse or promote products derived
-// from this software without specific prior written permission.
-//
+// from this software without specific prior written permission.
+//
// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
#include "Iex.h"
#include <ImfMisc.h>
#include <ImfChannelList.h>
-#include <algorithm> // for std::max()
+#include <ImfTileDescription.h>
+#include <algorithm>
+#include "ImfNamespace.h"
-namespace Imf {
+OPENEXR_IMF_INTERNAL_NAMESPACE_SOURCE_ENTER
-using Imath::Box2i;
-using Imath::V2i;
+using IMATH_NAMESPACE::Box2i;
+using IMATH_NAMESPACE::V2i;
int
levelSize (int min, int max, int l, LevelRoundingMode rmode)
{
if (l < 0)
- throw Iex::ArgExc ("Argument not in valid range.");
+ throw IEX_NAMESPACE::ArgExc ("Argument not in valid range.");
int a = max - min + 1;
int b = (1 << l);
int size = a / b;
if (rmode == ROUND_UP && size * b < a)
- size += 1;
+ size += 1;
return std::max (size, 1);
}
Box2i
dataWindowForLevel (const TileDescription &tileDesc,
- int minX, int maxX,
- int minY, int maxY,
- int lx, int ly)
+ int minX, int maxX,
+ int minY, int maxY,
+ int lx, int ly)
{
V2i levelMin = V2i (minX, minY);
V2i levelMax = levelMin +
- V2i (levelSize (minX, maxX, lx, tileDesc.roundingMode) - 1,
- levelSize (minY, maxY, ly, tileDesc.roundingMode) - 1);
+ V2i (levelSize (minX, maxX, lx, tileDesc.roundingMode) - 1,
+ levelSize (minY, maxY, ly, tileDesc.roundingMode) - 1);
return Box2i(levelMin, levelMax);
}
Box2i
dataWindowForTile (const TileDescription &tileDesc,
- int minX, int maxX,
- int minY, int maxY,
- int dx, int dy,
- int lx, int ly)
+ int minX, int maxX,
+ int minY, int maxY,
+ int dx, int dy,
+ int lx, int ly)
{
V2i tileMin = V2i (minX + dx * tileDesc.xSize,
- minY + dy * tileDesc.ySize);
+ minY + dy * tileDesc.ySize);
V2i tileMax = tileMin + V2i (tileDesc.xSize - 1, tileDesc.ySize - 1);
V2i levelMax = dataWindowForLevel
- (tileDesc, minX, maxX, minY, maxY, lx, ly).max;
+ (tileDesc, minX, maxX, minY, maxY, lx, ly).max;
tileMax = V2i (std::min (tileMax[0], levelMax[0]),
- std::min (tileMax[1], levelMax[1]));
+ std::min (tileMax[1], levelMax[1]));
return Box2i (tileMin, tileMax);
}
size_t bytesPerPixel = 0;
for (ChannelList::ConstIterator c = channels.begin();
- c != channels.end();
- ++c)
+ c != channels.end();
+ ++c)
{
- bytesPerPixel += pixelTypeSize (c.channel().type);
+ bytesPerPixel += pixelTypeSize (c.channel().type);
}
return bytesPerPixel;
}
+void
+calculateBytesPerLine (const Header &header,
+ char* sampleCountBase,
+ int sampleCountXStride,
+ int sampleCountYStride,
+ int minX, int maxX,
+ int minY, int maxY,
+ std::vector<int>& xOffsets,
+ std::vector<int>& yOffsets,
+ std::vector<Int64>& bytesPerLine)
+{
+ const ChannelList &channels = header.channels();
+
+ int pos = 0;
+ for (ChannelList::ConstIterator c = channels.begin();
+ c != channels.end();
+ ++c, ++pos)
+ {
+ int xOffset = xOffsets[pos];
+ int yOffset = yOffsets[pos];
+ int i = 0;
+ for (int y = minY - yOffset; y <= maxY - yOffset; y++, i++)
+ for (int x = minX - xOffset; x <= maxX - xOffset; x++)
+ {
+ bytesPerLine[i] += sampleCount(sampleCountBase,
+ sampleCountXStride,
+ sampleCountYStride,
+ x, y)
+ * pixelTypeSize (c.channel().type);
+ }
+ }
+}
+
+
namespace {
int
while (x > 1)
{
- y += 1;
- x >>= 1;
+ y += 1;
+ x >>= 1;
}
return y;
while (x > 1)
{
- if (x & 1)
- r = 1;
+ if (x & 1)
+ r = 1;
- y += 1;
- x >>= 1;
+ y += 1;
+ x >>= 1;
}
return y + r;
int
calculateNumXLevels (const TileDescription& tileDesc,
- int minX, int maxX,
- int minY, int maxY)
+ int minX, int maxX,
+ int minY, int maxY)
{
int num = 0;
{
case ONE_LEVEL:
- num = 1;
- break;
+ num = 1;
+ break;
case MIPMAP_LEVELS:
- {
- int w = maxX - minX + 1;
- int h = maxY - minY + 1;
- num = roundLog2 (std::max (w, h), tileDesc.roundingMode) + 1;
- }
+ {
+ int w = maxX - minX + 1;
+ int h = maxY - minY + 1;
+ num = roundLog2 (std::max (w, h), tileDesc.roundingMode) + 1;
+ }
break;
case RIPMAP_LEVELS:
- {
- int w = maxX - minX + 1;
- num = roundLog2 (w, tileDesc.roundingMode) + 1;
- }
- break;
+ {
+ int w = maxX - minX + 1;
+ num = roundLog2 (w, tileDesc.roundingMode) + 1;
+ }
+ break;
default:
- throw Iex::ArgExc ("Unknown LevelMode format.");
+ throw IEX_NAMESPACE::ArgExc ("Unknown LevelMode format.");
}
return num;
int
calculateNumYLevels (const TileDescription& tileDesc,
- int minX, int maxX,
- int minY, int maxY)
+ int minX, int maxX,
+ int minY, int maxY)
{
int num = 0;
{
case ONE_LEVEL:
- num = 1;
- break;
+ num = 1;
+ break;
case MIPMAP_LEVELS:
- {
- int w = maxX - minX + 1;
- int h = maxY - minY + 1;
- num = roundLog2 (std::max (w, h), tileDesc.roundingMode) + 1;
- }
+ {
+ int w = maxX - minX + 1;
+ int h = maxY - minY + 1;
+ num = roundLog2 (std::max (w, h), tileDesc.roundingMode) + 1;
+ }
break;
case RIPMAP_LEVELS:
- {
- int h = maxY - minY + 1;
- num = roundLog2 (h, tileDesc.roundingMode) + 1;
- }
- break;
+ {
+ int h = maxY - minY + 1;
+ num = roundLog2 (h, tileDesc.roundingMode) + 1;
+ }
+ break;
default:
- throw Iex::ArgExc ("Unknown LevelMode format.");
+ throw IEX_NAMESPACE::ArgExc ("Unknown LevelMode format.");
}
return num;
void
calculateNumTiles (int *numTiles,
- int numLevels,
- int min, int max,
- int size,
- LevelRoundingMode rmode)
+ int numLevels,
+ int min, int max,
+ int size,
+ LevelRoundingMode rmode)
{
for (int i = 0; i < numLevels; i++)
{
- numTiles[i] = (levelSize (min, max, i, rmode) + size - 1) / size;
+ numTiles[i] = (levelSize (min, max, i, rmode) + size - 1) / size;
}
}
void
precalculateTileInfo (const TileDescription& tileDesc,
- int minX, int maxX,
- int minY, int maxY,
- int *&numXTiles, int *&numYTiles,
- int &numXLevels, int &numYLevels)
+ int minX, int maxX,
+ int minY, int maxY,
+ int *&numXTiles, int *&numYTiles,
+ int &numXLevels, int &numYLevels)
{
numXLevels = calculateNumXLevels(tileDesc, minX, maxX, minY, maxY);
numYLevels = calculateNumYLevels(tileDesc, minX, maxX, minY, maxY);
-
+
numXTiles = new int[numXLevels];
numYTiles = new int[numYLevels];
calculateNumTiles (numXTiles,
- numXLevels,
- minX, maxX,
- tileDesc.xSize,
- tileDesc.roundingMode);
+ numXLevels,
+ minX, maxX,
+ tileDesc.xSize,
+ tileDesc.roundingMode);
calculateNumTiles (numYTiles,
- numYLevels,
- minY, maxY,
- tileDesc.ySize,
- tileDesc.roundingMode);
+ numYLevels,
+ minY, maxY,
+ tileDesc.ySize,
+ tileDesc.roundingMode);
+}
+
+
+int
+getTiledChunkOffsetTableSize(const Header& header)
+{
+ //
+ // Save the dataWindow information
+ //
+
+ const Box2i &dataWindow = header.dataWindow();
+
+ //
+ // Precompute level and tile information.
+ //
+
+ int* numXTiles;
+ int* numYTiles;
+ int numXLevels;
+ int numYLevels;
+ precalculateTileInfo (header.tileDescription(),
+ dataWindow.min.x, dataWindow.max.x,
+ dataWindow.min.y, dataWindow.max.y,
+ numXTiles, numYTiles,
+ numXLevels, numYLevels);
+
+ //
+ // Calculate lineOffsetSize.
+ //
+ int lineOffsetSize = 0;
+ const TileDescription &desc = header.tileDescription();
+ switch (desc.mode)
+ {
+ case ONE_LEVEL:
+ case MIPMAP_LEVELS:
+ for (int i = 0; i < numXLevels; i++)
+ lineOffsetSize += numXTiles[i] * numYTiles[i];
+ break;
+ case RIPMAP_LEVELS:
+ for (int i = 0; i < numXLevels; i++)
+ for (int j = 0; j < numYLevels; j++)
+ lineOffsetSize += numXTiles[i] * numYTiles[j];
+ break;
+ case NUM_LEVELMODES :
+ throw IEX_NAMESPACE::LogicExc("Bad level mode getting chunk offset table size");
+ }
+
+ delete[] numXTiles;
+ delete[] numYTiles;
+
+ return lineOffsetSize;
}
-} // namespace Imf
+OPENEXR_IMF_INTERNAL_NAMESPACE_SOURCE_EXIT
//
// Copyright (c) 2004, Industrial Light & Magic, a division of Lucas
// Digital Ltd. LLC
-//
+//
// All rights reserved.
-//
+//
// Redistribution and use in source and binary forms, with or without
// modification, are permitted provided that the following conditions are
// met:
// distribution.
// * Neither the name of Industrial Light & Magic nor the names of
// its contributors may be used to endorse or promote products derived
-// from this software without specific prior written permission.
-//
+// from this software without specific prior written permission.
+//
// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
//-----------------------------------------------------------------------------
#include "ImathBox.h"
-#include <ImfHeader.h>
+#include "ImfHeader.h"
+#include "ImfNamespace.h"
+
#include <stdio.h>
+#include <vector>
+
-namespace Imf {
+OPENEXR_IMF_INTERNAL_NAMESPACE_HEADER_ENTER
+IMF_EXPORT
int levelSize (int min, int max, int l, LevelRoundingMode rmode);
-Imath::Box2i dataWindowForLevel (const TileDescription &tileDesc,
- int minX, int maxX,
- int minY, int maxY,
- int lx, int ly);
+IMF_EXPORT
+IMATH_NAMESPACE::Box2i dataWindowForLevel (const TileDescription &tileDesc,
+ int minX, int maxX,
+ int minY, int maxY,
+ int lx, int ly);
-Imath::Box2i dataWindowForTile (const TileDescription &tileDesc,
- int minX, int maxX,
- int minY, int maxY,
- int dx, int dy,
- int lx, int ly);
+IMF_EXPORT
+IMATH_NAMESPACE::Box2i dataWindowForTile (const TileDescription &tileDesc,
+ int minX, int maxX,
+ int minY, int maxY,
+ int dx, int dy,
+ int lx, int ly);
+IMF_EXPORT
size_t calculateBytesPerPixel (const Header &header);
+//
+// Calculate the count of bytes for each lines in range [minY, maxY],
+// and pixels in range [minX, maxX].
+// Data will be saved in bytesPerLine.
+// sampleCountBase, sampleCountXStride and sampleCountYStride are
+// used to get the sample count values.
+//
+
+IMF_EXPORT
+void calculateBytesPerLine (const Header &header,
+ char* sampleCountBase,
+ int sampleCountXStride,
+ int sampleCountYStride,
+ int minX, int maxX,
+ int minY, int maxY,
+ std::vector<int>& xOffsets,
+ std::vector<int>& yOffsets,
+ std::vector<Int64>& bytesPerLine);
+
+IMF_EXPORT
void precalculateTileInfo (const TileDescription& tileDesc,
- int minX, int maxX,
- int minY, int maxY,
- int *&numXTiles, int *&numYTiles,
- int &numXLevels, int &numYLevels);
+ int minX, int maxX,
+ int minY, int maxY,
+ int *&numXTiles, int *&numYTiles,
+ int &numXLevels, int &numYLevels);
+
+IMF_EXPORT
+int getTiledChunkOffsetTableSize(const Header& header);
-} // namespace Imf
+OPENEXR_IMF_INTERNAL_NAMESPACE_HEADER_EXIT
#endif
//
// Copyright (c) 2004, Industrial Light & Magic, a division of Lucas
// Digital Ltd. LLC
-//
+//
// All rights reserved.
-//
+//
// Redistribution and use in source and binary forms, with or without
// modification, are permitted provided that the following conditions are
// met:
// distribution.
// * Neither the name of Industrial Light & Magic nor the names of
// its contributors may be used to endorse or promote products derived
-// from this software without specific prior written permission.
-//
+// from this software without specific prior written permission.
+//
// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
#include <ImfTiledOutputFile.h>
#include <ImfTiledInputFile.h>
+#include <ImfTiledInputPart.h>
#include <ImfInputFile.h>
+#include <ImfInputPart.h>
#include <ImfTileDescriptionAttribute.h>
#include <ImfPreviewImageAttribute.h>
#include <ImfChannelList.h>
#include <ImfVersion.h>
#include <ImfTileOffsets.h>
#include <ImfThreading.h>
+#include <ImfPartType.h>
#include "IlmThreadPool.h"
#include "IlmThreadSemaphore.h"
#include "IlmThreadMutex.h"
+#include "ImfOutputStreamMutex.h"
+#include "ImfOutputPartData.h"
#include "Iex.h"
#include <string>
#include <vector>
#include <fstream>
#include <assert.h>
#include <map>
-#include <algorithm> // for std::max()
+#include <algorithm>
+#include "ImfNamespace.h"
-namespace Imf {
-using Imath::Box2i;
-using Imath::V2i;
+OPENEXR_IMF_INTERNAL_NAMESPACE_SOURCE_ENTER
+
+using IMATH_NAMESPACE::Box2i;
+using IMATH_NAMESPACE::V2i;
using std::string;
using std::vector;
using std::ofstream;
using std::min;
using std::max;
using std::swap;
-using IlmThread::Mutex;
-using IlmThread::Lock;
-using IlmThread::Semaphore;
-using IlmThread::Task;
-using IlmThread::TaskGroup;
-using IlmThread::ThreadPool;
+using ILMTHREAD_NAMESPACE::Mutex;
+using ILMTHREAD_NAMESPACE::Lock;
+using ILMTHREAD_NAMESPACE::Semaphore;
+using ILMTHREAD_NAMESPACE::Task;
+using ILMTHREAD_NAMESPACE::TaskGroup;
+using ILMTHREAD_NAMESPACE::ThreadPool;
namespace {
int yTileCoords;
TOutSliceInfo (PixelType type = HALF,
- const char *base = 0,
- size_t xStride = 0,
- size_t yStride = 0,
- bool zero = false,
+ const char *base = 0,
+ size_t xStride = 0,
+ size_t yStride = 0,
+ bool zero = false,
int xTileCoords = 0,
int yTileCoords = 0);
};
TOutSliceInfo::TOutSliceInfo (PixelType t,
- const char *b,
- size_t xs, size_t ys,
- bool z,
+ const char *b,
+ size_t xs, size_t ys,
+ bool z,
int xtc,
int ytc)
:
int dy;
int lx;
int ly;
-
+
TileCoord (int xTile = 0, int yTile = 0,
- int xLevel = 0, int yLevel = 0)
+ int xLevel = 0, int yLevel = 0)
:
dx (xTile), dy (yTile),
- lx (xLevel), ly (yLevel)
+ lx (xLevel), ly (yLevel)
{
// empty
}
-
+
bool
operator < (const TileCoord &other) const
{
return (ly < other.ly) ||
- (ly == other.ly && lx < other.lx) ||
- ((ly == other.ly && lx == other.lx) &&
- ((dy < other.dy) || (dy == other.dy && dx < other.dx)));
+ (ly == other.ly && lx < other.lx) ||
+ ((ly == other.ly && lx == other.lx) &&
+ ((dy < other.dy) || (dy == other.dy && dx < other.dx)));
}
operator == (const TileCoord &other) const
{
return lx == other.lx &&
- ly == other.ly &&
- dx == other.dx &&
- dy == other.dy;
+ ly == other.ly &&
+ dx == other.dx &&
+ dy == other.dy;
}
};
int pixelDataSize;
BufferedTile (const char *data, int size):
- pixelData (0),
- pixelDataSize(size)
+ pixelData (0),
+ pixelDataSize(size)
{
- pixelData = new char[pixelDataSize];
- memcpy (pixelData, data, pixelDataSize);
+ pixelData = new char[pixelDataSize];
+ memcpy (pixelData, data, pixelDataSize);
}
~BufferedTile()
{
- delete [] pixelData;
+ delete [] pixelData;
}
};
} // namespace
-struct TiledOutputFile::Data: public Mutex
+struct TiledOutputFile::Data
{
Header header; // the image header
int version; // file format version
+ bool multipart; // part came from a multipart file
TileDescription tileDesc; // describes the tile layout
FrameBuffer frameBuffer; // framebuffer to write into
Int64 previewPosition;
int * numYTiles; // number of y tiles at a level
TileOffsets tileOffsets; // stores offsets in file for
- // each tile
+ // each tile
Compressor::Format format; // compressor's data format
vector<TOutSliceInfo> slices; // info about channels in file
- OStream * os; // file stream to write to
- bool deleteStream;
size_t maxBytesPerTileLine; // combined size of a tile line
- // over all channels
-
+ // over all channels
+
vector<TileBuffer*> tileBuffers;
size_t tileBufferSize; // size of a tile buffer
Int64 tileOffsetsPosition; // position of the tile index
- Int64 currentPosition; // current position in the file
-
+
TileMap tileMap;
TileCoord nextTileToWrite;
- Data (bool del, int numThreads);
- ~Data ();
+ int partNumber; // the output part number
+ Data (int numThreads);
+ ~Data ();
+
inline TileBuffer * getTileBuffer (int number);
- // hash function from tile
- // buffer coords into our
- // vector of tile buffers
-
+ // hash function from tile
+ // buffer coords into our
+ // vector of tile buffers
+
TileCoord nextTileCoord (const TileCoord &a);
};
-TiledOutputFile::Data::Data (bool del, int numThreads):
+TiledOutputFile::Data::Data (int numThreads):
+ multipart(false),
numXTiles(0),
numYTiles(0),
- os (0),
- deleteStream (del),
- tileOffsetsPosition (0)
+ tileOffsetsPosition (0),
+ partNumber(-1)
{
//
// We need at least one tileBuffer, but if threading is used,
delete [] numXTiles;
delete [] numYTiles;
- if (deleteStream)
- delete os;
-
//
// Delete all the tile buffers, if any still happen to exist
//
-
+
for (TileMap::iterator i = tileMap.begin(); i != tileMap.end(); ++i)
- delete i->second;
+ delete i->second;
for (size_t i = 0; i < tileBuffers.size(); i++)
delete tileBuffers[i];
TiledOutputFile::Data::nextTileCoord (const TileCoord &a)
{
TileCoord b = a;
-
+
if (lineOrder == INCREASING_Y)
{
b.dx++;
if (b.dy >= numYTiles[b.ly])
{
- //
- // the next tile is in the next level
- //
+ //
+ // the next tile is in the next level
+ //
b.dy = 0;
b.lx = 0;
b.ly++;
- #ifdef DEBUG
- assert (b.ly <= numYLevels);
- #endif
+ #ifdef DEBUG
+ assert (b.ly <= numYLevels);
+ #endif
}
break;
+ case NUM_LEVELMODES:
+ throw(IEX_NAMESPACE::ArgExc("Invalid tile description"));
+
}
}
}
if (b.dy < 0)
{
- //
- // the next tile is in the next level
- //
+ //
+ // the next tile is in the next level
+ //
switch (tileDesc.mode)
{
b.lx = 0;
b.ly++;
- #ifdef DEBUG
- assert (b.ly <= numYLevels);
- #endif
+ #ifdef DEBUG
+ assert (b.ly <= numYLevels);
+ #endif
}
break;
+ case NUM_LEVELMODES:
+ throw(IEX_NAMESPACE::ArgExc("Invalid tile description"));
+
}
- if (b.ly < numYLevels)
- b.dy = numYTiles[b.ly] - 1;
+ if (b.ly < numYLevels)
+ b.dy = numYTiles[b.ly] - 1;
}
}
}
-
- return b;
+
+ return b;
}
namespace {
void
-writeTileData (TiledOutputFile::Data *ofd,
+writeTileData (OutputStreamMutex *streamData,
+ TiledOutputFile::Data *ofd,
int dx, int dy,
- int lx, int ly,
+ int lx, int ly,
const char pixelData[],
int pixelDataSize)
{
// without calling tellp() (tellp() can be fairly expensive).
//
- Int64 currentPosition = ofd->currentPosition;
- ofd->currentPosition = 0;
+ Int64 currentPosition = streamData->currentPosition;
+ streamData->currentPosition = 0;
if (currentPosition == 0)
- currentPosition = ofd->os->tellp();
+ currentPosition = streamData->os->tellp();
ofd->tileOffsets (dx, dy, lx, ly) = currentPosition;
#ifdef DEBUG
- assert (ofd->os->tellp() == currentPosition);
+ assert (streamData->os->tellp() == currentPosition);
#endif
//
// Write the tile header.
//
- Xdr::write <StreamIO> (*ofd->os, dx);
- Xdr::write <StreamIO> (*ofd->os, dy);
- Xdr::write <StreamIO> (*ofd->os, lx);
- Xdr::write <StreamIO> (*ofd->os, ly);
- Xdr::write <StreamIO> (*ofd->os, pixelDataSize);
+ if (ofd->multipart)
+ {
+ Xdr::write <StreamIO> (*streamData->os, ofd->partNumber);
+ }
+ Xdr::write <StreamIO> (*streamData->os, dx);
+ Xdr::write <StreamIO> (*streamData->os, dy);
+ Xdr::write <StreamIO> (*streamData->os, lx);
+ Xdr::write <StreamIO> (*streamData->os, ly);
+ Xdr::write <StreamIO> (*streamData->os, pixelDataSize);
- ofd->os->write (pixelData, pixelDataSize);
+ streamData->os->write (pixelData, pixelDataSize);
//
- // Keep current position in the file so that we can avoid
+ // Keep current position in the file so that we can avoid
// redundant seekg() operations (seekg() can be fairly expensive).
//
- ofd->currentPosition = currentPosition +
+ streamData->currentPosition = currentPosition +
5 * Xdr::size<int>() +
pixelDataSize;
+
+ if (ofd->multipart)
+ {
+ streamData->currentPosition += Xdr::size<int>();
+ }
}
void
-bufferedTileWrite (TiledOutputFile::Data *ofd,
+bufferedTileWrite (OutputStreamMutex *streamData,
+ TiledOutputFile::Data *ofd,
int dx, int dy,
- int lx, int ly,
+ int lx, int ly,
const char pixelData[],
int pixelDataSize)
{
if (ofd->tileOffsets (dx, dy, lx, ly))
{
- THROW (Iex::ArgExc,
- "Attempt to write tile "
- "(" << dx << ", " << dy << ", " << lx << "," << ly << ") "
- "more than once.");
+ THROW (IEX_NAMESPACE::ArgExc,
+ "Attempt to write tile "
+ "(" << dx << ", " << dy << ", " << lx << ", " << ly << ") "
+ "more than once.");
}
//
// If tiles can be written in random order, then don't buffer anything.
//
-
+
if (ofd->lineOrder == RANDOM_Y)
{
- writeTileData (ofd, dx, dy, lx, ly, pixelData, pixelDataSize);
+ writeTileData (streamData, ofd, dx, dy, lx, ly, pixelData, pixelDataSize);
return;
}
-
+
//
// If the tiles cannot be written in random order, then check if a
// tile with coordinates (dx,dy,lx,ly) has already been buffered.
if (ofd->tileMap.find (currentTile) != ofd->tileMap.end())
{
- THROW (Iex::ArgExc,
- "Attempt to write tile "
- "(" << dx << ", " << dy << ", " << lx << "," << ly << ") "
- "more than once.");
+ THROW (IEX_NAMESPACE::ArgExc,
+ "Attempt to write tile "
+ "(" << dx << ", " << dy << ", " << lx << ", " << ly << ") "
+ "more than once.");
}
//
//
// Otherwise, buffer the tile so it can be written to file later.
//
-
+
if (ofd->nextTileToWrite == currentTile)
{
- writeTileData (ofd, dx, dy, lx, ly, pixelData, pixelDataSize);
+ writeTileData (streamData, ofd, dx, dy, lx, ly, pixelData, pixelDataSize);
ofd->nextTileToWrite = ofd->nextTileCoord (ofd->nextTileToWrite);
TileMap::iterator i = ofd->tileMap.find (ofd->nextTileToWrite);
-
+
//
// Step through the tiles and write all successive buffered tiles after
// the current one.
//
-
+
while(i != ofd->tileMap.end())
{
//
// Write the tile, and then delete the tile's buffered data
//
- writeTileData (ofd,
- i->first.dx, i->first.dy,
- i->first.lx, i->first.ly,
- i->second->pixelData,
- i->second->pixelDataSize);
+ writeTileData (streamData,
+ ofd,
+ i->first.dx, i->first.dy,
+ i->first.lx, i->first.ly,
+ i->second->pixelData,
+ i->second->pixelDataSize);
delete i->second;
ofd->tileMap.erase (i);
-
+
//
// Proceed to the next tile
//
-
+
ofd->nextTileToWrite = ofd->nextTileCoord (ofd->nextTileToWrite);
i = ofd->tileMap.find (ofd->nextTileToWrite);
}
// insert it into the tileMap.
//
- ofd->tileMap[currentTile] =
- new BufferedTile ((const char *)pixelData, pixelDataSize);
+ ofd->tileMap[currentTile] =
+ new BufferedTile ((const char *)pixelData, pixelDataSize);
}
}
void
convertToXdr (TiledOutputFile::Data *ofd,
Array<char>& tileBuffer,
- int numScanLines,
- int numPixelsPerScanLine)
+ int numScanLines,
+ int numPixelsPerScanLine)
{
//
- // Convert the contents of a TiledOutputFile's tileBuffer from the
+ // Convert the contents of a TiledOutputFile's tileBuffer from the
// machine's native representation to Xdr format. This function is called
// by writeTile(), below, if the compressor wanted its input pixel data
// in the machine's native format, but then failed to compress the data
for (int y = 0; y < numScanLines; ++y)
{
- //
- // Iterate over all slices in the file.
- //
-
- for (unsigned int i = 0; i < ofd->slices.size(); ++i)
- {
- const TOutSliceInfo &slice = ofd->slices[i];
-
- //
- // Convert the samples in place.
- //
-
+ //
+ // Iterate over all slices in the file.
+ //
+
+ for (unsigned int i = 0; i < ofd->slices.size(); ++i)
+ {
+ const TOutSliceInfo &slice = ofd->slices[i];
+
+ //
+ // Convert the samples in place.
+ //
+
convertInPlace (writePtr, readPtr, slice.type,
numPixelsPerScanLine);
- }
+ }
}
#ifdef DEBUG
- assert (writePtr == readPtr);
+ assert (writePtr == readPtr);
#endif
}
class TileBufferTask: public Task
{
public:
-
+
TileBufferTask (TaskGroup *group,
TiledOutputFile::Data *ofd,
int number,
- int dx, int dy,
- int lx, int ly);
-
+ int dx, int dy,
+ int lx, int ly);
+
virtual ~TileBufferTask ();
virtual void execute ();
-
+
private:
TiledOutputFile::Data * _ofd;
{
//
// First copy the pixel data from the frame buffer
- // into the tile buffer
+ // into the tile buffer
//
// Convert one tile's worth of pixel data to
// a machine-independent representation, and store
// the result in _tileBuffer->buffer.
//
-
+
char *writePtr = _tileBuffer->buffer;
-
- Box2i tileRange = Imf::dataWindowForTile (_ofd->tileDesc,
+
+ Box2i tileRange = dataWindowForTile (_ofd->tileDesc,
_ofd->minX, _ofd->maxX,
_ofd->minY, _ofd->maxY,
_tileBuffer->tileCoord.dx,
_tileBuffer->tileCoord.dy,
_tileBuffer->tileCoord.lx,
_tileBuffer->tileCoord.ly);
-
+
int numScanLines = tileRange.max.y - tileRange.min.y + 1;
int numPixelsPerScanLine = tileRange.max.x - tileRange.min.x + 1;
-
+
//
// Iterate over the scan lines in the tile.
//
-
+
for (int y = tileRange.min.y; y <= tileRange.max.y; ++y)
{
//
// Iterate over all image channels.
//
-
+
for (unsigned int i = 0; i < _ofd->slices.size(); ++i)
{
const TOutSliceInfo &slice = _ofd->slices[i];
-
+
//
// These offsets are used to facilitate both absolute
// and tile-relative pixel coordinates.
//
-
+
int xOffset = slice.xTileCoords * tileRange.min.x;
int yOffset = slice.yTileCoords * tileRange.min.y;
-
- //
- // Fill the tile buffer with pixel data.
- //
+
+ //
+ // Fill the tile buffer with pixel data.
+ //
if (slice.zero)
{
// The frame buffer contains no data for this channel.
// Store zeroes in _data->tileBuffer.
//
-
+
fillChannelWithZeroes (writePtr, _ofd->format, slice.type,
numPixelsPerScanLine);
}
//
// The frame buffer contains data for this channel.
//
-
+
const char *readPtr = slice.base +
(y - yOffset) * slice.yStride +
(tileRange.min.x - xOffset) *
const char *endPtr = readPtr +
(numPixelsPerScanLine - 1) *
slice.xStride;
-
+
copyFromFrameBuffer (writePtr, readPtr, endPtr,
slice.xStride, _ofd->format,
slice.type);
}
}
}
-
+
//
- // Compress the contents of the tileBuffer,
+ // Compress the contents of the tileBuffer,
// and store the compressed data in the output file.
//
-
+
_tileBuffer->dataSize = writePtr - _tileBuffer->buffer;
_tileBuffer->dataPtr = _tileBuffer->buffer;
-
+
if (_tileBuffer->compressor)
{
const char *compPtr;
(_tileBuffer->dataPtr,
_tileBuffer->dataSize,
tileRange, compPtr);
-
+
if (compSize < _tileBuffer->dataSize)
{
_tileBuffer->dataSize = compSize;
// we cannot write to the file using native format,
// so we need to convert the lineBuffer to Xdr.
//
-
+
convertToXdr (_ofd, _tileBuffer->buffer, numScanLines,
numPixelsPerScanLine);
}
const Header &header,
int numThreads)
:
- _data (new Data (true, numThreads))
+ _data (new Data (numThreads)),
+ _streamData (new OutputStreamMutex()),
+ _deleteStream (true)
{
try
{
- header.sanityCheck (true);
- _data->os = new StdOFStream (fileName);
- initialize (header);
+ header.sanityCheck (true);
+ _streamData->os = new StdOFStream (fileName);
+ _data->multipart=false; // since we opened with one header we can't be multipart
+ initialize (header);
+ _streamData->currentPosition = _streamData->os->tellp();
+
+ // Write header and empty offset table to the file.
+ writeMagicNumberAndVersionField(*_streamData->os, _data->header);
+ _data->previewPosition = _data->header.writeTo (*_streamData->os, true);
+ _data->tileOffsetsPosition = _data->tileOffsets.writeTo (*_streamData->os);
}
- catch (Iex::BaseExc &e)
+ catch (IEX_NAMESPACE::BaseExc &e)
{
- delete _data;
+ // ~TiledOutputFile will not run, so free memory here
+ delete _streamData->os;
+ delete _streamData;
+ delete _data;
- REPLACE_EXC (e, "Cannot open image file "
- "\"" << fileName << "\". " << e);
- throw;
+ REPLACE_EXC (e, "Cannot open image file "
+ "\"" << fileName << "\". " << e.what());
+ throw;
}
catch (...)
{
- delete _data;
+ // ~TiledOutputFile will not run, so free memory here
+ delete _streamData->os;
+ delete _streamData;
+ delete _data;
throw;
}
}
TiledOutputFile::TiledOutputFile
- (OStream &os,
+ (OPENEXR_IMF_INTERNAL_NAMESPACE::OStream &os,
const Header &header,
int numThreads)
:
- _data (new Data (false, numThreads))
+ _data (new Data (numThreads)),
+ _streamData (new OutputStreamMutex()),
+ _deleteStream (false)
{
try
{
- header.sanityCheck(true);
- _data->os = &os;
- initialize (header);
+ header.sanityCheck(true);
+ _streamData->os = &os;
+ _data->multipart=false; // since we opened with one header we can't be multipart
+ initialize (header);
+ _streamData->currentPosition = _streamData->os->tellp();
+
+ // Write header and empty offset table to the file.
+ writeMagicNumberAndVersionField(*_streamData->os, _data->header);
+ _data->previewPosition = _data->header.writeTo (*_streamData->os, true);
+ _data->tileOffsetsPosition = _data->tileOffsets.writeTo (*_streamData->os);
+
}
- catch (Iex::BaseExc &e)
+ catch (IEX_NAMESPACE::BaseExc &e)
{
- delete _data;
+ delete _streamData;
+ delete _data;
- REPLACE_EXC (e, "Cannot open image file "
- "\"" << os.fileName() << "\". " << e);
- throw;
+ REPLACE_EXC (e, "Cannot open image file "
+ "\"" << os.fileName() << "\". " << e.what());
+ throw;
}
catch (...)
{
- delete _data;
+ delete _streamData;
+ delete _data;
throw;
}
}
+TiledOutputFile::TiledOutputFile(const OutputPartData* part) :
+ _deleteStream (false)
+{
+ try
+ {
+ if (part->header.type() != TILEDIMAGE)
+ throw IEX_NAMESPACE::ArgExc("Can't build a TiledOutputFile from a type-mismatched part.");
+
+ _streamData = part->mutex;
+ _data = new Data(part->numThreads);
+ _data->multipart=part->multipart;
+ initialize(part->header);
+ _data->partNumber = part->partNumber;
+ _data->tileOffsetsPosition = part->chunkOffsetTablePosition;
+ _data->previewPosition = part->previewPosition;
+ }
+ catch (IEX_NAMESPACE::BaseExc &e)
+ {
+ delete _data;
+
+ REPLACE_EXC (e, "Cannot initialize output part "
+ "\"" << part->partNumber << "\". " << e.what());
+ throw;
+ }
+ catch (...)
+ {
+ delete _data;
+ throw;
+ }
+}
void
TiledOutputFile::initialize (const Header &header)
_data->header = header;
_data->lineOrder = _data->header.lineOrder();
+
+
//
// Check that the file is indeed tiled
//
_data->tileDesc = _data->header.tileDescription();
+
+ //
+ // 'Fix' the type attribute if it exists but is incorrectly set
+ // (attribute is optional, but ensure it is correct if it exists)
+ //
+ if(_data->header.hasType())
+ {
+ _data->header.setType(TILEDIMAGE);
+ }
+
+
//
// Save the dataWindow information
//
//
precalculateTileInfo (_data->tileDesc,
- _data->minX, _data->maxX,
- _data->minY, _data->maxY,
- _data->numXTiles, _data->numYTiles,
- _data->numXLevels, _data->numYLevels);
-
+ _data->minX, _data->maxX,
+ _data->minY, _data->maxY,
+ _data->numXTiles, _data->numYTiles,
+ _data->numXLevels, _data->numYLevels);
+
//
// Determine the first tile coordinate that we will be writing
// if the file is not RANDOM_Y.
//
-
+
_data->nextTileToWrite = (_data->lineOrder == INCREASING_Y)?
- TileCoord (0, 0, 0, 0):
- TileCoord (0, _data->numYTiles[0] - 1, 0, 0);
+ TileCoord (0, 0, 0, 0):
+ TileCoord (0, _data->numYTiles[0] - 1, 0, 0);
_data->maxBytesPerTileLine =
- calculateBytesPerPixel (_data->header) * _data->tileDesc.xSize;
+ calculateBytesPerPixel (_data->header) * _data->tileDesc.xSize;
_data->tileBufferSize = _data->maxBytesPerTileLine * _data->tileDesc.ySize;
-
+
//
// Create all the TileBuffers and allocate their internal buffers
//
for (size_t i = 0; i < _data->tileBuffers.size(); i++)
{
_data->tileBuffers[i] = new TileBuffer (newTileCompressor
- (_data->header.compression(),
- _data->maxBytesPerTileLine,
- _data->tileDesc.ySize,
- _data->header));
+ (_data->header.compression(),
+ _data->maxBytesPerTileLine,
+ _data->tileDesc.ySize,
+ _data->header));
_data->tileBuffers[i]->buffer.resizeErase(_data->tileBufferSize);
}
_data->format = defaultFormat (_data->tileBuffers[0]->compressor);
_data->tileOffsets = TileOffsets (_data->tileDesc.mode,
- _data->numXLevels,
- _data->numYLevels,
- _data->numXTiles,
- _data->numYTiles);
-
- _data->previewPosition = _data->header.writeTo (*_data->os, true);
-
- _data->tileOffsetsPosition = _data->tileOffsets.writeTo (*_data->os);
- _data->currentPosition = _data->os->tellp();
+ _data->numXLevels,
+ _data->numYLevels,
+ _data->numXTiles,
+ _data->numYTiles);
}
if (_data)
{
{
+ Lock lock(*_streamData);
+ Int64 originalPosition = _streamData->os->tellp();
+
if (_data->tileOffsetsPosition > 0)
{
try
{
- _data->os->seekp (_data->tileOffsetsPosition);
- _data->tileOffsets.writeTo (*_data->os);
+ _streamData->os->seekp (_data->tileOffsetsPosition);
+ _data->tileOffsets.writeTo (*_streamData->os);
+
+ //
+ // Restore the original position.
+ //
+ _streamData->os->seekp (originalPosition);
}
catch (...)
{
}
}
}
+
+ if (_deleteStream && _streamData)
+ delete _streamData->os;
+
+ if (_data->partNumber == -1)
+ delete _streamData;
delete _data;
}
const char *
TiledOutputFile::fileName () const
{
- return _data->os->fileName();
+ return _streamData->os->fileName();
}
}
-void
+void
TiledOutputFile::setFrameBuffer (const FrameBuffer &frameBuffer)
{
- Lock lock (*_data);
+ Lock lock (*_streamData);
//
// Check if the new frame buffer descriptor
const ChannelList &channels = _data->header.channels();
for (ChannelList::ConstIterator i = channels.begin();
- i != channels.end();
- ++i)
+ i != channels.end();
+ ++i)
{
- FrameBuffer::ConstIterator j = frameBuffer.find (i.name());
+ FrameBuffer::ConstIterator j = frameBuffer.find (i.name());
- if (j == frameBuffer.end())
- continue;
+ if (j == frameBuffer.end())
+ continue;
- if (i.channel().type != j.slice().type)
- THROW (Iex::ArgExc, "Pixel type of \"" << i.name() << "\" channel "
- "of output file \"" << fileName() << "\" is "
- "not compatible with the frame buffer's "
- "pixel type.");
+ if (i.channel().type != j.slice().type)
+ THROW (IEX_NAMESPACE::ArgExc, "Pixel type of \"" << i.name() << "\" channel "
+ "of output file \"" << fileName() << "\" is "
+ "not compatible with the frame buffer's "
+ "pixel type.");
- if (j.slice().xSampling != 1 || j.slice().ySampling != 1)
- THROW (Iex::ArgExc, "All channels in a tiled file must have"
- "sampling (1,1).");
+ if (j.slice().xSampling != 1 || j.slice().ySampling != 1)
+ THROW (IEX_NAMESPACE::ArgExc, "All channels in a tiled file must have"
+ "sampling (1,1).");
}
-
+
//
// Initialize slice table for writePixels().
//
vector<TOutSliceInfo> slices;
for (ChannelList::ConstIterator i = channels.begin();
- i != channels.end();
- ++i)
- {
- FrameBuffer::ConstIterator j = frameBuffer.find (i.name());
-
- if (j == frameBuffer.end())
- {
- //
- // Channel i is not present in the frame buffer.
- // In the file, channel i will contain only zeroes.
- //
-
- slices.push_back (TOutSliceInfo (i.channel().type,
- 0, // base
- 0, // xStride,
- 0, // yStride,
- true)); // zero
- }
- else
+ i != channels.end();
+ ++i)
{
- //
- // Channel i is present in the frame buffer.
- //
-
- slices.push_back (TOutSliceInfo (j.slice().type,
- j.slice().base,
- j.slice().xStride,
- j.slice().yStride,
- false, // zero
+ FrameBuffer::ConstIterator j = frameBuffer.find (i.name());
+
+ if (j == frameBuffer.end())
+ {
+ //
+ // Channel i is not present in the frame buffer.
+ // In the file, channel i will contain only zeroes.
+ //
+
+ slices.push_back (TOutSliceInfo (i.channel().type,
+ 0, // base
+ 0, // xStride,
+ 0, // yStride,
+ true)); // zero
+ }
+ else
+ {
+ //
+ // Channel i is present in the frame buffer.
+ //
+
+ slices.push_back (TOutSliceInfo (j.slice().type,
+ j.slice().base,
+ j.slice().xStride,
+ j.slice().yStride,
+ false, // zero
(j.slice().xTileCoords)? 1: 0,
(j.slice().yTileCoords)? 1: 0));
- }
+ }
}
//
const FrameBuffer &
TiledOutputFile::frameBuffer () const
{
- Lock lock (*_data);
+ Lock lock (*_streamData);
return _data->frameBuffer;
}
-void
+void
TiledOutputFile::writeTiles (int dx1, int dx2, int dy1, int dy2,
int lx, int ly)
{
try
{
- Lock lock (*_data);
+ Lock lock (*_streamData);
if (_data->slices.size() == 0)
- throw Iex::ArgExc ("No frame buffer specified "
- "as pixel data source.");
+ throw IEX_NAMESPACE::ArgExc ("No frame buffer specified "
+ "as pixel data source.");
- if (!isValidTile (dx1, dy1, lx, ly) || !isValidTile (dx2, dy2, lx, ly))
- throw Iex::ArgExc ("Tile coordinates are invalid.");
+ if (!isValidTile (dx1, dy1, lx, ly) || !isValidTile (dx2, dy2, lx, ly))
+ throw IEX_NAMESPACE::ArgExc ("Tile coordinates are invalid.");
+ if (!isValidLevel (lx, ly))
+ THROW (IEX_NAMESPACE::ArgExc,
+ "Level coordinate "
+ "(" << lx << ", " << ly << ") "
+ "is invalid.");
//
// Determine the first and last tile coordinates in both dimensions
// based on the file's lineOrder
//
-
+
if (dx1 > dx2)
swap (dx1, dx2);
-
+
if (dy1 > dy2)
swap (dy1, dy2);
-
+
int dyStart = dy1;
- int dyStop = dy2 + 1;
- int dY = 1;
-
+ int dyStop = dy2 + 1;
+ int dY = 1;
+
if (_data->lineOrder == DECREASING_Y)
{
dyStart = dy2;
dyStop = dy1 - 1;
dY = -1;
}
-
+
int numTiles = (dx2 - dx1 + 1) * (dy2 - dy1 + 1);
int numTasks = min ((int)_data->tileBuffers.size(), numTiles);
//
// Create a task group for all tile buffer tasks. When the
- // task group goes out of scope, the destructor waits until
- // all tasks are complete.
+ // task group goes out of scope, the destructor waits until
+ // all tasks are complete.
//
{
TaskGroup taskGroup;
-
+
//
// Add in the initial compression tasks to the thread pool
//
-
+
int nextCompBuffer = 0;
- int dxComp = dx1;
- int dyComp = dyStart;
+ int dxComp = dx1;
+ int dyComp = dyStart;
while (nextCompBuffer < numTasks)
{
dyComp += dY;
}
}
-
+
//
// Write the compressed buffers and add in more compression
- // tasks until done
+ // tasks until done
//
-
+
int nextWriteBuffer = 0;
- int dxWrite = dx1;
- int dyWrite = dyStart;
+ int dxWrite = dx1;
+ int dyWrite = dyStart;
while (nextWriteBuffer < numTiles)
{
- //
+ //
// Wait until the nextWriteBuffer is ready to be written
- //
+ //
TileBuffer* writeBuffer =
_data->getTileBuffer (nextWriteBuffer);
writeBuffer->wait();
-
- //
+
+ //
// Write the tilebuffer
- //
+ //
- bufferedTileWrite (_data, dxWrite, dyWrite, lx, ly,
+ bufferedTileWrite (_streamData, _data, dxWrite, dyWrite, lx, ly,
writeBuffer->dataPtr,
writeBuffer->dataSize);
-
- //
+
+ //
// Release the lock on nextWriteBuffer
- //
+ //
writeBuffer->post();
-
- //
+
+ //
// If there are no more tileBuffers to compress, then
- // only continue to write out remaining tileBuffers,
- // otherwise keep adding compression tasks.
- //
+ // only continue to write out remaining tileBuffers,
+ // otherwise keep adding compression tasks.
+ //
if (nextCompBuffer < numTiles)
{
- //
+ //
// add nextCompBuffer as a compression Task
- //
+ //
ThreadPool::addGlobalTask
- (new TileBufferTask (&taskGroup,
- _data,
- nextCompBuffer,
+ (new TileBufferTask (&taskGroup,
+ _data,
+ nextCompBuffer,
dxComp, dyComp,
- lx, ly));
+ lx, ly));
}
-
+
nextWriteBuffer++;
dxWrite++;
dxWrite = dx1;
dyWrite += dY;
}
-
+
nextCompBuffer++;
dxComp++;
}
}
- //
+ //
// finish all tasks
- //
+ //
}
- //
- // Exeption handling:
- //
- // TileBufferTask::execute() may have encountered exceptions, but
- // those exceptions occurred in another thread, not in the thread
- // that is executing this call to TiledOutputFile::writeTiles().
- // TileBufferTask::execute() has caught all exceptions and stored
- // the exceptions' what() strings in the tile buffers.
- // Now we check if any tile buffer contains a stored exception; if
- // this is the case then we re-throw the exception in this thread.
- // (It is possible that multiple tile buffers contain stored
- // exceptions. We re-throw the first exception we find and
- // ignore all others.)
- //
-
- const string *exception = 0;
-
- for (int i = 0; i < _data->tileBuffers.size(); ++i)
- {
+ //
+ // Exeption handling:
+ //
+ // TileBufferTask::execute() may have encountered exceptions, but
+ // those exceptions occurred in another thread, not in the thread
+ // that is executing this call to TiledOutputFile::writeTiles().
+ // TileBufferTask::execute() has caught all exceptions and stored
+ // the exceptions' what() strings in the tile buffers.
+ // Now we check if any tile buffer contains a stored exception; if
+ // this is the case then we re-throw the exception in this thread.
+ // (It is possible that multiple tile buffers contain stored
+ // exceptions. We re-throw the first exception we find and
+ // ignore all others.)
+ //
+
+ const string *exception = 0;
+
+ for (size_t i = 0; i < _data->tileBuffers.size(); ++i)
+ {
TileBuffer *tileBuffer = _data->tileBuffers[i];
- if (tileBuffer->hasException && !exception)
- exception = &tileBuffer->exception;
+ if (tileBuffer->hasException && !exception)
+ exception = &tileBuffer->exception;
- tileBuffer->hasException = false;
- }
+ tileBuffer->hasException = false;
+ }
- if (exception)
- throw Iex::IoExc (*exception);
+ if (exception)
+ throw IEX_NAMESPACE::IoExc (*exception);
}
- catch (Iex::BaseExc &e)
+ catch (IEX_NAMESPACE::BaseExc &e)
{
REPLACE_EXC (e, "Failed to write pixel data to image "
- "file \"" << fileName() << "\". " << e);
+ "file \"" << fileName() << "\". " << e.what());
throw;
}
}
-void
+void
TiledOutputFile::writeTiles (int dx1, int dxMax, int dyMin, int dyMax, int l)
{
writeTiles (dx1, dxMax, dyMin, dyMax, l, l);
}
-void
+void
TiledOutputFile::writeTile (int dx, int dy, int lx, int ly)
{
writeTiles (dx, dx, dy, dy, lx, ly);
}
-void
+void
TiledOutputFile::copyPixels (TiledInputFile &in)
{
- Lock lock (*_data);
+ Lock lock (*_streamData);
//
// Check if this file's and and the InputFile's
//
const Header &hdr = _data->header;
- const Header &inHdr = in.header();
+ const Header &inHdr = in.header();
if (!hdr.hasTileDescription() || !inHdr.hasTileDescription())
- THROW (Iex::ArgExc, "Cannot perform a quick pixel copy from image "
- "file \"" << in.fileName() << "\" to image "
- "file \"" << fileName() << "\". The "
+ THROW (IEX_NAMESPACE::ArgExc, "Cannot perform a quick pixel copy from image "
+ "file \"" << in.fileName() << "\" to image "
+ "file \"" << fileName() << "\". The "
"output file is tiled, but the input file is not. "
"Try using OutputFile::copyPixels() instead.");
if (!(hdr.tileDescription() == inHdr.tileDescription()))
- THROW (Iex::ArgExc, "Quick pixel copy from image "
- "file \"" << in.fileName() << "\" to image "
- "file \"" << fileName() << "\" failed. "
- "The files have different tile descriptions.");
+ THROW (IEX_NAMESPACE::ArgExc, "Quick pixel copy from image "
+ "file \"" << in.fileName() << "\" to image "
+ "file \"" << fileName() << "\" failed. "
+ "The files have different tile descriptions.");
if (!(hdr.dataWindow() == inHdr.dataWindow()))
- THROW (Iex::ArgExc, "Cannot copy pixels from image "
- "file \"" << in.fileName() << "\" to image "
- "file \"" << fileName() << "\". The "
+ THROW (IEX_NAMESPACE::ArgExc, "Cannot copy pixels from image "
+ "file \"" << in.fileName() << "\" to image "
+ "file \"" << fileName() << "\". The "
"files have different data windows.");
if (!(hdr.lineOrder() == inHdr.lineOrder()))
- THROW (Iex::ArgExc, "Quick pixel copy from image "
- "file \"" << in.fileName() << "\" to image "
- "file \"" << fileName() << "\" failed. "
- "The files have different line orders.");
+ THROW (IEX_NAMESPACE::ArgExc, "Quick pixel copy from image "
+ "file \"" << in.fileName() << "\" to image "
+ "file \"" << fileName() << "\" failed. "
+ "The files have different line orders.");
if (!(hdr.compression() == inHdr.compression()))
- THROW (Iex::ArgExc, "Quick pixel copy from image "
- "file \"" << in.fileName() << "\" to image "
- "file \"" << fileName() << "\" failed. "
- "The files use different compression methods.");
+ THROW (IEX_NAMESPACE::ArgExc, "Quick pixel copy from image "
+ "file \"" << in.fileName() << "\" to image "
+ "file \"" << fileName() << "\" failed. "
+ "The files use different compression methods.");
if (!(hdr.channels() == inHdr.channels()))
- THROW (Iex::ArgExc, "Quick pixel copy from image "
- "file \"" << in.fileName() << "\" to image "
- "file \"" << fileName() << "\" "
+ THROW (IEX_NAMESPACE::ArgExc, "Quick pixel copy from image "
+ "file \"" << in.fileName() << "\" to image "
+ "file \"" << fileName() << "\" "
"failed. The files have different channel "
"lists.");
//
if (!_data->tileOffsets.isEmpty())
- THROW (Iex::LogicExc, "Quick pixel copy from image "
- "file \"" << in.fileName() << "\" to image "
- "file \"" << _data->os->fileName() << "\" "
+ THROW (IEX_NAMESPACE::LogicExc, "Quick pixel copy from image "
+ "file \"" << in.fileName() << "\" to image "
+ "file \"" << _streamData->os->fileName() << "\" "
"failed. \"" << fileName() << "\" "
"already contains pixel data.");
case ONE_LEVEL:
case MIPMAP_LEVELS:
- for (size_t i_l = 0; i_l < numLevels (); ++i_l)
+ for (int i_l = 0; i_l < numLevels (); ++i_l)
numAllTiles += numXTiles (i_l) * numYTiles (i_l);
break;
case RIPMAP_LEVELS:
- for (size_t i_ly = 0; i_ly < numYLevels (); ++i_ly)
- for (size_t i_lx = 0; i_lx < numXLevels (); ++i_lx)
+ for (int i_ly = 0; i_ly < numYLevels (); ++i_ly)
+ for (int i_lx = 0; i_lx < numXLevels (); ++i_lx)
numAllTiles += numXTiles (i_lx) * numYTiles (i_ly);
break;
default:
- throw Iex::ArgExc ("Unknown LevelMode format.");
+ throw IEX_NAMESPACE::ArgExc ("Unknown LevelMode format.");
+ }
+
+ bool random_y = _data->lineOrder==RANDOM_Y;
+
+ std::vector<int> dx_table(random_y ? numAllTiles : 1);
+ std::vector<int> dy_table(random_y ? numAllTiles : 1);
+ std::vector<int> lx_table(random_y ? numAllTiles : 1);
+ std::vector<int> ly_table(random_y ? numAllTiles : 1);
+
+ if(random_y)
+ {
+ in.tileOrder(&dx_table[0],&dy_table[0],&lx_table[0],&ly_table[0]);
+ _data->nextTileToWrite.dx=dx_table[0];
+ _data->nextTileToWrite.dy=dy_table[0];
+ _data->nextTileToWrite.lx=lx_table[0];
+ _data->nextTileToWrite.ly=ly_table[0];
}
for (int i = 0; i < numAllTiles; ++i)
{
const char *pixelData;
int pixelDataSize;
-
+
int dx = _data->nextTileToWrite.dx;
int dy = _data->nextTileToWrite.dy;
int lx = _data->nextTileToWrite.lx;
int ly = _data->nextTileToWrite.ly;
+
in.rawTileData (dx, dy, lx, ly, pixelData, pixelDataSize);
- writeTileData (_data, dx, dy, lx, ly, pixelData, pixelDataSize);
+ writeTileData (_streamData, _data, dx, dy, lx, ly, pixelData, pixelDataSize);
+
+ if(random_y)
+ {
+ if(i<numAllTiles-1)
+ {
+ _data->nextTileToWrite.dx=dx_table[i+1];
+ _data->nextTileToWrite.dy=dy_table[i+1];
+ _data->nextTileToWrite.lx=lx_table[i+1];
+ _data->nextTileToWrite.ly=ly_table[i+1];
+ }
+ }else{
+ _data->nextTileToWrite=_data->nextTileCoord(_data->nextTileToWrite);
+ }
}
}
-void
+void
TiledOutputFile::copyPixels (InputFile &in)
{
copyPixels (*in.tFile());
}
+void
+TiledOutputFile::copyPixels (InputPart &in)
+{
+ copyPixels (*in.file);
+}
+
+void
+TiledOutputFile::copyPixels (TiledInputPart &in)
+{
+ copyPixels (*in.file);
+}
+
+
+
unsigned int
TiledOutputFile::tileXSize () const
{
TiledOutputFile::numLevels () const
{
if (levelMode() == RIPMAP_LEVELS)
- THROW (Iex::LogicExc, "Error calling numLevels() on image "
- "file \"" << fileName() << "\" "
- "(numLevels() is not defined for RIPMAPs).");
+ THROW (IEX_NAMESPACE::LogicExc, "Error calling numLevels() on image "
+ "file \"" << fileName() << "\" "
+ "(numLevels() is not defined for RIPMAPs).");
return _data->numXLevels;
}
}
-bool
+bool
TiledOutputFile::isValidLevel (int lx, int ly) const
{
if (lx < 0 || ly < 0)
- return false;
+ return false;
if (levelMode() == MIPMAP_LEVELS && lx != ly)
- return false;
+ return false;
if (lx >= numXLevels() || ly >= numYLevels())
- return false;
+ return false;
return true;
}
{
try
{
- int retVal = levelSize (_data->minX, _data->maxX, lx,
- _data->tileDesc.roundingMode);
-
+ int retVal = levelSize (_data->minX, _data->maxX, lx,
+ _data->tileDesc.roundingMode);
+
return retVal;
}
- catch (Iex::BaseExc &e)
+ catch (IEX_NAMESPACE::BaseExc &e)
{
- REPLACE_EXC (e, "Error calling levelWidth() on image "
- "file \"" << fileName() << "\". " << e);
- throw;
+ REPLACE_EXC (e, "Error calling levelWidth() on image "
+ "file \"" << fileName() << "\". " << e.what());
+ throw;
}
}
{
try
{
- return levelSize (_data->minY, _data->maxY, ly,
- _data->tileDesc.roundingMode);
+ return levelSize (_data->minY, _data->maxY, ly,
+ _data->tileDesc.roundingMode);
}
- catch (Iex::BaseExc &e)
+ catch (IEX_NAMESPACE::BaseExc &e)
{
- REPLACE_EXC (e, "Error calling levelHeight() on image "
- "file \"" << fileName() << "\". " << e);
- throw;
+ REPLACE_EXC (e, "Error calling levelHeight() on image "
+ "file \"" << fileName() << "\". " << e.what());
+ throw;
}
}
TiledOutputFile::numXTiles (int lx) const
{
if (lx < 0 || lx >= _data->numXLevels)
- THROW (Iex::LogicExc, "Error calling numXTiles() on image "
- "file \"" << _data->os->fileName() << "\" "
- "(Argument is not in valid range).");
+ THROW (IEX_NAMESPACE::LogicExc, "Error calling numXTiles() on image "
+ "file \"" << _streamData->os->fileName() << "\" "
+ "(Argument is not in valid range).");
return _data->numXTiles[lx];
}
TiledOutputFile::numYTiles (int ly) const
{
if (ly < 0 || ly >= _data->numYLevels)
- THROW (Iex::LogicExc, "Error calling numXTiles() on image "
- "file \"" << _data->os->fileName() << "\" "
- "(Argument is not in valid range).");
+ THROW (IEX_NAMESPACE::LogicExc, "Error calling numXTiles() on image "
+ "file \"" << _streamData->os->fileName() << "\" "
+ "(Argument is not in valid range).");
return _data->numYTiles[ly];
}
{
try
{
- return Imf::dataWindowForLevel (_data->tileDesc,
- _data->minX, _data->maxX,
- _data->minY, _data->maxY,
- lx, ly);
+ return OPENEXR_IMF_INTERNAL_NAMESPACE::dataWindowForLevel (
+ _data->tileDesc,
+ _data->minX, _data->maxX,
+ _data->minY, _data->maxY,
+ lx, ly);
}
- catch (Iex::BaseExc &e)
+ catch (IEX_NAMESPACE::BaseExc &e)
{
- REPLACE_EXC (e, "Error calling dataWindowForLevel() on image "
- "file \"" << fileName() << "\". " << e);
- throw;
+ REPLACE_EXC (e, "Error calling dataWindowForLevel() on image "
+ "file \"" << fileName() << "\". " << e.what());
+ throw;
}
}
{
try
{
- if (!isValidTile (dx, dy, lx, ly))
- throw Iex::ArgExc ("Arguments not in valid range.");
-
- return Imf::dataWindowForTile (_data->tileDesc,
- _data->minX, _data->maxX,
- _data->minY, _data->maxY,
- dx, dy,
- lx, ly);
+ if (!isValidTile (dx, dy, lx, ly))
+ throw IEX_NAMESPACE::ArgExc ("Arguments not in valid range.");
+
+ return OPENEXR_IMF_INTERNAL_NAMESPACE::dataWindowForTile (
+ _data->tileDesc,
+ _data->minX, _data->maxX,
+ _data->minY, _data->maxY,
+ dx, dy,
+ lx, ly);
}
- catch (Iex::BaseExc &e)
+ catch (IEX_NAMESPACE::BaseExc &e)
{
- REPLACE_EXC (e, "Error calling dataWindowForTile() on image "
- "file \"" << fileName() << "\". " << e);
- throw;
+ REPLACE_EXC (e, "Error calling dataWindowForTile() on image "
+ "file \"" << fileName() << "\". " << e.what());
+ throw;
}
}
TiledOutputFile::isValidTile (int dx, int dy, int lx, int ly) const
{
return ((lx < _data->numXLevels && lx >= 0) &&
- (ly < _data->numYLevels && ly >= 0) &&
- (dx < _data->numXTiles[lx] && dx >= 0) &&
- (dy < _data->numYTiles[ly] && dy >= 0));
+ (ly < _data->numYLevels && ly >= 0) &&
+ (dx < _data->numXTiles[lx] && dx >= 0) &&
+ (dy < _data->numYTiles[ly] && dy >= 0));
}
void
TiledOutputFile::updatePreviewImage (const PreviewRgba newPixels[])
{
- Lock lock (*_data);
+ Lock lock (*_streamData);
if (_data->previewPosition <= 0)
- THROW (Iex::LogicExc, "Cannot update preview image pixels. "
- "File \"" << fileName() << "\" does not "
- "contain a preview image.");
+ THROW (IEX_NAMESPACE::LogicExc, "Cannot update preview image pixels. "
+ "File \"" << fileName() << "\" does not "
+ "contain a preview image.");
//
// Store the new pixels in the header's preview image attribute.
//
PreviewImageAttribute &pia =
- _data->header.typedAttribute <PreviewImageAttribute> ("preview");
+ _data->header.typedAttribute <PreviewImageAttribute> ("preview");
PreviewImage &pi = pia.value();
PreviewRgba *pixels = pi.pixels();
int numPixels = pi.width() * pi.height();
for (int i = 0; i < numPixels; ++i)
- pixels[i] = newPixels[i];
+ pixels[i] = newPixels[i];
//
// Save the current file position, jump to the position in
// preview image, and jump back to the saved file position.
//
- Int64 savedPosition = _data->os->tellp();
+ Int64 savedPosition = _streamData->os->tellp();
try
{
- _data->os->seekp (_data->previewPosition);
- pia.writeValueTo (*_data->os, _data->version);
- _data->os->seekp (savedPosition);
+ _streamData->os->seekp (_data->previewPosition);
+ pia.writeValueTo (*_streamData->os, _data->version);
+ _streamData->os->seekp (savedPosition);
}
- catch (Iex::BaseExc &e)
+ catch (IEX_NAMESPACE::BaseExc &e)
{
- REPLACE_EXC (e, "Cannot update preview image pixels for "
- "file \"" << fileName() << "\". " << e);
- throw;
+ REPLACE_EXC (e, "Cannot update preview image pixels for "
+ "file \"" << fileName() << "\". " << e.what());
+ throw;
}
}
void
-TiledOutputFile::breakTile
+TiledOutputFile::breakTile
(int dx, int dy,
int lx, int ly,
int offset,
int length,
char c)
{
- Lock lock (*_data);
+ Lock lock (*_streamData);
Int64 position = _data->tileOffsets (dx, dy, lx, ly);
if (!position)
- THROW (Iex::ArgExc,
- "Cannot overwrite tile "
- "(" << dx << ", " << dy << ", " << lx << "," << ly << "). "
- "The tile has not yet been stored in "
- "file \"" << fileName() << "\".");
+ THROW (IEX_NAMESPACE::ArgExc,
+ "Cannot overwrite tile "
+ "(" << dx << ", " << dy << ", " << lx << "," << ly << "). "
+ "The tile has not yet been stored in "
+ "file \"" << fileName() << "\".");
- _data->currentPosition = 0;
- _data->os->seekp (position + offset);
+ _streamData->currentPosition = 0;
+ _streamData->os->seekp (position + offset);
for (int i = 0; i < length; ++i)
- _data->os->write (&c, 1);
+ _streamData->os->write (&c, 1);
}
-} // namespace Imf
+OPENEXR_IMF_INTERNAL_NAMESPACE_SOURCE_EXIT
//
// Copyright (c) 2004, Industrial Light & Magic, a division of Lucas
// Digital Ltd. LLC
-//
+//
// All rights reserved.
-//
+//
// Redistribution and use in source and binary forms, with or without
// modification, are permitted provided that the following conditions are
// met:
// distribution.
// * Neither the name of Industrial Light & Magic nor the names of
// its contributors may be used to endorse or promote products derived
-// from this software without specific prior written permission.
-//
+// from this software without specific prior written permission.
+//
// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
//
//-----------------------------------------------------------------------------
-#include <ImfHeader.h>
-#include <ImfFrameBuffer.h>
+#include "ImfHeader.h"
+#include "ImfFrameBuffer.h"
#include "ImathBox.h"
-#include <ImfTileDescription.h>
-#include <ImfThreading.h>
+#include "ImfTileDescription.h"
+#include "ImfThreading.h"
+#include "ImfGenericOutputFile.h"
+#include "ImfForward.h"
+#include "ImfNamespace.h"
+#include "ImfExport.h"
+
+
+OPENEXR_IMF_INTERNAL_NAMESPACE_HEADER_ENTER
-namespace Imf {
-class TiledInputFile;
-class InputFile;
struct PreviewRgba;
-class TiledOutputFile
+class TiledOutputFile : public GenericOutputFile
{
public:
// faster than reading the tiles in random order (see writeTile,
// below).
//-------------------------------------------------------------------
-
+
+ IMF_EXPORT
TiledOutputFile (const char fileName[],
- const Header &header,
+ const Header &header,
int numThreads = globalThreadCount ());
// close the corresponding files.
// ----------------------------------------------------------------
- TiledOutputFile (OStream &os,
- const Header &header,
+ IMF_EXPORT
+ TiledOutputFile (OPENEXR_IMF_INTERNAL_NAMESPACE::OStream &os,
+ const Header &header,
int numThreads = globalThreadCount ());
// Destroying a TiledOutputFile object before all tiles
// have been written results in an incomplete file.
//-----------------------------------------------------
-
+
+ IMF_EXPORT
virtual ~TiledOutputFile ();
//------------------------
// Access to the file name
//------------------------
-
+
+ IMF_EXPORT
const char * fileName () const;
//--------------------------
// Access to the file header
//--------------------------
-
+
+ IMF_EXPORT
const Header & header () const;
// called. The current frame buffer can be changed
// after each call to writeTile().
//-------------------------------------------------------
-
+
+ IMF_EXPORT
void setFrameBuffer (const FrameBuffer &frameBuffer);
//-----------------------------------
// Access to the current frame buffer
//-----------------------------------
-
+
+ IMF_EXPORT
const FrameBuffer & frameBuffer () const;
// fields of the file header's TileDescriptionAttribute.
//---------------------------------------------------------
+ IMF_EXPORT
unsigned int tileXSize () const;
+ IMF_EXPORT
unsigned int tileYSize () const;
+ IMF_EXPORT
LevelMode levelMode () const;
+ IMF_EXPORT
LevelRoundingMode levelRoundingMode () const;
// return value is the same as for numXLevels()
//
// if levelMode() == RIPMAP_LEVELS:
- // an Iex::LogicExc exception is thrown
+ // an IEX_NAMESPACE::LogicExc exception is thrown
//
- // isValidLevel(lx, ly) returns true if the file contains
+ // isValidLevel(lx, ly) returns true if the file contains
// a level with level number (lx, ly), false if not.
//
//--------------------------------------------------------------------
+ IMF_EXPORT
int numLevels () const;
+ IMF_EXPORT
int numXLevels () const;
+ IMF_EXPORT
int numYLevels () const;
+ IMF_EXPORT
bool isValidLevel (int lx, int ly) const;
//
//---------------------------------------------------------
+ IMF_EXPORT
int levelWidth (int lx) const;
+ IMF_EXPORT
int levelHeight (int ly) const;
//
//----------------------------------------------------------
+ IMF_EXPORT
int numXTiles (int lx = 0) const;
+ IMF_EXPORT
int numYTiles (int ly = 0) const;
//
//---------------------------------------------------------
- Imath::Box2i dataWindowForLevel (int l = 0) const;
- Imath::Box2i dataWindowForLevel (int lx, int ly) const;
+ IMF_EXPORT
+ IMATH_NAMESPACE::Box2i dataWindowForLevel (int l = 0) const;
+ IMF_EXPORT
+ IMATH_NAMESPACE::Box2i dataWindowForLevel (int lx, int ly) const;
//-------------------------------------------------------------------
//
//-------------------------------------------------------------------
- Imath::Box2i dataWindowForTile (int dx, int dy,
- int l = 0) const;
+ IMF_EXPORT
+ IMATH_NAMESPACE::Box2i dataWindowForTile (int dx, int dy,
+ int l = 0) const;
- Imath::Box2i dataWindowForTile (int dx, int dy,
- int lx, int ly) const;
+ IMF_EXPORT
+ IMATH_NAMESPACE::Box2i dataWindowForTile (int dx, int dy,
+ int lx, int ly) const;
//------------------------------------------------------------------
// Write pixel data:
// in a contiguous block. The levels are ordered
// like this:
//
- // (0, 0) (1, 0) ... (nx-1, 0)
- // (0, 1) (1, 1) ... (nx-1, 1)
+ // (0, 0) (1, 0) ... (nx-1, 0)
+ // (0, 1) (1, 1) ... (nx-1, 1)
// ...
- // (0,ny-1) (1,ny-1) ... (nx-1,ny-1)
+ // (0,ny-1) (1,ny-1) ... (nx-1,ny-1)
//
// where nx = numXLevels(), and ny = numYLevels().
// In an individual level, (lx, ly), the tiles
//
//------------------------------------------------------------------
+ IMF_EXPORT
void writeTile (int dx, int dy, int l = 0);
+ IMF_EXPORT
void writeTile (int dx, int dy, int lx, int ly);
+ IMF_EXPORT
void writeTiles (int dx1, int dx2, int dy1, int dy2,
int lx, int ly);
+ IMF_EXPORT
void writeTiles (int dx1, int dx2, int dy1, int dy2,
int l = 0);
// header: The two header's "dataWindow", "compression",
// "lineOrder", "channels", and "tiles" attributes must be the same.
//------------------------------------------------------------------
-
+
+ IMF_EXPORT
void copyPixels (TiledInputFile &in);
-
-
+ IMF_EXPORT
+ void copyPixels (TiledInputPart &in);
+
+
//------------------------------------------------------------------
// Shortcut to copy all pixels from an InputFile into this file,
// without uncompressing and then recompressing the pixel data.
//
// To use this function, the InputFile must be tiled.
//------------------------------------------------------------------
-
+
+ IMF_EXPORT
void copyPixels (InputFile &in);
+ IMF_EXPORT
+ void copyPixels (InputPart &in);
+
//--------------------------------------------------------------
// Updating the preview image:
// updatePreviewImage() supplies a new set of pixels for the
// preview image attribute in the file's header. If the header
// does not contain a preview image, updatePreviewImage() throws
- // an Iex::LogicExc.
+ // an IEX_NAMESPACE::LogicExc.
//
// Note: updatePreviewImage() is necessary because images are
// often stored in a file incrementally, a few tiles at a time,
//
//--------------------------------------------------------------
+ IMF_EXPORT
void updatePreviewImage (const PreviewRgba newPixels[]);
//-------------------------------------------------------------
// Break a tile -- for testing and debugging only:
- //
+ //
// breakTile(dx,dy,lx,ly,p,n,c) introduces an error into the
// output file by writing n copies of character c, starting
// p bytes from the beginning of the tile with tile coordinates
//
//-------------------------------------------------------------
+ IMF_EXPORT
void breakTile (int dx, int dy,
- int lx, int ly,
- int offset,
- int length,
- char c);
+ int lx, int ly,
+ int offset,
+ int length,
+ char c);
struct Data;
private:
+ // ----------------------------------------------------------------
+ // A constructor attaches the OutputStreamMutex to the
+ // given one from MultiPartOutputFile. Set the previewPosition
+ // and lineOffsetsPosition which have been acquired from
+ // the constructor of MultiPartOutputFile as well.
+ // ----------------------------------------------------------------
+ TiledOutputFile (const OutputPartData* part);
+
TiledOutputFile (const TiledOutputFile &); // not implemented
TiledOutputFile & operator = (const TiledOutputFile &); // not implemented
void initialize (const Header &header);
bool isValidTile (int dx, int dy,
- int lx, int ly) const;
+ int lx, int ly) const;
size_t bytesPerLineForTile (int dx, int dy,
- int lx, int ly) const;
+ int lx, int ly) const;
Data * _data;
+
+ OutputStreamMutex* _streamData;
+ bool _deleteStream;
+
+ friend class MultiPartOutputFile;
};
-} // namespace Imf
+OPENEXR_IMF_INTERNAL_NAMESPACE_HEADER_EXIT
#endif
--- /dev/null
+///////////////////////////////////////////////////////////////////////////
+//
+// Copyright (c) 2011, Industrial Light & Magic, a division of Lucas
+// Digital Ltd. LLC
+//
+// All rights reserved.
+//
+// Redistribution and use in source and binary forms, with or without
+// modification, are permitted provided that the following conditions are
+// met:
+// * Redistributions of source code must retain the above copyright
+// notice, this list of conditions and the following disclaimer.
+// * Redistributions in binary form must reproduce the above
+// copyright notice, this list of conditions and the following disclaimer
+// in the documentation and/or other materials provided with the
+// distribution.
+// * Neither the name of Industrial Light & Magic nor the names of
+// its contributors may be used to endorse or promote products derived
+// from this software without specific prior written permission.
+//
+// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+//
+///////////////////////////////////////////////////////////////////////////
+
+#include "ImfTiledOutputPart.h"
+#include "ImfNamespace.h"
+
+OPENEXR_IMF_INTERNAL_NAMESPACE_SOURCE_ENTER
+
+TiledOutputPart::TiledOutputPart(MultiPartOutputFile& multiPartFile, int partNumber)
+{
+ file = multiPartFile.getOutputPart<TiledOutputFile>(partNumber);
+}
+
+const char *
+TiledOutputPart::fileName () const
+{
+ return file->fileName();
+}
+
+const Header &
+TiledOutputPart::header () const
+{
+ return file->header();
+}
+
+void
+TiledOutputPart::setFrameBuffer (const FrameBuffer &frameBuffer)
+{
+ file->setFrameBuffer(frameBuffer);
+}
+
+const FrameBuffer &
+TiledOutputPart::frameBuffer () const
+{
+ return file->frameBuffer();
+}
+
+unsigned int
+TiledOutputPart::tileXSize () const
+{
+ return file->tileXSize();
+}
+
+unsigned int
+TiledOutputPart::tileYSize () const
+{
+ return file->tileYSize();
+}
+
+LevelMode
+TiledOutputPart::levelMode () const
+{
+ return file->levelMode();
+}
+
+LevelRoundingMode
+TiledOutputPart::levelRoundingMode () const
+{
+ return file->levelRoundingMode();
+}
+
+int
+TiledOutputPart::numLevels () const
+{
+ return file->numLevels();
+}
+
+int
+TiledOutputPart::numXLevels () const
+{
+ return file->numXLevels();
+}
+
+int
+TiledOutputPart::numYLevels () const
+{
+ return file->numYLevels();
+}
+
+bool
+TiledOutputPart::isValidLevel (int lx, int ly) const
+{
+ return file->isValidLevel(lx, ly);
+}
+
+int
+TiledOutputPart::levelWidth (int lx) const
+{
+ return file->levelWidth(lx);
+}
+
+int
+TiledOutputPart::levelHeight (int ly) const
+{
+ return file->levelHeight(ly);
+}
+
+int
+TiledOutputPart::numXTiles (int lx) const
+{
+ return file->numXTiles(lx);
+}
+
+int
+TiledOutputPart::numYTiles (int ly) const
+{
+ return file->numYTiles(ly);
+}
+
+IMATH_NAMESPACE::Box2i
+TiledOutputPart::dataWindowForLevel (int l) const
+{
+ return file->dataWindowForLevel(l);
+}
+
+IMATH_NAMESPACE::Box2i
+TiledOutputPart::dataWindowForLevel (int lx, int ly) const
+{
+ return file->dataWindowForLevel(lx, ly);
+}
+
+IMATH_NAMESPACE::Box2i
+TiledOutputPart::dataWindowForTile (int dx, int dy, int l) const
+{
+ return file->dataWindowForTile(dx, dy, l);
+}
+
+IMATH_NAMESPACE::Box2i
+TiledOutputPart::dataWindowForTile (int dx, int dy, int lx, int ly) const
+{
+ return file->dataWindowForTile(dx, dy, lx, ly);
+}
+
+void
+TiledOutputPart::writeTile (int dx, int dy, int l)
+{
+ file->writeTile(dx, dy, l);
+}
+
+void
+TiledOutputPart::writeTile (int dx, int dy, int lx, int ly)
+{
+ file->writeTile(dx, dy, lx, ly);
+}
+
+void
+TiledOutputPart::writeTiles (int dx1, int dx2, int dy1, int dy2, int lx, int ly)
+{
+ file->writeTiles(dx1, dx2, dy1, dy2, lx, ly);
+}
+
+void
+TiledOutputPart::writeTiles (int dx1, int dx2, int dy1, int dy2, int l)
+{
+ file->writeTiles(dx1, dx2, dy1, dy2, l);
+}
+
+void
+TiledOutputPart::copyPixels (TiledInputFile &in)
+{
+ file->copyPixels(in);
+}
+
+void
+TiledOutputPart::copyPixels (InputFile &in)
+{
+ file->copyPixels(in);
+}
+
+void
+TiledOutputPart::copyPixels (TiledInputPart &in)
+{
+ file->copyPixels(in);
+}
+
+void
+TiledOutputPart::copyPixels (InputPart &in)
+{
+ file->copyPixels(in);
+}
+
+
+
+void
+TiledOutputPart::updatePreviewImage (const PreviewRgba newPixels[])
+{
+ file->updatePreviewImage(newPixels);
+}
+
+void
+TiledOutputPart::breakTile (int dx, int dy, int lx, int ly, int offset, int length, char c)
+{
+ file->breakTile(dx, dy, lx, ly, offset, length, c);
+}
+
+
+OPENEXR_IMF_INTERNAL_NAMESPACE_SOURCE_EXIT
--- /dev/null
+///////////////////////////////////////////////////////////////////////////
+//
+// Copyright (c) 2011, Industrial Light & Magic, a division of Lucas
+// Digital Ltd. LLC
+//
+// All rights reserved.
+//
+// Redistribution and use in source and binary forms, with or without
+// modification, are permitted provided that the following conditions are
+// met:
+// * Redistributions of source code must retain the above copyright
+// notice, this list of conditions and the following disclaimer.
+// * Redistributions in binary form must reproduce the above
+// copyright notice, this list of conditions and the following disclaimer
+// in the documentation and/or other materials provided with the
+// distribution.
+// * Neither the name of Industrial Light & Magic nor the names of
+// its contributors may be used to endorse or promote products derived
+// from this software without specific prior written permission.
+//
+// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+//
+///////////////////////////////////////////////////////////////////////////
+
+#ifndef IMFTILEDOUTPUTPART_H_
+#define IMFTILEDOUTPUTPART_H_
+
+#include "ImfMultiPartOutputFile.h"
+#include "ImfTiledOutputFile.h"
+#include "ImfForward.h"
+#include "ImfExport.h"
+#include "ImfNamespace.h"
+
+
+OPENEXR_IMF_INTERNAL_NAMESPACE_HEADER_ENTER
+
+//-------------------------------------------------------------------------------
+// class TiledOutputPart:
+//
+// Same interface as TiledOutputFile. Please have a reference to TiledOutputFile.
+//-------------------------------------------------------------------------------
+
+class TiledOutputPart
+{
+ public:
+ IMF_EXPORT
+ TiledOutputPart(MultiPartOutputFile& multiPartFile, int partNumber);
+
+ IMF_EXPORT
+ const char * fileName () const;
+ IMF_EXPORT
+ const Header & header () const;
+ IMF_EXPORT
+ void setFrameBuffer (const FrameBuffer &frameBuffer);
+ IMF_EXPORT
+ const FrameBuffer & frameBuffer () const;
+ IMF_EXPORT
+ unsigned int tileXSize () const;
+ IMF_EXPORT
+ unsigned int tileYSize () const;
+ IMF_EXPORT
+ LevelMode levelMode () const;
+ IMF_EXPORT
+ LevelRoundingMode levelRoundingMode () const;
+ IMF_EXPORT
+ int numLevels () const;
+ IMF_EXPORT
+ int numXLevels () const;
+ IMF_EXPORT
+ int numYLevels () const;
+ IMF_EXPORT
+ bool isValidLevel (int lx, int ly) const;
+ IMF_EXPORT
+ int levelWidth (int lx) const;
+ IMF_EXPORT
+ int levelHeight (int ly) const;
+ IMF_EXPORT
+ int numXTiles (int lx = 0) const;
+ IMF_EXPORT
+ int numYTiles (int ly = 0) const;
+ IMF_EXPORT
+ IMATH_NAMESPACE::Box2i dataWindowForLevel (int l = 0) const;
+ IMF_EXPORT
+ IMATH_NAMESPACE::Box2i dataWindowForLevel (int lx, int ly) const;
+ IMF_EXPORT
+ IMATH_NAMESPACE::Box2i dataWindowForTile (int dx, int dy,
+ int l = 0) const;
+ IMF_EXPORT
+ IMATH_NAMESPACE::Box2i dataWindowForTile (int dx, int dy,
+ int lx, int ly) const;
+ IMF_EXPORT
+ void writeTile (int dx, int dy, int l = 0);
+ IMF_EXPORT
+ void writeTile (int dx, int dy, int lx, int ly);
+ IMF_EXPORT
+ void writeTiles (int dx1, int dx2, int dy1, int dy2,
+ int lx, int ly);
+ IMF_EXPORT
+ void writeTiles (int dx1, int dx2, int dy1, int dy2,
+ int l = 0);
+ IMF_EXPORT
+ void copyPixels (TiledInputFile &in);
+ IMF_EXPORT
+ void copyPixels (InputFile &in);
+ IMF_EXPORT
+ void copyPixels (TiledInputPart &in);
+ IMF_EXPORT
+ void copyPixels (InputPart &in);
+
+
+ IMF_EXPORT
+ void updatePreviewImage (const PreviewRgba newPixels[]);
+ IMF_EXPORT
+ void breakTile (int dx, int dy,
+ int lx, int ly,
+ int offset,
+ int length,
+ char c);
+
+ private:
+ TiledOutputFile* file;
+};
+
+OPENEXR_IMF_INTERNAL_NAMESPACE_HEADER_EXIT
+
+#endif /* IMFTILEDOUTPUTPART_H_ */
//
// Copyright (c) 2004, Industrial Light & Magic, a division of Lucas
// Digital Ltd. LLC
-//
+//
// All rights reserved.
-//
+//
// Redistribution and use in source and binary forms, with or without
// modification, are permitted provided that the following conditions are
// met:
// distribution.
// * Neither the name of Industrial Light & Magic nor the names of
// its contributors may be used to endorse or promote products derived
-// from this software without specific prior written permission.
-//
+// from this software without specific prior written permission.
+//
// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
#include "IlmThreadMutex.h"
#include "Iex.h"
+#include "ImfNamespace.h"
-namespace Imf {
+OPENEXR_IMF_INTERNAL_NAMESPACE_SOURCE_ENTER
using namespace std;
-using namespace Imath;
+using namespace IMATH_NAMESPACE;
using namespace RgbaYca;
-using namespace IlmThread;
+using namespace ILMTHREAD_NAMESPACE;
namespace {
void
insertChannels (Header &header,
- RgbaChannels rgbaChannels,
- const char fileName[])
+ RgbaChannels rgbaChannels,
+ const char fileName[])
{
ChannelList ch;
if (rgbaChannels & (WRITE_Y | WRITE_C))
{
- if (rgbaChannels & WRITE_Y)
- {
- ch.insert ("Y", Channel (HALF, 1, 1));
- }
-
- if (rgbaChannels & WRITE_C)
- {
- THROW (Iex::ArgExc, "Cannot open file \"" << fileName << "\" "
- "for writing. Tiled image files do not "
- "support subsampled chroma channels.");
- }
+ if (rgbaChannels & WRITE_Y)
+ {
+ ch.insert ("Y", Channel (HALF, 1, 1));
+ }
+
+ if (rgbaChannels & WRITE_C)
+ {
+ THROW (IEX_NAMESPACE::ArgExc, "Cannot open file \"" << fileName << "\" "
+ "for writing. Tiled image files do not "
+ "support subsampled chroma channels.");
+ }
}
else
{
- if (rgbaChannels & WRITE_R)
- ch.insert ("R", Channel (HALF, 1, 1));
+ if (rgbaChannels & WRITE_R)
+ ch.insert ("R", Channel (HALF, 1, 1));
- if (rgbaChannels & WRITE_G)
- ch.insert ("G", Channel (HALF, 1, 1));
+ if (rgbaChannels & WRITE_G)
+ ch.insert ("G", Channel (HALF, 1, 1));
- if (rgbaChannels & WRITE_B)
- ch.insert ("B", Channel (HALF, 1, 1));
+ if (rgbaChannels & WRITE_B)
+ ch.insert ("B", Channel (HALF, 1, 1));
}
if (rgbaChannels & WRITE_A)
- ch.insert ("A", Channel (HALF, 1, 1));
+ ch.insert ("A", Channel (HALF, 1, 1));
header.channels() = ch;
}
int i = 0;
if (ch.findChannel (channelNamePrefix + "R"))
- i |= WRITE_R;
+ i |= WRITE_R;
if (ch.findChannel (channelNamePrefix + "G"))
- i |= WRITE_G;
-
+ i |= WRITE_G;
+
if (ch.findChannel (channelNamePrefix + "B"))
- i |= WRITE_B;
+ i |= WRITE_B;
if (ch.findChannel (channelNamePrefix + "A"))
- i |= WRITE_A;
+ i |= WRITE_A;
if (ch.findChannel (channelNamePrefix + "Y"))
- i |= WRITE_Y;
+ i |= WRITE_Y;
return RgbaChannels (i);
}
prefixFromLayerName (const string &layerName, const Header &header)
{
if (layerName.empty())
- return "";
+ return "";
if (hasMultiView (header) && multiView(header)[0] == layerName)
- return "";
+ return "";
return layerName + ".";
}
Chromaticities cr;
if (hasChromaticities (header))
- cr = chromaticities (header);
+ cr = chromaticities (header);
return computeYw (cr);
}
ToYa (TiledOutputFile &outputFile, RgbaChannels rgbaChannels);
void setFrameBuffer (const Rgba *base,
- size_t xStride,
- size_t yStride);
+ size_t xStride,
+ size_t yStride);
void writeTile (int dx, int dy, int lx, int ly);
TiledRgbaOutputFile::ToYa::ToYa (TiledOutputFile &outputFile,
- RgbaChannels rgbaChannels)
+ RgbaChannels rgbaChannels)
:
_outputFile (outputFile)
{
_writeA = (rgbaChannels & WRITE_A)? true: false;
-
+
const TileDescription &td = outputFile.header().tileDescription();
_tileXSize = td.xSize;
void
TiledRgbaOutputFile::ToYa::setFrameBuffer (const Rgba *base,
- size_t xStride,
- size_t yStride)
+ size_t xStride,
+ size_t yStride)
{
_fbBase = base;
_fbXStride = xStride;
{
if (_fbBase == 0)
{
- THROW (Iex::ArgExc, "No frame buffer was specified as the "
- "pixel data source for image file "
- "\"" << _outputFile.fileName() << "\".");
+ THROW (IEX_NAMESPACE::ArgExc, "No frame buffer was specified as the "
+ "pixel data source for image file "
+ "\"" << _outputFile.fileName() << "\".");
}
//
for (int y = dw.min.y, y1 = 0; y <= dw.max.y; ++y, ++y1)
{
- for (int x = dw.min.x, x1 = 0; x <= dw.max.x; ++x, ++x1)
- _buf[y1][x1] = _fbBase[x * _fbXStride + y * _fbYStride];
+ for (int x = dw.min.x, x1 = 0; x <= dw.max.x; ++x, ++x1)
+ _buf[y1][x1] = _fbBase[x * _fbXStride + y * _fbYStride];
- RGBAtoYCA (_yw, width, _writeA, _buf[y1], _buf[y1]);
+ RGBAtoYCA (_yw, width, _writeA, _buf[y1], _buf[y1]);
}
//
FrameBuffer fb;
fb.insert ("Y", Slice (HALF, // type
- (char *) &_buf[-dw.min.y][-dw.min.x].g, // base
- sizeof (Rgba), // xStride
- sizeof (Rgba) * _tileXSize)); // yStride
+ (char *) &_buf[-dw.min.y][-dw.min.x].g, // base
+ sizeof (Rgba), // xStride
+ sizeof (Rgba) * _tileXSize)); // yStride
fb.insert ("A", Slice (HALF, // type
- (char *) &_buf[-dw.min.y][-dw.min.x].a, // base
- sizeof (Rgba), // xStride
- sizeof (Rgba) * _tileXSize)); // yStride
+ (char *) &_buf[-dw.min.y][-dw.min.x].a, // base
+ sizeof (Rgba), // xStride
+ sizeof (Rgba) * _tileXSize)); // yStride
_outputFile.setFrameBuffer (fb);
_outputFile.writeTile (dx, dy, lx, ly);
_outputFile = new TiledOutputFile (name, hd, numThreads);
if (rgbaChannels & WRITE_Y)
- _toYa = new ToYa (*_outputFile, rgbaChannels);
+ _toYa = new ToYa (*_outputFile, rgbaChannels);
}
TiledRgbaOutputFile::TiledRgbaOutputFile
- (OStream &os,
+ (OPENEXR_IMF_INTERNAL_NAMESPACE::OStream &os,
const Header &header,
RgbaChannels rgbaChannels,
int tileXSize,
_outputFile = new TiledOutputFile (os, hd, numThreads);
if (rgbaChannels & WRITE_Y)
- _toYa = new ToYa (*_outputFile, rgbaChannels);
+ _toYa = new ToYa (*_outputFile, rgbaChannels);
}
int tileYSize,
LevelMode mode,
LevelRoundingMode rmode,
- const Imath::Box2i &displayWindow,
- const Imath::Box2i &dataWindow,
+ const IMATH_NAMESPACE::Box2i &displayWindow,
+ const IMATH_NAMESPACE::Box2i &dataWindow,
RgbaChannels rgbaChannels,
float pixelAspectRatio,
- const Imath::V2f screenWindowCenter,
+ const IMATH_NAMESPACE::V2f screenWindowCenter,
float screenWindowWidth,
LineOrder lineOrder,
Compression compression,
_toYa (0)
{
Header hd (displayWindow,
- dataWindow.isEmpty()? displayWindow: dataWindow,
- pixelAspectRatio,
- screenWindowCenter,
- screenWindowWidth,
- lineOrder,
- compression);
+ dataWindow.isEmpty()? displayWindow: dataWindow,
+ pixelAspectRatio,
+ screenWindowCenter,
+ screenWindowWidth,
+ lineOrder,
+ compression);
insertChannels (hd, rgbaChannels, name);
hd.setTileDescription (TileDescription (tileXSize, tileYSize, mode, rmode));
_outputFile = new TiledOutputFile (name, hd, numThreads);
if (rgbaChannels & WRITE_Y)
- _toYa = new ToYa (*_outputFile, rgbaChannels);
+ _toYa = new ToYa (*_outputFile, rgbaChannels);
}
LevelRoundingMode rmode,
RgbaChannels rgbaChannels,
float pixelAspectRatio,
- const Imath::V2f screenWindowCenter,
+ const IMATH_NAMESPACE::V2f screenWindowCenter,
float screenWindowWidth,
LineOrder lineOrder,
Compression compression,
_toYa (0)
{
Header hd (width,
- height,
- pixelAspectRatio,
- screenWindowCenter,
- screenWindowWidth,
- lineOrder,
- compression);
+ height,
+ pixelAspectRatio,
+ screenWindowCenter,
+ screenWindowWidth,
+ lineOrder,
+ compression);
insertChannels (hd, rgbaChannels, name);
hd.setTileDescription (TileDescription (tileXSize, tileYSize, mode, rmode));
_outputFile = new TiledOutputFile (name, hd, numThreads);
if (rgbaChannels & WRITE_Y)
- _toYa = new ToYa (*_outputFile, rgbaChannels);
+ _toYa = new ToYa (*_outputFile, rgbaChannels);
}
void
TiledRgbaOutputFile::setFrameBuffer (const Rgba *base,
- size_t xStride,
- size_t yStride)
+ size_t xStride,
+ size_t yStride)
{
if (_toYa)
{
- Lock lock (*_toYa);
- _toYa->setFrameBuffer (base, xStride, yStride);
+ Lock lock (*_toYa);
+ _toYa->setFrameBuffer (base, xStride, yStride);
}
else
{
- size_t xs = xStride * sizeof (Rgba);
- size_t ys = yStride * sizeof (Rgba);
+ size_t xs = xStride * sizeof (Rgba);
+ size_t ys = yStride * sizeof (Rgba);
- FrameBuffer fb;
+ FrameBuffer fb;
- fb.insert ("R", Slice (HALF, (char *) &base[0].r, xs, ys));
- fb.insert ("G", Slice (HALF, (char *) &base[0].g, xs, ys));
- fb.insert ("B", Slice (HALF, (char *) &base[0].b, xs, ys));
- fb.insert ("A", Slice (HALF, (char *) &base[0].a, xs, ys));
+ fb.insert ("R", Slice (HALF, (char *) &base[0].r, xs, ys));
+ fb.insert ("G", Slice (HALF, (char *) &base[0].g, xs, ys));
+ fb.insert ("B", Slice (HALF, (char *) &base[0].b, xs, ys));
+ fb.insert ("A", Slice (HALF, (char *) &base[0].a, xs, ys));
- _outputFile->setFrameBuffer (fb);
+ _outputFile->setFrameBuffer (fb);
}
}
}
-const Imath::Box2i &
+const IMATH_NAMESPACE::Box2i &
TiledRgbaOutputFile::displayWindow () const
{
return _outputFile->header().displayWindow();
}
-const Imath::Box2i &
+const IMATH_NAMESPACE::Box2i &
TiledRgbaOutputFile::dataWindow () const
{
return _outputFile->header().dataWindow();
}
-float
+float
TiledRgbaOutputFile::pixelAspectRatio () const
{
return _outputFile->header().pixelAspectRatio();
}
-const Imath::V2f
+const IMATH_NAMESPACE::V2f
TiledRgbaOutputFile::screenWindowCenter () const
{
return _outputFile->header().screenWindowCenter();
}
-float
+float
TiledRgbaOutputFile::screenWindowWidth () const
{
return _outputFile->header().screenWindowWidth();
}
-Imath::Box2i
+IMATH_NAMESPACE::Box2i
TiledRgbaOutputFile::dataWindowForLevel (int l) const
{
return _outputFile->dataWindowForLevel (l);
}
-Imath::Box2i
+IMATH_NAMESPACE::Box2i
TiledRgbaOutputFile::dataWindowForLevel (int lx, int ly) const
{
return _outputFile->dataWindowForLevel (lx, ly);
}
-Imath::Box2i
+IMATH_NAMESPACE::Box2i
TiledRgbaOutputFile::dataWindowForTile (int dx, int dy, int l) const
{
return _outputFile->dataWindowForTile (dx, dy, l);
}
-Imath::Box2i
+IMATH_NAMESPACE::Box2i
TiledRgbaOutputFile::dataWindowForTile (int dx, int dy, int lx, int ly) const
{
return _outputFile->dataWindowForTile (dx, dy, lx, ly);
{
if (_toYa)
{
- Lock lock (*_toYa);
- _toYa->writeTile (dx, dy, l, l);
+ Lock lock (*_toYa);
+ _toYa->writeTile (dx, dy, l, l);
}
else
{
- _outputFile->writeTile (dx, dy, l);
+ _outputFile->writeTile (dx, dy, l);
}
}
{
if (_toYa)
{
- Lock lock (*_toYa);
- _toYa->writeTile (dx, dy, lx, ly);
+ Lock lock (*_toYa);
+ _toYa->writeTile (dx, dy, lx, ly);
}
else
{
- _outputFile->writeTile (dx, dy, lx, ly);
+ _outputFile->writeTile (dx, dy, lx, ly);
}
}
-void
+void
TiledRgbaOutputFile::writeTiles
(int dxMin, int dxMax, int dyMin, int dyMax, int lx, int ly)
{
if (_toYa)
{
- Lock lock (*_toYa);
+ Lock lock (*_toYa);
for (int dy = dyMin; dy <= dyMax; dy++)
for (int dx = dxMin; dx <= dxMax; dx++)
- _toYa->writeTile (dx, dy, lx, ly);
+ _toYa->writeTile (dx, dy, lx, ly);
}
else
{
}
}
-void
+void
TiledRgbaOutputFile::writeTiles
(int dxMin, int dxMax, int dyMin, int dyMax, int l)
{
FromYa (TiledInputFile &inputFile);
void setFrameBuffer (Rgba *base,
- size_t xStride,
- size_t yStride,
- const string &channelNamePrefix);
+ size_t xStride,
+ size_t yStride,
+ const string &channelNamePrefix);
void readTile (int dx, int dy, int lx, int ly);
void
TiledRgbaInputFile::FromYa::setFrameBuffer (Rgba *base,
- size_t xStride,
- size_t yStride,
- const string &channelNamePrefix)
+ size_t xStride,
+ size_t yStride,
+ const string &channelNamePrefix)
{
if (_fbBase == 0)
{
- FrameBuffer fb;
-
- fb.insert (channelNamePrefix + "Y",
- Slice (HALF, // type
- (char *) &_buf[0][0].g, // base
- sizeof (Rgba), // xStride
- sizeof (Rgba) * _tileXSize, // yStride
- 1, 1, // sampling
- 0.0, // fillValue
- true, true)); // tileCoordinates
-
- fb.insert (channelNamePrefix + "A",
- Slice (HALF, // type
- (char *) &_buf[0][0].a, // base
- sizeof (Rgba), // xStride
- sizeof (Rgba) * _tileXSize, // yStride
- 1, 1, // sampling
- 1.0, // fillValue
- true, true)); // tileCoordinates
-
- _inputFile.setFrameBuffer (fb);
+ FrameBuffer fb;
+
+ fb.insert (channelNamePrefix + "Y",
+ Slice (HALF, // type
+ (char *) &_buf[0][0].g, // base
+ sizeof (Rgba), // xStride
+ sizeof (Rgba) * _tileXSize, // yStride
+ 1, 1, // sampling
+ 0.0, // fillValue
+ true, true)); // tileCoordinates
+
+ fb.insert (channelNamePrefix + "A",
+ Slice (HALF, // type
+ (char *) &_buf[0][0].a, // base
+ sizeof (Rgba), // xStride
+ sizeof (Rgba) * _tileXSize, // yStride
+ 1, 1, // sampling
+ 1.0, // fillValue
+ true, true)); // tileCoordinates
+
+ _inputFile.setFrameBuffer (fb);
}
_fbBase = base;
{
if (_fbBase == 0)
{
- THROW (Iex::ArgExc, "No frame buffer was specified as the "
- "pixel data destination for image file "
- "\"" << _inputFile.fileName() << "\".");
+ THROW (IEX_NAMESPACE::ArgExc, "No frame buffer was specified as the "
+ "pixel data destination for image file "
+ "\"" << _inputFile.fileName() << "\".");
}
//
// Read the tile requested by the caller into _buf.
//
-
+
_inputFile.readTile (dx, dy, lx, ly);
//
for (int y = dw.min.y, y1 = 0; y <= dw.max.y; ++y, ++y1)
{
- for (int x1 = 0; x1 < width; ++x1)
- {
- _buf[y1][x1].r = 0;
- _buf[y1][x1].b = 0;
- }
-
- YCAtoRGBA (_yw, width, _buf[y1], _buf[y1]);
-
- for (int x = dw.min.x, x1 = 0; x <= dw.max.x; ++x, ++x1)
- {
- _fbBase[x * _fbXStride + y * _fbYStride] = _buf[y1][x1];
- }
+ for (int x1 = 0; x1 < width; ++x1)
+ {
+ _buf[y1][x1].r = 0;
+ _buf[y1][x1].b = 0;
+ }
+
+ YCAtoRGBA (_yw, width, _buf[y1], _buf[y1]);
+
+ for (int x = dw.min.x, x1 = 0; x <= dw.max.x; ++x, ++x1)
+ {
+ _fbBase[x * _fbXStride + y * _fbYStride] = _buf[y1][x1];
+ }
}
}
_channelNamePrefix ("")
{
if (channels() & WRITE_Y)
- _fromYa = new FromYa (*_inputFile);
+ _fromYa = new FromYa (*_inputFile);
}
-TiledRgbaInputFile::TiledRgbaInputFile (IStream &is, int numThreads):
+TiledRgbaInputFile::TiledRgbaInputFile (OPENEXR_IMF_INTERNAL_NAMESPACE::IStream &is, int numThreads):
_inputFile (new TiledInputFile (is, numThreads)),
_fromYa (0),
_channelNamePrefix ("")
{
if (channels() & WRITE_Y)
- _fromYa = new FromYa (*_inputFile);
+ _fromYa = new FromYa (*_inputFile);
}
TiledRgbaInputFile::TiledRgbaInputFile (const char name[],
- const string &layerName,
- int numThreads)
+ const string &layerName,
+ int numThreads)
:
_inputFile (new TiledInputFile (name, numThreads)),
_fromYa (0),
_channelNamePrefix (prefixFromLayerName (layerName, _inputFile->header()))
{
if (channels() & WRITE_Y)
- _fromYa = new FromYa (*_inputFile);
+ _fromYa = new FromYa (*_inputFile);
}
-TiledRgbaInputFile::TiledRgbaInputFile (IStream &is,
- const string &layerName,
- int numThreads)
+TiledRgbaInputFile::TiledRgbaInputFile (OPENEXR_IMF_INTERNAL_NAMESPACE::IStream &is,
+ const string &layerName,
+ int numThreads)
:
_inputFile (new TiledInputFile (is, numThreads)),
_fromYa (0),
_channelNamePrefix (prefixFromLayerName (layerName, _inputFile->header()))
{
if (channels() & WRITE_Y)
- _fromYa = new FromYa (*_inputFile);
+ _fromYa = new FromYa (*_inputFile);
}
}
-void
+void
TiledRgbaInputFile::setFrameBuffer (Rgba *base, size_t xStride, size_t yStride)
{
if (_fromYa)
{
- Lock lock (*_fromYa);
- _fromYa->setFrameBuffer (base, xStride, yStride, _channelNamePrefix);
+ Lock lock (*_fromYa);
+ _fromYa->setFrameBuffer (base, xStride, yStride, _channelNamePrefix);
}
else
{
- size_t xs = xStride * sizeof (Rgba);
- size_t ys = yStride * sizeof (Rgba);
-
- FrameBuffer fb;
-
- fb.insert (_channelNamePrefix + "R",
- Slice (HALF,
- (char *) &base[0].r,
- xs, ys,
- 1, 1, // xSampling, ySampling
- 0.0)); // fillValue
-
- fb.insert (_channelNamePrefix + "G",
- Slice (HALF,
- (char *) &base[0].g,
- xs, ys,
- 1, 1, // xSampling, ySampling
- 0.0)); // fillValue
-
- fb.insert (_channelNamePrefix + "B",
- Slice (HALF,
- (char *) &base[0].b,
- xs, ys,
- 1, 1, // xSampling, ySampling
- 0.0)); // fillValue
-
- fb.insert (_channelNamePrefix + "A",
- Slice (HALF,
- (char *) &base[0].a,
- xs, ys,
- 1, 1, // xSampling, ySampling
- 1.0)); // fillValue
-
- _inputFile->setFrameBuffer (fb);
+ size_t xs = xStride * sizeof (Rgba);
+ size_t ys = yStride * sizeof (Rgba);
+
+ FrameBuffer fb;
+
+ fb.insert (_channelNamePrefix + "R",
+ Slice (HALF,
+ (char *) &base[0].r,
+ xs, ys,
+ 1, 1, // xSampling, ySampling
+ 0.0)); // fillValue
+
+ fb.insert (_channelNamePrefix + "G",
+ Slice (HALF,
+ (char *) &base[0].g,
+ xs, ys,
+ 1, 1, // xSampling, ySampling
+ 0.0)); // fillValue
+
+ fb.insert (_channelNamePrefix + "B",
+ Slice (HALF,
+ (char *) &base[0].b,
+ xs, ys,
+ 1, 1, // xSampling, ySampling
+ 0.0)); // fillValue
+
+ fb.insert (_channelNamePrefix + "A",
+ Slice (HALF,
+ (char *) &base[0].a,
+ xs, ys,
+ 1, 1, // xSampling, ySampling
+ 1.0)); // fillValue
+
+ _inputFile->setFrameBuffer (fb);
}
}
-void
+void
TiledRgbaInputFile::setLayerName (const std::string &layerName)
{
delete _fromYa;
_fromYa = 0;
-
+
_channelNamePrefix = prefixFromLayerName (layerName, _inputFile->header());
if (channels() & WRITE_Y)
- _fromYa = new FromYa (*_inputFile);
+ _fromYa = new FromYa (*_inputFile);
FrameBuffer fb;
_inputFile->setFrameBuffer (fb);
}
-const FrameBuffer &
+const FrameBuffer &
TiledRgbaInputFile::frameBuffer () const
{
return _inputFile->frameBuffer();
}
-const Imath::Box2i &
+const IMATH_NAMESPACE::Box2i &
TiledRgbaInputFile::displayWindow () const
{
return _inputFile->header().displayWindow();
}
-const Imath::Box2i &
+const IMATH_NAMESPACE::Box2i &
TiledRgbaInputFile::dataWindow () const
{
return _inputFile->header().dataWindow();
}
-float
+float
TiledRgbaInputFile::pixelAspectRatio () const
{
return _inputFile->header().pixelAspectRatio();
}
-const Imath::V2f
+const IMATH_NAMESPACE::V2f
TiledRgbaInputFile::screenWindowCenter () const
{
return _inputFile->header().screenWindowCenter();
}
-float
+float
TiledRgbaInputFile::screenWindowWidth () const
{
return _inputFile->header().screenWindowWidth();
}
-RgbaChannels
+RgbaChannels
TiledRgbaInputFile::channels () const
{
return rgbaChannels (_inputFile->header().channels(), _channelNamePrefix);
}
-Imath::Box2i
+IMATH_NAMESPACE::Box2i
TiledRgbaInputFile::dataWindowForLevel (int l) const
{
return _inputFile->dataWindowForLevel (l);
}
-Imath::Box2i
+IMATH_NAMESPACE::Box2i
TiledRgbaInputFile::dataWindowForLevel (int lx, int ly) const
{
return _inputFile->dataWindowForLevel (lx, ly);
}
-Imath::Box2i
+IMATH_NAMESPACE::Box2i
TiledRgbaInputFile::dataWindowForTile (int dx, int dy, int l) const
{
return _inputFile->dataWindowForTile (dx, dy, l);
}
-Imath::Box2i
+IMATH_NAMESPACE::Box2i
TiledRgbaInputFile::dataWindowForTile (int dx, int dy, int lx, int ly) const
{
return _inputFile->dataWindowForTile (dx, dy, lx, ly);
{
if (_fromYa)
{
- Lock lock (*_fromYa);
- _fromYa->readTile (dx, dy, l, l);
+ Lock lock (*_fromYa);
+ _fromYa->readTile (dx, dy, l, l);
}
else
{
- _inputFile->readTile (dx, dy, l);
+ _inputFile->readTile (dx, dy, l);
}
}
{
if (_fromYa)
{
- Lock lock (*_fromYa);
- _fromYa->readTile (dx, dy, lx, ly);
+ Lock lock (*_fromYa);
+ _fromYa->readTile (dx, dy, lx, ly);
}
else
{
- _inputFile->readTile (dx, dy, lx, ly);
+ _inputFile->readTile (dx, dy, lx, ly);
}
}
-void
+void
TiledRgbaInputFile::readTiles (int dxMin, int dxMax, int dyMin, int dyMax,
int lx, int ly)
{
if (_fromYa)
{
- Lock lock (*_fromYa);
+ Lock lock (*_fromYa);
for (int dy = dyMin; dy <= dyMax; dy++)
for (int dx = dxMin; dx <= dxMax; dx++)
- _fromYa->readTile (dx, dy, lx, ly);
+ _fromYa->readTile (dx, dy, lx, ly);
}
else
{
}
}
-void
+void
TiledRgbaInputFile::readTiles (int dxMin, int dxMax, int dyMin, int dyMax,
int l)
{
}
-void
+void
TiledRgbaOutputFile::updatePreviewImage (const PreviewRgba newPixels[])
{
_outputFile->updatePreviewImage (newPixels);
}
-void
+void
TiledRgbaOutputFile::breakTile (int dx, int dy, int lx, int ly,
- int offset, int length, char c)
+ int offset, int length, char c)
{
_outputFile->breakTile (dx, dy, lx, ly, offset, length, c);
}
-} // namespace Imf
+OPENEXR_IMF_INTERNAL_NAMESPACE_SOURCE_EXIT
//
// Copyright (c) 2004, Industrial Light & Magic, a division of Lucas
// Digital Ltd. LLC
-//
+//
// All rights reserved.
-//
+//
// Redistribution and use in source and binary forms, with or without
// modification, are permitted provided that the following conditions are
// met:
// distribution.
// * Neither the name of Industrial Light & Magic nor the names of
// its contributors may be used to endorse or promote products derived
-// from this software without specific prior written permission.
-//
+// from this software without specific prior written permission.
+//
// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
//
//-----------------------------------------------------------------------------
-#include <ImfHeader.h>
-#include <ImfFrameBuffer.h>
+#include "ImfHeader.h"
+#include "ImfFrameBuffer.h"
#include "ImathVec.h"
#include "ImathBox.h"
#include "half.h"
-#include <ImfTileDescription.h>
-#include <ImfRgba.h>
-#include <ImfThreading.h>
+#include "ImfTileDescription.h"
+#include "ImfRgba.h"
+#include "ImfThreading.h"
#include <string>
+#include "ImfNamespace.h"
+#include "ImfForward.h"
-namespace Imf {
-class TiledOutputFile;
-class TiledInputFile;
-struct PreviewRgba;
+OPENEXR_IMF_INTERNAL_NAMESPACE_HEADER_ENTER
//
// constructor.
//---------------------------------------------------
+ IMF_EXPORT
TiledRgbaOutputFile (const char name[],
- const Header &header,
- RgbaChannels rgbaChannels,
- int tileXSize,
- int tileYSize,
- LevelMode mode,
- LevelRoundingMode rmode = ROUND_DOWN,
+ const Header &header,
+ RgbaChannels rgbaChannels,
+ int tileXSize,
+ int tileYSize,
+ LevelMode mode,
+ LevelRoundingMode rmode = ROUND_DOWN,
int numThreads = globalThreadCount ());
// corresponding files.
//---------------------------------------------------
- TiledRgbaOutputFile (OStream &os,
- const Header &header,
- RgbaChannels rgbaChannels,
- int tileXSize,
- int tileYSize,
- LevelMode mode,
- LevelRoundingMode rmode = ROUND_DOWN,
+ IMF_EXPORT
+ TiledRgbaOutputFile (OPENEXR_IMF_INTERNAL_NAMESPACE::OStream &os,
+ const Header &header,
+ RgbaChannels rgbaChannels,
+ int tileXSize,
+ int tileYSize,
+ LevelMode mode,
+ LevelRoundingMode rmode = ROUND_DOWN,
int numThreads = globalThreadCount ());
// "same as displayWindow")
//------------------------------------------------------
+ IMF_EXPORT
TiledRgbaOutputFile (const char name[],
- int tileXSize,
- int tileYSize,
- LevelMode mode,
- LevelRoundingMode rmode,
- const Imath::Box2i &displayWindow,
- const Imath::Box2i &dataWindow = Imath::Box2i(),
- RgbaChannels rgbaChannels = WRITE_RGBA,
- float pixelAspectRatio = 1,
- const Imath::V2f screenWindowCenter =
- Imath::V2f (0, 0),
- float screenWindowWidth = 1,
- LineOrder lineOrder = INCREASING_Y,
- Compression compression = ZIP_COMPRESSION,
+ int tileXSize,
+ int tileYSize,
+ LevelMode mode,
+ LevelRoundingMode rmode,
+ const IMATH_NAMESPACE::Box2i &displayWindow,
+ const IMATH_NAMESPACE::Box2i &dataWindow = IMATH_NAMESPACE::Box2i(),
+ RgbaChannels rgbaChannels = WRITE_RGBA,
+ float pixelAspectRatio = 1,
+ const IMATH_NAMESPACE::V2f screenWindowCenter =
+ IMATH_NAMESPACE::V2f (0, 0),
+ float screenWindowWidth = 1,
+ LineOrder lineOrder = INCREASING_Y,
+ Compression compression = ZIP_COMPRESSION,
int numThreads = globalThreadCount ());
// Box2i (V2i (0, 0), V2i (width - 1, height -1))
//-----------------------------------------------
+ IMF_EXPORT
TiledRgbaOutputFile (const char name[],
- int width,
- int height,
- int tileXSize,
- int tileYSize,
- LevelMode mode,
- LevelRoundingMode rmode = ROUND_DOWN,
- RgbaChannels rgbaChannels = WRITE_RGBA,
- float pixelAspectRatio = 1,
- const Imath::V2f screenWindowCenter =
- Imath::V2f (0, 0),
- float screenWindowWidth = 1,
- LineOrder lineOrder = INCREASING_Y,
- Compression compression = ZIP_COMPRESSION,
+ int width,
+ int height,
+ int tileXSize,
+ int tileYSize,
+ LevelMode mode,
+ LevelRoundingMode rmode = ROUND_DOWN,
+ RgbaChannels rgbaChannels = WRITE_RGBA,
+ float pixelAspectRatio = 1,
+ const IMATH_NAMESPACE::V2f screenWindowCenter =
+ IMATH_NAMESPACE::V2f (0, 0),
+ float screenWindowWidth = 1,
+ LineOrder lineOrder = INCREASING_Y,
+ Compression compression = ZIP_COMPRESSION,
int numThreads = globalThreadCount ());
-
+ IMF_EXPORT
virtual ~TiledRgbaOutputFile ();
//
//------------------------------------------------
+ IMF_EXPORT
void setFrameBuffer (const Rgba *base,
- size_t xStride,
- size_t yStride);
+ size_t xStride,
+ size_t yStride);
//--------------------------
// Access to the file header
//--------------------------
+ IMF_EXPORT
const Header & header () const;
+ IMF_EXPORT
const FrameBuffer & frameBuffer () const;
- const Imath::Box2i & displayWindow () const;
- const Imath::Box2i & dataWindow () const;
+ IMF_EXPORT
+ const IMATH_NAMESPACE::Box2i & displayWindow () const;
+ IMF_EXPORT
+ const IMATH_NAMESPACE::Box2i & dataWindow () const;
+ IMF_EXPORT
float pixelAspectRatio () const;
- const Imath::V2f screenWindowCenter () const;
+ IMF_EXPORT
+ const IMATH_NAMESPACE::V2f screenWindowCenter () const;
+ IMF_EXPORT
float screenWindowWidth () const;
+ IMF_EXPORT
LineOrder lineOrder () const;
+ IMF_EXPORT
Compression compression () const;
+ IMF_EXPORT
RgbaChannels channels () const;
// Utility functions (same as in Imf::TiledOutputFile)
//----------------------------------------------------
+ IMF_EXPORT
unsigned int tileXSize () const;
+ IMF_EXPORT
unsigned int tileYSize () const;
+ IMF_EXPORT
LevelMode levelMode () const;
+ IMF_EXPORT
LevelRoundingMode levelRoundingMode () const;
+ IMF_EXPORT
int numLevels () const;
+ IMF_EXPORT
int numXLevels () const;
+ IMF_EXPORT
int numYLevels () const;
+ IMF_EXPORT
bool isValidLevel (int lx, int ly) const;
+ IMF_EXPORT
int levelWidth (int lx) const;
+ IMF_EXPORT
int levelHeight (int ly) const;
+ IMF_EXPORT
int numXTiles (int lx = 0) const;
+ IMF_EXPORT
int numYTiles (int ly = 0) const;
- Imath::Box2i dataWindowForLevel (int l = 0) const;
- Imath::Box2i dataWindowForLevel (int lx, int ly) const;
+ IMF_EXPORT
+ IMATH_NAMESPACE::Box2i dataWindowForLevel (int l = 0) const;
+ IMF_EXPORT
+ IMATH_NAMESPACE::Box2i dataWindowForLevel (int lx, int ly) const;
- Imath::Box2i dataWindowForTile (int dx, int dy,
- int l = 0) const;
+ IMF_EXPORT
+ IMATH_NAMESPACE::Box2i dataWindowForTile (int dx, int dy,
+ int l = 0) const;
- Imath::Box2i dataWindowForTile (int dx, int dy,
- int lx, int ly) const;
+ IMF_EXPORT
+ IMATH_NAMESPACE::Box2i dataWindowForTile (int dx, int dy,
+ int lx, int ly) const;
//------------------------------------------------------------------
// Write pixel data:
//
//------------------------------------------------------------------
+ IMF_EXPORT
void writeTile (int dx, int dy, int l = 0);
+ IMF_EXPORT
void writeTile (int dx, int dy, int lx, int ly);
+ IMF_EXPORT
void writeTiles (int dxMin, int dxMax, int dyMin, int dyMax,
int lx, int ly);
+ IMF_EXPORT
void writeTiles (int dxMin, int dxMax, int dyMin, int dyMax,
int l = 0);
// Update the preview image (see Imf::TiledOutputFile::updatePreviewImage())
// -------------------------------------------------------------------------
+ IMF_EXPORT
void updatePreviewImage (const PreviewRgba[]);
//
//------------------------------------------------
+ IMF_EXPORT
void breakTile (int dx, int dy,
- int lx, int ly,
- int offset,
- int length,
- char c);
+ int lx, int ly,
+ int offset,
+ int length,
+ char c);
private:
//
// Copy constructor and assignment are not implemented
//
- TiledRgbaOutputFile (const TiledRgbaOutputFile &);
+ TiledRgbaOutputFile (const TiledRgbaOutputFile &);
TiledRgbaOutputFile & operator = (const TiledRgbaOutputFile &);
class ToYa;
// files.
//--------------------------------------------------------
+ IMF_EXPORT
TiledRgbaInputFile (const char name[],
int numThreads = globalThreadCount ());
// corresponding files.
//-------------------------------------------------------
- TiledRgbaInputFile (IStream &is, int numThreads = globalThreadCount ());
+ IMF_EXPORT
+ TiledRgbaInputFile (OPENEXR_IMF_INTERNAL_NAMESPACE::IStream &is, int numThreads = globalThreadCount ());
//------------------------------------------------------------
// expected to be layerName.R, layerName.G, etc.
//------------------------------------------------------------
+ IMF_EXPORT
TiledRgbaInputFile (const char name[],
- const std::string &layerName,
- int numThreads = globalThreadCount());
+ const std::string &layerName,
+ int numThreads = globalThreadCount());
- TiledRgbaInputFile (IStream &is,
- const std::string &layerName,
- int numThreads = globalThreadCount());
+ IMF_EXPORT
+ TiledRgbaInputFile (OPENEXR_IMF_INTERNAL_NAMESPACE::IStream &is,
+ const std::string &layerName,
+ int numThreads = globalThreadCount());
//-----------
// Destructor
//-----------
+ IMF_EXPORT
virtual ~TiledRgbaInputFile ();
//
//-----------------------------------------------------
+ IMF_EXPORT
void setFrameBuffer (Rgba *base,
- size_t xStride,
- size_t yStride);
+ size_t xStride,
+ size_t yStride);
//-------------------------------------------------------------------
// Switch to a different layer -- subsequent calls to readTile()
// at least once before the next call to readTile() or readTiles().
//-------------------------------------------------------------------
+ IMF_EXPORT
void setLayerName (const std::string &layerName);
// Access to the file header
//--------------------------
+ IMF_EXPORT
const Header & header () const;
+ IMF_EXPORT
const FrameBuffer & frameBuffer () const;
- const Imath::Box2i & displayWindow () const;
- const Imath::Box2i & dataWindow () const;
+ IMF_EXPORT
+ const IMATH_NAMESPACE::Box2i & displayWindow () const;
+ IMF_EXPORT
+ const IMATH_NAMESPACE::Box2i & dataWindow () const;
+ IMF_EXPORT
float pixelAspectRatio () const;
- const Imath::V2f screenWindowCenter () const;
+ IMF_EXPORT
+ const IMATH_NAMESPACE::V2f screenWindowCenter () const;
+ IMF_EXPORT
float screenWindowWidth () const;
+ IMF_EXPORT
LineOrder lineOrder () const;
+ IMF_EXPORT
Compression compression () const;
+ IMF_EXPORT
RgbaChannels channels () const;
+ IMF_EXPORT
const char * fileName () const;
+ IMF_EXPORT
bool isComplete () const;
//----------------------------------
// Access to the file format version
//----------------------------------
+ IMF_EXPORT
int version () const;
// Utility functions (same as in Imf::TiledInputFile)
//---------------------------------------------------
+ IMF_EXPORT
unsigned int tileXSize () const;
+ IMF_EXPORT
unsigned int tileYSize () const;
+ IMF_EXPORT
LevelMode levelMode () const;
+ IMF_EXPORT
LevelRoundingMode levelRoundingMode () const;
+ IMF_EXPORT
int numLevels () const;
+ IMF_EXPORT
int numXLevels () const;
+ IMF_EXPORT
int numYLevels () const;
+ IMF_EXPORT
bool isValidLevel (int lx, int ly) const;
+ IMF_EXPORT
int levelWidth (int lx) const;
+ IMF_EXPORT
int levelHeight (int ly) const;
+ IMF_EXPORT
int numXTiles (int lx = 0) const;
+ IMF_EXPORT
int numYTiles (int ly = 0) const;
- Imath::Box2i dataWindowForLevel (int l = 0) const;
- Imath::Box2i dataWindowForLevel (int lx, int ly) const;
-
- Imath::Box2i dataWindowForTile (int dx, int dy,
- int l = 0) const;
+ IMF_EXPORT
+ IMATH_NAMESPACE::Box2i dataWindowForLevel (int l = 0) const;
+ IMF_EXPORT
+ IMATH_NAMESPACE::Box2i dataWindowForLevel (int lx, int ly) const;
- Imath::Box2i dataWindowForTile (int dx, int dy,
- int lx, int ly) const;
+ IMF_EXPORT
+ IMATH_NAMESPACE::Box2i dataWindowForTile (int dx, int dy,
+ int l = 0) const;
+ IMF_EXPORT
+ IMATH_NAMESPACE::Box2i dataWindowForTile (int dx, int dy,
+ int lx, int ly) const;
+
//----------------------------------------------------------------
// Read pixel data:
//
//----------------------------------------------------------------
+ IMF_EXPORT
void readTile (int dx, int dy, int l = 0);
+ IMF_EXPORT
void readTile (int dx, int dy, int lx, int ly);
+ IMF_EXPORT
void readTiles (int dxMin, int dxMax,
int dyMin, int dyMax, int lx, int ly);
+ IMF_EXPORT
void readTiles (int dxMin, int dxMax,
int dyMin, int dyMax, int l = 0);
};
-} // namespace Imf
+OPENEXR_IMF_INTERNAL_NAMESPACE_HEADER_EXIT
+
+
+
+
#endif
//
// Copyright (c) 2004, Industrial Light & Magic, a division of Lucas
// Digital Ltd. LLC
-//
+//
// All rights reserved.
-//
+//
// Redistribution and use in source and binary forms, with or without
// modification, are permitted provided that the following conditions are
// met:
// distribution.
// * Neither the name of Industrial Light & Magic nor the names of
// its contributors may be used to endorse or promote products derived
-// from this software without specific prior written permission.
-//
+// from this software without specific prior written permission.
+//
// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
//-----------------------------------------------------------------------------
//
// class TimeCode
-//
+//
//-----------------------------------------------------------------------------
#include <ImfTimeCode.h>
#include "Iex.h"
+#include "ImfNamespace.h"
-namespace Imf {
-
+OPENEXR_IMF_INTERNAL_NAMESPACE_SOURCE_ENTER
+
TimeCode::TimeCode ()
{
_time = 0;
return *this;
}
+
+bool
+TimeCode::operator == (const TimeCode & c) const
+{
+ return (_time == c._time && _user == c._user);
+}
+
+
+bool
+TimeCode::operator != (const TimeCode & c) const
+{
+ return (_time != c._time || _user != c._user);
+}
+
+
namespace {
TimeCode::setHours (int value)
{
if (value < 0 || value > 23)
- throw Iex::ArgExc ("Cannot set hours field in time code. "
- "New value is out of range.");
+ throw IEX_NAMESPACE::ArgExc ("Cannot set hours field in time code. "
+ "New value is out of range.");
setBitField (_time, 24, 29, binaryToBcd (value));
}
TimeCode::setMinutes (int value)
{
if (value < 0 || value > 59)
- throw Iex::ArgExc ("Cannot set minutes field in time code. "
- "New value is out of range.");
+ throw IEX_NAMESPACE::ArgExc ("Cannot set minutes field in time code. "
+ "New value is out of range.");
setBitField (_time, 16, 22, binaryToBcd (value));
}
TimeCode::setSeconds (int value)
{
if (value < 0 || value > 59)
- throw Iex::ArgExc ("Cannot set seconds field in time code. "
- "New value is out of range.");
+ throw IEX_NAMESPACE::ArgExc ("Cannot set seconds field in time code. "
+ "New value is out of range.");
setBitField (_time, 8, 14, binaryToBcd (value));
}
TimeCode::setFrame (int value)
{
if (value < 0 || value > 59)
- throw Iex::ArgExc ("Cannot set frame field in time code. "
- "New value is out of range.");
+ throw IEX_NAMESPACE::ArgExc ("Cannot set frame field in time code. "
+ "New value is out of range.");
setBitField (_time, 0, 5, binaryToBcd (value));
}
bool
TimeCode::dropFrame () const
{
- return bool (bitField (_time, 6, 6));
+ return !!bitField (_time, 6, 6);
}
bool
TimeCode::colorFrame () const
{
- return bool (bitField (_time, 7, 7));
+ return !!bitField (_time, 7, 7);
}
bool
TimeCode::fieldPhase () const
{
- return bool (bitField (_time, 15, 15));
+ return !!bitField (_time, 15, 15);
}
bool
TimeCode::bgf0 () const
{
- return bool (bitField (_time, 23, 23));
+ return !!bitField (_time, 23, 23);
}
bool
TimeCode::bgf1 () const
{
- return bool (bitField (_time, 30, 30));
+ return!!bitField (_time, 30, 30);
}
bool
TimeCode::bgf2 () const
{
- return bool (bitField (_time, 31, 31));
+ return !!bitField (_time, 31, 31);
}
TimeCode::binaryGroup (int group) const
{
if (group < 1 || group > 8)
- throw Iex::ArgExc ("Cannot extract binary group from time code "
- "user data. Group number is out of range.");
+ throw IEX_NAMESPACE::ArgExc ("Cannot extract binary group from time code "
+ "user data. Group number is out of range.");
int minBit = 4 * (group - 1);
int maxBit = minBit + 3;
TimeCode::setBinaryGroup (int group, int value)
{
if (group < 1 || group > 8)
- throw Iex::ArgExc ("Cannot extract binary group from time code "
- "user data. Group number is out of range.");
+ throw IEX_NAMESPACE::ArgExc ("Cannot extract binary group from time code "
+ "user data. Group number is out of range.");
int minBit = 4 * (group - 1);
int maxBit = minBit + 3;
{
if (packing == TV50_PACKING)
{
- unsigned int t = _time;
+ unsigned int t = _time;
- t &= ~((1 << 6) | (1 << 15) | (1 << 23) | (1 << 30) | (1 << 31));
+ t &= ~((1 << 6) | (1 << 15) | (1 << 23) | (1 << 30) | (1 << 31));
- t |= ((unsigned int) bgf0() << 15);
- t |= ((unsigned int) bgf2() << 23);
- t |= ((unsigned int) bgf1() << 30);
- t |= ((unsigned int) fieldPhase() << 31);
+ t |= ((unsigned int) bgf0() << 15);
+ t |= ((unsigned int) bgf2() << 23);
+ t |= ((unsigned int) bgf1() << 30);
+ t |= ((unsigned int) fieldPhase() << 31);
- return t;
+ return t;
}
if (packing == FILM24_PACKING)
{
- return _time & ~((1 << 6) | (1 << 7));
+ return _time & ~((1 << 6) | (1 << 7));
}
else // packing == TV60_PACKING
{
- return _time;
+ return _time;
}
}
{
if (packing == TV50_PACKING)
{
- _time = value &
- ~((1 << 6) | (1 << 15) | (1 << 23) | (1 << 30) | (1 << 31));
+ _time = value &
+ ~((1 << 6) | (1 << 15) | (1 << 23) | (1 << 30) | (1 << 31));
- if (value & (1 << 15))
- setBgf0 (true);
+ if (value & (1 << 15))
+ setBgf0 (true);
- if (value & (1 << 23))
- setBgf2 (true);
+ if (value & (1 << 23))
+ setBgf2 (true);
- if (value & (1 << 30))
- setBgf1 (true);
+ if (value & (1 << 30))
+ setBgf1 (true);
- if (value & (1 << 31))
- setFieldPhase (true);
+ if (value & (1 << 31))
+ setFieldPhase (true);
}
else if (packing == FILM24_PACKING)
{
- _time = value & ~((1 << 6) | (1 << 7));
+ _time = value & ~((1 << 6) | (1 << 7));
}
else // packing == TV60_PACKING
{
- _time = value;
+ _time = value;
}
}
}
-} // namespace Imf
+OPENEXR_IMF_INTERNAL_NAMESPACE_SOURCE_EXIT
//
// Copyright (c) 2004, Industrial Light & Magic, a division of Lucas
// Digital Ltd. LLC
-//
+//
// All rights reserved.
-//
+//
// Redistribution and use in source and binary forms, with or without
// modification, are permitted provided that the following conditions are
// met:
// distribution.
// * Neither the name of Industrial Light & Magic nor the names of
// its contributors may be used to endorse or promote products derived
-// from this software without specific prior written permission.
-//
+// from this software without specific prior written permission.
+//
// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
#ifndef INCLUDED_IMF_TIME_CODE_H
#define INCLUDED_IMF_TIME_CODE_H
+#include "ImfExport.h"
+#include "ImfNamespace.h"
+
//-----------------------------------------------------------------------------
//
// class TimeCode
-//
+//
// A TimeCode object stores time and control codes as described
// in SMPTE standard 12M-1999. A TimeCode object contains the
// following fields:
//
//-----------------------------------------------------------------------------
-namespace Imf {
-
+OPENEXR_IMF_INTERNAL_NAMESPACE_HEADER_ENTER
+
class TimeCode
{
public:
enum Packing
{
- TV60_PACKING, // packing for 60-field television
- TV50_PACKING, // packing for 50-field television
- FILM24_PACKING // packing for 24-frame film
+ TV60_PACKING, // packing for 60-field television
+ TV50_PACKING, // packing for 50-field television
+ FILM24_PACKING // packing for 24-frame film
};
// Constructors and assignment operator
//-------------------------------------
+ IMF_EXPORT
TimeCode (); // all fields set to 0 or false
+ IMF_EXPORT
TimeCode (int hours,
- int minutes,
- int seconds,
- int frame,
- bool dropFrame = false,
- bool colorFrame = false,
- bool fieldPhase = false,
- bool bgf0 = false,
- bool bgf1 = false,
- bool bgf2 = false,
- int binaryGroup1 = 0,
- int binaryGroup2 = 0,
- int binaryGroup3 = 0,
- int binaryGroup4 = 0,
- int binaryGroup5 = 0,
- int binaryGroup6 = 0,
- int binaryGroup7 = 0,
- int binaryGroup8 = 0);
-
+ int minutes,
+ int seconds,
+ int frame,
+ bool dropFrame = false,
+ bool colorFrame = false,
+ bool fieldPhase = false,
+ bool bgf0 = false,
+ bool bgf1 = false,
+ bool bgf2 = false,
+ int binaryGroup1 = 0,
+ int binaryGroup2 = 0,
+ int binaryGroup3 = 0,
+ int binaryGroup4 = 0,
+ int binaryGroup5 = 0,
+ int binaryGroup6 = 0,
+ int binaryGroup7 = 0,
+ int binaryGroup8 = 0);
+
+ IMF_EXPORT
TimeCode (unsigned int timeAndFlags,
- unsigned int userData = 0,
- Packing packing = TV60_PACKING);
+ unsigned int userData = 0,
+ Packing packing = TV60_PACKING);
+ IMF_EXPORT
TimeCode (const TimeCode &other);
+ IMF_EXPORT
TimeCode & operator = (const TimeCode &other);
// Access to individual fields
//----------------------------
+ IMF_EXPORT
int hours () const;
+ IMF_EXPORT
void setHours (int value);
+ IMF_EXPORT
int minutes () const;
+ IMF_EXPORT
void setMinutes (int value);
+ IMF_EXPORT
int seconds () const;
+ IMF_EXPORT
void setSeconds (int value);
+ IMF_EXPORT
int frame () const;
+ IMF_EXPORT
void setFrame (int value);
+ IMF_EXPORT
bool dropFrame () const;
+ IMF_EXPORT
void setDropFrame (bool value);
+ IMF_EXPORT
bool colorFrame () const;
+ IMF_EXPORT
void setColorFrame (bool value);
+ IMF_EXPORT
bool fieldPhase () const;
+ IMF_EXPORT
void setFieldPhase (bool value);
+ IMF_EXPORT
bool bgf0 () const;
+ IMF_EXPORT
void setBgf0 (bool value);
+ IMF_EXPORT
bool bgf1 () const;
+ IMF_EXPORT
void setBgf1 (bool value);
+ IMF_EXPORT
bool bgf2 () const;
+ IMF_EXPORT
void setBgf2 (bool value);
+ IMF_EXPORT
int binaryGroup (int group) const; // group must be between 1 and 8
+ IMF_EXPORT
void setBinaryGroup (int group, int value);
-
+
//---------------------------------
// Access to packed representations
//---------------------------------
+ IMF_EXPORT
unsigned int timeAndFlags (Packing packing = TV60_PACKING) const;
+ IMF_EXPORT
void setTimeAndFlags (unsigned int value,
- Packing packing = TV60_PACKING);
+ Packing packing = TV60_PACKING);
+ IMF_EXPORT
unsigned int userData () const;
+ IMF_EXPORT
void setUserData (unsigned int value);
-
+
+
+ //---------
+ // Equality
+ //---------
+
+ IMF_EXPORT
+ bool operator == (const TimeCode &v) const;
+ IMF_EXPORT
+ bool operator != (const TimeCode &v) const;
+
private:
unsigned int _time;
};
-} // namespace Imf
+
+OPENEXR_IMF_INTERNAL_NAMESPACE_HEADER_EXIT
+
+
+
+
#endif
//
// Copyright (c) 2004, Industrial Light & Magic, a division of Lucas
// Digital Ltd. LLC
-//
+//
// All rights reserved.
-//
+//
// Redistribution and use in source and binary forms, with or without
// modification, are permitted provided that the following conditions are
// met:
// distribution.
// * Neither the name of Industrial Light & Magic nor the names of
// its contributors may be used to endorse or promote products derived
-// from this software without specific prior written permission.
-//
+// from this software without specific prior written permission.
+//
// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
#include <ImfTimeCodeAttribute.h>
-namespace Imf {
+OPENEXR_IMF_INTERNAL_NAMESPACE_SOURCE_ENTER
+using namespace OPENEXR_IMF_INTERNAL_NAMESPACE;
template <>
const char *
template <>
void
-TimeCodeAttribute::writeValueTo (OStream &os, int) const
+TimeCodeAttribute::writeValueTo (OPENEXR_IMF_INTERNAL_NAMESPACE::OStream &os, int version) const
{
Xdr::write <StreamIO> (os, _value.timeAndFlags());
Xdr::write <StreamIO> (os, _value.userData());
template <>
void
-TimeCodeAttribute::readValueFrom (IStream &is, int, int)
+TimeCodeAttribute::readValueFrom (OPENEXR_IMF_INTERNAL_NAMESPACE::IStream &is, int size, int version)
{
unsigned int tmp;
}
-} // namespace Imf
+OPENEXR_IMF_INTERNAL_NAMESPACE_SOURCE_EXIT
//
// Copyright (c) 2004, Industrial Light & Magic, a division of Lucas
// Digital Ltd. LLC
-//
+//
// All rights reserved.
-//
+//
// Redistribution and use in source and binary forms, with or without
// modification, are permitted provided that the following conditions are
// met:
// distribution.
// * Neither the name of Industrial Light & Magic nor the names of
// its contributors may be used to endorse or promote products derived
-// from this software without specific prior written permission.
-//
+// from this software without specific prior written permission.
+//
// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
//
//-----------------------------------------------------------------------------
-#include <ImfAttribute.h>
-#include <ImfTimeCode.h>
-
+#include "ImfAttribute.h"
+#include "ImfTimeCode.h"
-namespace Imf {
+OPENEXR_IMF_INTERNAL_NAMESPACE_HEADER_ENTER
-typedef TypedAttribute<TimeCode> TimeCodeAttribute;
+typedef TypedAttribute<OPENEXR_IMF_INTERNAL_NAMESPACE::TimeCode> TimeCodeAttribute;
template <>
+IMF_EXPORT
const char *TimeCodeAttribute::staticTypeName ();
template <>
-void TimeCodeAttribute::writeValueTo (OStream &, int) const;
+IMF_EXPORT
+void TimeCodeAttribute::writeValueTo (OPENEXR_IMF_INTERNAL_NAMESPACE::OStream &,
+ int) const;
template <>
-void TimeCodeAttribute::readValueFrom (IStream &, int, int);
+IMF_EXPORT
+void TimeCodeAttribute::readValueFrom (OPENEXR_IMF_INTERNAL_NAMESPACE::IStream &,
+ int, int);
+
+
+OPENEXR_IMF_INTERNAL_NAMESPACE_HEADER_EXIT
-} // namespace Imf
-// Metrowerks compiler wants the .cpp file inlined, too
-#ifdef __MWERKS__
-#include <ImfTimeCodeAttribute.cpp>
-#endif
#endif
//
// Copyright (c) 2004, Industrial Light & Magic, a division of Lucas
// Digital Ltd. LLC
-//
+//
// All rights reserved.
-//
+//
// Redistribution and use in source and binary forms, with or without
// modification, are permitted provided that the following conditions are
// met:
// distribution.
// * Neither the name of Industrial Light & Magic nor the names of
// its contributors may be used to endorse or promote products derived
-// from this software without specific prior written permission.
-//
+// from this software without specific prior written permission.
+//
// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
#include <ImfVecAttribute.h>
-namespace Imf {
+OPENEXR_IMF_INTERNAL_NAMESPACE_SOURCE_ENTER
+using namespace OPENEXR_IMF_INTERNAL_NAMESPACE;
template <>
const char *
template <>
void
-V2iAttribute::writeValueTo (OStream &os, int) const
+V2iAttribute::writeValueTo (OPENEXR_IMF_INTERNAL_NAMESPACE::OStream &os, int version) const
{
Xdr::write <StreamIO> (os, _value.x);
Xdr::write <StreamIO> (os, _value.y);
template <>
void
-V2iAttribute::readValueFrom (IStream &is, int, int)
+V2iAttribute::readValueFrom (OPENEXR_IMF_INTERNAL_NAMESPACE::IStream &is, int size, int version)
{
Xdr::read <StreamIO> (is, _value.x);
Xdr::read <StreamIO> (is, _value.y);
template <>
void
-V2fAttribute::writeValueTo (OStream &os, int) const
+V2fAttribute::writeValueTo (OPENEXR_IMF_INTERNAL_NAMESPACE::OStream &os, int version) const
{
Xdr::write <StreamIO> (os, _value.x);
Xdr::write <StreamIO> (os, _value.y);
template <>
void
-V2fAttribute::readValueFrom (IStream &is, int, int)
+V2fAttribute::readValueFrom (OPENEXR_IMF_INTERNAL_NAMESPACE::IStream &is, int size, int version)
{
Xdr::read <StreamIO> (is, _value.x);
Xdr::read <StreamIO> (is, _value.y);
template <>
void
-V2dAttribute::writeValueTo (OStream &os, int) const
+V2dAttribute::writeValueTo (OPENEXR_IMF_INTERNAL_NAMESPACE::OStream &os, int version) const
{
Xdr::write <StreamIO> (os, _value.x);
Xdr::write <StreamIO> (os, _value.y);
template <>
void
-V2dAttribute::readValueFrom (IStream &is, int, int)
+V2dAttribute::readValueFrom (OPENEXR_IMF_INTERNAL_NAMESPACE::IStream &is, int size, int version)
{
Xdr::read <StreamIO> (is, _value.x);
Xdr::read <StreamIO> (is, _value.y);
template <>
void
-V3iAttribute::writeValueTo (OStream &os, int) const
+V3iAttribute::writeValueTo (OPENEXR_IMF_INTERNAL_NAMESPACE::OStream &os, int version) const
{
Xdr::write <StreamIO> (os, _value.x);
Xdr::write <StreamIO> (os, _value.y);
template <>
void
-V3iAttribute::readValueFrom (IStream &is, int, int)
+V3iAttribute::readValueFrom (OPENEXR_IMF_INTERNAL_NAMESPACE::IStream &is, int size, int version)
{
Xdr::read <StreamIO> (is, _value.x);
Xdr::read <StreamIO> (is, _value.y);
template <>
void
-V3fAttribute::writeValueTo (OStream &os, int) const
+V3fAttribute::writeValueTo (OPENEXR_IMF_INTERNAL_NAMESPACE::OStream &os, int version) const
{
Xdr::write <StreamIO> (os, _value.x);
Xdr::write <StreamIO> (os, _value.y);
template <>
void
-V3fAttribute::readValueFrom (IStream &is, int, int)
+V3fAttribute::readValueFrom (OPENEXR_IMF_INTERNAL_NAMESPACE::IStream &is, int size, int version)
{
Xdr::read <StreamIO> (is, _value.x);
Xdr::read <StreamIO> (is, _value.y);
template <>
void
-V3dAttribute::writeValueTo (OStream &os, int) const
+V3dAttribute::writeValueTo (OPENEXR_IMF_INTERNAL_NAMESPACE::OStream &os, int version) const
{
Xdr::write <StreamIO> (os, _value.x);
Xdr::write <StreamIO> (os, _value.y);
template <>
void
-V3dAttribute::readValueFrom (IStream &is, int, int)
+V3dAttribute::readValueFrom (OPENEXR_IMF_INTERNAL_NAMESPACE::IStream &is, int size, int version)
{
Xdr::read <StreamIO> (is, _value.x);
Xdr::read <StreamIO> (is, _value.y);
}
-} // namespace Imf
+OPENEXR_IMF_INTERNAL_NAMESPACE_SOURCE_EXIT
//
// Copyright (c) 2004, Industrial Light & Magic, a division of Lucas
// Digital Ltd. LLC
-//
+//
// All rights reserved.
-//
+//
// Redistribution and use in source and binary forms, with or without
// modification, are permitted provided that the following conditions are
// met:
// distribution.
// * Neither the name of Industrial Light & Magic nor the names of
// its contributors may be used to endorse or promote products derived
-// from this software without specific prior written permission.
-//
+// from this software without specific prior written permission.
+//
// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
//
//-----------------------------------------------------------------------------
-#include <ImfAttribute.h>
+#include "ImfAttribute.h"
#include "ImathVec.h"
+OPENEXR_IMF_INTERNAL_NAMESPACE_HEADER_ENTER
-namespace Imf {
+typedef TypedAttribute<IMATH_NAMESPACE::V2i> V2iAttribute;
+template <> IMF_EXPORT const char *V2iAttribute::staticTypeName ();
+template <> IMF_EXPORT void V2iAttribute::writeValueTo (OPENEXR_IMF_INTERNAL_NAMESPACE::OStream &, int) const;
+template <> IMF_EXPORT void V2iAttribute::readValueFrom (OPENEXR_IMF_INTERNAL_NAMESPACE::IStream &, int, int);
-typedef TypedAttribute<Imath::V2i> V2iAttribute;
-template <> const char *V2iAttribute::staticTypeName ();
-template <> void V2iAttribute::writeValueTo (OStream &, int) const;
-template <> void V2iAttribute::readValueFrom (IStream &, int, int);
+typedef TypedAttribute<IMATH_NAMESPACE::V2f> V2fAttribute;
+template <> IMF_EXPORT const char *V2fAttribute::staticTypeName ();
+template <> IMF_EXPORT void V2fAttribute::writeValueTo (OPENEXR_IMF_INTERNAL_NAMESPACE::OStream &, int) const;
+template <> IMF_EXPORT void V2fAttribute::readValueFrom (OPENEXR_IMF_INTERNAL_NAMESPACE::IStream &, int, int);
-typedef TypedAttribute<Imath::V2f> V2fAttribute;
-template <> const char *V2fAttribute::staticTypeName ();
-template <> void V2fAttribute::writeValueTo (OStream &, int) const;
-template <> void V2fAttribute::readValueFrom (IStream &, int, int);
+typedef TypedAttribute<IMATH_NAMESPACE::V2d> V2dAttribute;
+template <> IMF_EXPORT const char *V2dAttribute::staticTypeName ();
+template <> IMF_EXPORT void V2dAttribute::writeValueTo (OPENEXR_IMF_INTERNAL_NAMESPACE::OStream &, int) const;
+template <> IMF_EXPORT void V2dAttribute::readValueFrom (OPENEXR_IMF_INTERNAL_NAMESPACE::IStream &, int, int);
-typedef TypedAttribute<Imath::V2d> V2dAttribute;
-template <> const char *V2dAttribute::staticTypeName ();
-template <> void V2dAttribute::writeValueTo (OStream &, int) const;
-template <> void V2dAttribute::readValueFrom (IStream &, int, int);
+typedef TypedAttribute<IMATH_NAMESPACE::V3i> V3iAttribute;
+template <> IMF_EXPORT const char *V3iAttribute::staticTypeName ();
+template <> IMF_EXPORT void V3iAttribute::writeValueTo (OPENEXR_IMF_INTERNAL_NAMESPACE::OStream &, int) const;
+template <> IMF_EXPORT void V3iAttribute::readValueFrom (OPENEXR_IMF_INTERNAL_NAMESPACE::IStream &, int, int);
-typedef TypedAttribute<Imath::V3i> V3iAttribute;
-template <> const char *V3iAttribute::staticTypeName ();
-template <> void V3iAttribute::writeValueTo (OStream &, int) const;
-template <> void V3iAttribute::readValueFrom (IStream &, int, int);
+typedef TypedAttribute<IMATH_NAMESPACE::V3f> V3fAttribute;
+template <> IMF_EXPORT const char *V3fAttribute::staticTypeName ();
+template <> IMF_EXPORT void V3fAttribute::writeValueTo (OPENEXR_IMF_INTERNAL_NAMESPACE::OStream &, int) const;
+template <> IMF_EXPORT void V3fAttribute::readValueFrom (OPENEXR_IMF_INTERNAL_NAMESPACE::IStream &, int, int);
-typedef TypedAttribute<Imath::V3f> V3fAttribute;
-template <> const char *V3fAttribute::staticTypeName ();
-template <> void V3fAttribute::writeValueTo (OStream &, int) const;
-template <> void V3fAttribute::readValueFrom (IStream &, int, int);
+typedef TypedAttribute<IMATH_NAMESPACE::V3d> V3dAttribute;
+template <> IMF_EXPORT const char *V3dAttribute::staticTypeName ();
+template <> IMF_EXPORT void V3dAttribute::writeValueTo (OPENEXR_IMF_INTERNAL_NAMESPACE::OStream &, int) const;
+template <> IMF_EXPORT void V3dAttribute::readValueFrom (OPENEXR_IMF_INTERNAL_NAMESPACE::IStream &, int, int);
-typedef TypedAttribute<Imath::V3d> V3dAttribute;
-template <> const char *V3dAttribute::staticTypeName ();
-template <> void V3dAttribute::writeValueTo (OStream &, int) const;
-template <> void V3dAttribute::readValueFrom (IStream &, int, int);
+OPENEXR_IMF_INTERNAL_NAMESPACE_HEADER_EXIT
-} // namespace Imf
+#if defined (OPENEXR_IMF_INTERNAL_NAMESPACE_AUTO_EXPOSE)
+namespace Imf { using namespace OPENEXR_IMF_INTERNAL_NAMESPACE; }
-// Metrowerks compiler wants the .cpp file inlined, too
-#ifdef __MWERKS__
-#include <ImfVecAttribute.cpp>
#endif
#endif
//
// Copyright (c) 2004, Industrial Light & Magic, a division of Lucas
// Digital Ltd. LLC
-//
+//
// All rights reserved.
-//
+//
// Redistribution and use in source and binary forms, with or without
// modification, are permitted provided that the following conditions are
// met:
// distribution.
// * Neither the name of Industrial Light & Magic nor the names of
// its contributors may be used to endorse or promote products derived
-// from this software without specific prior written permission.
-//
+// from this software without specific prior written permission.
+//
// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
#include <ImfVersion.h>
+#include "ImfNamespace.h"
-namespace Imf {
+OPENEXR_IMF_INTERNAL_NAMESPACE_SOURCE_ENTER
bool
isImfMagic (const char bytes[4])
{
return bytes[0] == ((MAGIC >> 0) & 0x00ff) &&
- bytes[1] == ((MAGIC >> 8) & 0x00ff) &&
- bytes[2] == ((MAGIC >> 16) & 0x00ff) &&
- bytes[3] == ((MAGIC >> 24) & 0x00ff);
+ bytes[1] == ((MAGIC >> 8) & 0x00ff) &&
+ bytes[2] == ((MAGIC >> 16) & 0x00ff) &&
+ bytes[3] == ((MAGIC >> 24) & 0x00ff);
}
-} // namespace Imf
+OPENEXR_IMF_INTERNAL_NAMESPACE_SOURCE_EXIT
//
// Copyright (c) 2004, Industrial Light & Magic, a division of Lucas
// Digital Ltd. LLC
-//
+//
// All rights reserved.
-//
+//
// Redistribution and use in source and binary forms, with or without
// modification, are permitted provided that the following conditions are
// met:
// distribution.
// * Neither the name of Industrial Light & Magic nor the names of
// its contributors may be used to endorse or promote products derived
-// from this software without specific prior written permission.
-//
+// from this software without specific prior written permission.
+//
// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
//
//-----------------------------------------------------------------------------
+#include "ImfExport.h"
+#include "ImfNamespace.h"
-namespace Imf {
-
+OPENEXR_IMF_INTERNAL_NAMESPACE_HEADER_ENTER
//
// The MAGIC number is stored in the first four bytes of every
// attribute or channel
// names
+const int NON_IMAGE_FLAG = 0x00000800; // File has at least one part
+ // which is not a regular
+ // scanline image or regular tiled image
+ // (that is, it is a deep format)
+
+const int MULTI_PART_FILE_FLAG = 0x00001000; // File has multiple parts
+
//
// Bitwise OR of all known flags.
//
-const int ALL_FLAGS = TILED_FLAG | LONG_NAMES_FLAG;
+const int ALL_FLAGS = TILED_FLAG | LONG_NAMES_FLAG |
+ NON_IMAGE_FLAG | MULTI_PART_FILE_FLAG;
//
//
inline bool isTiled (int version) {return !!(version & TILED_FLAG);}
+inline bool isMultiPart (int version) {return !!(version & MULTI_PART_FILE_FLAG); }
+inline bool isNonImage(int version) {return !!(version & NON_IMAGE_FLAG); }
inline int makeTiled (int version) {return version | TILED_FLAG;}
inline int makeNotTiled (int version) {return version & ~TILED_FLAG;}
inline int getVersion (int version) {return version & VERSION_NUMBER_FIELD;}
// file is probably an OpenEXR image file, false if not.
//
+IMF_EXPORT
bool isImfMagic (const char bytes[4]);
-} // namespace Imf
+OPENEXR_IMF_INTERNAL_NAMESPACE_HEADER_EXIT
+
+
+
+
#endif
//
// Copyright (c) 2002, Industrial Light & Magic, a division of Lucas
// Digital Ltd. LLC
-//
+//
// All rights reserved.
-//
+//
// Redistribution and use in source and binary forms, with or without
// modification, are permitted provided that the following conditions are
// met:
// distribution.
// * Neither the name of Industrial Light & Magic nor the names of
// its contributors may be used to endorse or promote products derived
-// from this software without specific prior written permission.
-//
+// from this software without specific prior written permission.
+//
// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
#include <ImfWav.h>
+#include "ImfNamespace.h"
-namespace Imf {
+OPENEXR_IMF_INTERNAL_NAMESPACE_SOURCE_ENTER
namespace {
int d = ao - b;
if (d < 0)
- m = (m + M_OFFSET) & MOD_MASK;
+ m = (m + M_OFFSET) & MOD_MASK;
d &= MOD_MASK;
while (p2 <= n)
{
- unsigned short *py = in;
- unsigned short *ey = in + oy * (ny - p2);
- int oy1 = oy * p;
- int oy2 = oy * p2;
- int ox1 = ox * p;
- int ox2 = ox * p2;
- unsigned short i00,i01,i10,i11;
-
- //
- // Y loop
- //
-
- for (; py <= ey; py += oy2)
- {
- unsigned short *px = py;
- unsigned short *ex = py + ox * (nx - p2);
-
- //
- // X loop
- //
-
- for (; px <= ex; px += ox2)
- {
- unsigned short *p01 = px + ox1;
- unsigned short *p10 = px + oy1;
- unsigned short *p11 = p10 + ox1;
-
- //
- // 2D wavelet encoding
- //
-
- if (w14)
- {
- wenc14 (*px, *p01, i00, i01);
- wenc14 (*p10, *p11, i10, i11);
- wenc14 (i00, i10, *px, *p10);
- wenc14 (i01, i11, *p01, *p11);
- }
- else
- {
- wenc16 (*px, *p01, i00, i01);
- wenc16 (*p10, *p11, i10, i11);
- wenc16 (i00, i10, *px, *p10);
- wenc16 (i01, i11, *p01, *p11);
- }
- }
-
- //
- // Encode (1D) odd column (still in Y loop)
- //
-
- if (nx & p)
- {
- unsigned short *p10 = px + oy1;
-
- if (w14)
- wenc14 (*px, *p10, i00, *p10);
- else
- wenc16 (*px, *p10, i00, *p10);
-
- *px= i00;
- }
- }
-
- //
- // Encode (1D) odd line (must loop in X)
- //
-
- if (ny & p)
- {
- unsigned short *px = py;
- unsigned short *ex = py + ox * (nx - p2);
-
- for (; px <= ex; px += ox2)
- {
- unsigned short *p01 = px + ox1;
-
- if (w14)
- wenc14 (*px, *p01, i00, *p01);
- else
- wenc16 (*px, *p01, i00, *p01);
-
- *px= i00;
- }
- }
-
- //
- // Next level
- //
-
- p = p2;
- p2 <<= 1;
+ unsigned short *py = in;
+ unsigned short *ey = in + oy * (ny - p2);
+ int oy1 = oy * p;
+ int oy2 = oy * p2;
+ int ox1 = ox * p;
+ int ox2 = ox * p2;
+ unsigned short i00,i01,i10,i11;
+
+ //
+ // Y loop
+ //
+
+ for (; py <= ey; py += oy2)
+ {
+ unsigned short *px = py;
+ unsigned short *ex = py + ox * (nx - p2);
+
+ //
+ // X loop
+ //
+
+ for (; px <= ex; px += ox2)
+ {
+ unsigned short *p01 = px + ox1;
+ unsigned short *p10 = px + oy1;
+ unsigned short *p11 = p10 + ox1;
+
+ //
+ // 2D wavelet encoding
+ //
+
+ if (w14)
+ {
+ wenc14 (*px, *p01, i00, i01);
+ wenc14 (*p10, *p11, i10, i11);
+ wenc14 (i00, i10, *px, *p10);
+ wenc14 (i01, i11, *p01, *p11);
+ }
+ else
+ {
+ wenc16 (*px, *p01, i00, i01);
+ wenc16 (*p10, *p11, i10, i11);
+ wenc16 (i00, i10, *px, *p10);
+ wenc16 (i01, i11, *p01, *p11);
+ }
+ }
+
+ //
+ // Encode (1D) odd column (still in Y loop)
+ //
+
+ if (nx & p)
+ {
+ unsigned short *p10 = px + oy1;
+
+ if (w14)
+ wenc14 (*px, *p10, i00, *p10);
+ else
+ wenc16 (*px, *p10, i00, *p10);
+
+ *px= i00;
+ }
+ }
+
+ //
+ // Encode (1D) odd line (must loop in X)
+ //
+
+ if (ny & p)
+ {
+ unsigned short *px = py;
+ unsigned short *ex = py + ox * (nx - p2);
+
+ for (; px <= ex; px += ox2)
+ {
+ unsigned short *p01 = px + ox1;
+
+ if (w14)
+ wenc14 (*px, *p01, i00, *p01);
+ else
+ wenc16 (*px, *p01, i00, *p01);
+
+ *px= i00;
+ }
+ }
+
+ //
+ // Next level
+ //
+
+ p = p2;
+ p2 <<= 1;
}
}
//
while (p <= n)
- p <<= 1;
+ p <<= 1;
p >>= 1;
p2 = p;
while (p >= 1)
{
- unsigned short *py = in;
- unsigned short *ey = in + oy * (ny - p2);
- int oy1 = oy * p;
- int oy2 = oy * p2;
- int ox1 = ox * p;
- int ox2 = ox * p2;
- unsigned short i00,i01,i10,i11;
-
- //
- // Y loop
- //
-
- for (; py <= ey; py += oy2)
- {
- unsigned short *px = py;
- unsigned short *ex = py + ox * (nx - p2);
-
- //
- // X loop
- //
-
- for (; px <= ex; px += ox2)
- {
- unsigned short *p01 = px + ox1;
- unsigned short *p10 = px + oy1;
- unsigned short *p11 = p10 + ox1;
-
- //
- // 2D wavelet decoding
- //
-
- if (w14)
- {
- wdec14 (*px, *p10, i00, i10);
- wdec14 (*p01, *p11, i01, i11);
- wdec14 (i00, i01, *px, *p01);
- wdec14 (i10, i11, *p10, *p11);
- }
- else
- {
- wdec16 (*px, *p10, i00, i10);
- wdec16 (*p01, *p11, i01, i11);
- wdec16 (i00, i01, *px, *p01);
- wdec16 (i10, i11, *p10, *p11);
- }
- }
-
- //
- // Decode (1D) odd column (still in Y loop)
- //
-
- if (nx & p)
- {
- unsigned short *p10 = px + oy1;
-
- if (w14)
- wdec14 (*px, *p10, i00, *p10);
- else
- wdec16 (*px, *p10, i00, *p10);
-
- *px= i00;
- }
- }
-
- //
- // Decode (1D) odd line (must loop in X)
- //
-
- if (ny & p)
- {
- unsigned short *px = py;
- unsigned short *ex = py + ox * (nx - p2);
-
- for (; px <= ex; px += ox2)
- {
- unsigned short *p01 = px + ox1;
-
- if (w14)
- wdec14 (*px, *p01, i00, *p01);
- else
- wdec16 (*px, *p01, i00, *p01);
-
- *px= i00;
- }
- }
-
- //
- // Next level
- //
-
- p2 = p;
- p >>= 1;
+ unsigned short *py = in;
+ unsigned short *ey = in + oy * (ny - p2);
+ int oy1 = oy * p;
+ int oy2 = oy * p2;
+ int ox1 = ox * p;
+ int ox2 = ox * p2;
+ unsigned short i00,i01,i10,i11;
+
+ //
+ // Y loop
+ //
+
+ for (; py <= ey; py += oy2)
+ {
+ unsigned short *px = py;
+ unsigned short *ex = py + ox * (nx - p2);
+
+ //
+ // X loop
+ //
+
+ for (; px <= ex; px += ox2)
+ {
+ unsigned short *p01 = px + ox1;
+ unsigned short *p10 = px + oy1;
+ unsigned short *p11 = p10 + ox1;
+
+ //
+ // 2D wavelet decoding
+ //
+
+ if (w14)
+ {
+ wdec14 (*px, *p10, i00, i10);
+ wdec14 (*p01, *p11, i01, i11);
+ wdec14 (i00, i01, *px, *p01);
+ wdec14 (i10, i11, *p10, *p11);
+ }
+ else
+ {
+ wdec16 (*px, *p10, i00, i10);
+ wdec16 (*p01, *p11, i01, i11);
+ wdec16 (i00, i01, *px, *p01);
+ wdec16 (i10, i11, *p10, *p11);
+ }
+ }
+
+ //
+ // Decode (1D) odd column (still in Y loop)
+ //
+
+ if (nx & p)
+ {
+ unsigned short *p10 = px + oy1;
+
+ if (w14)
+ wdec14 (*px, *p10, i00, *p10);
+ else
+ wdec16 (*px, *p10, i00, *p10);
+
+ *px= i00;
+ }
+ }
+
+ //
+ // Decode (1D) odd line (must loop in X)
+ //
+
+ if (ny & p)
+ {
+ unsigned short *px = py;
+ unsigned short *ex = py + ox * (nx - p2);
+
+ for (; px <= ex; px += ox2)
+ {
+ unsigned short *p01 = px + ox1;
+
+ if (w14)
+ wdec14 (*px, *p01, i00, *p01);
+ else
+ wdec16 (*px, *p01, i00, *p01);
+
+ *px= i00;
+ }
+ }
+
+ //
+ // Next level
+ //
+
+ p2 = p;
+ p >>= 1;
}
}
-} // namespace Imf
+OPENEXR_IMF_INTERNAL_NAMESPACE_SOURCE_EXIT
//
// Copyright (c) 2002, Industrial Light & Magic, a division of Lucas
// Digital Ltd. LLC
-//
+//
// All rights reserved.
-//
+//
// Redistribution and use in source and binary forms, with or without
// modification, are permitted provided that the following conditions are
// met:
// distribution.
// * Neither the name of Industrial Light & Magic nor the names of
// its contributors may be used to endorse or promote products derived
-// from this software without specific prior written permission.
-//
+// from this software without specific prior written permission.
+//
// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
// 16-bit Haar Wavelet encoding and decoding
//
//-----------------------------------------------------------------------------
+#include "ImfNamespace.h"
+#include "ImfExport.h"
-namespace Imf {
+OPENEXR_IMF_INTERNAL_NAMESPACE_HEADER_ENTER
+IMF_EXPORT
void
wav2Encode
(unsigned short *in, // io: values in[y][x] are transformed in place
int oy, // i : y offset
unsigned short mx); // i : maximum in[x][y] value
+IMF_EXPORT
void
wav2Decode
(unsigned short *in, // io: values in[y][x] are transformed in place
unsigned short mx); // i : maximum in[x][y] value
-} // namespace Imf
+OPENEXR_IMF_INTERNAL_NAMESPACE_HEADER_EXIT
+
+
+
+
#endif
//
// Copyright (c) 2002, Industrial Light & Magic, a division of Lucas
// Digital Ltd. LLC
-//
+//
// All rights reserved.
-//
+//
// Redistribution and use in source and binary forms, with or without
// modification, are permitted provided that the following conditions are
// met:
// distribution.
// * Neither the name of Industrial Light & Magic nor the names of
// its contributors may be used to endorse or promote products derived
-// from this software without specific prior written permission.
-//
+// from this software without specific prior written permission.
+//
// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
#ifndef INCLUDED_IMF_XDR_H
#define INCLUDED_IMF_XDR_H
+
//----------------------------------------------------------------------------
//
// Xdr -- routines to convert data between the machine's native
// size<S>(); returns the size, in bytes, of the
// machine-independent representation
// of an object of type S.
-//
+//
// The write() and read() routines are templates; data can be written
// to and read from any output or input buffer type T for which a helper
// class, R, exits. Class R must define a method to store a char array
//
//----------------------------------------------------------------------------
-#include <ImfInt64.h>
+#include "ImfInt64.h"
#include "IexMathExc.h"
#include "half.h"
#include <limits.h>
-namespace Imf {
+#include "ImfNamespace.h"
+
+OPENEXR_IMF_INTERNAL_NAMESPACE_HEADER_ENTER
+
namespace Xdr {
#if LONG_MAX == 2147483647
- if (v >= 0)
- {
- b[4] = 0;
- b[5] = 0;
- b[6] = 0;
- b[7] = 0;
- }
- else
- {
- b[4] = ~0;
- b[5] = ~0;
- b[6] = ~0;
- b[7] = ~0;
- }
+ if (v >= 0)
+ {
+ b[4] = 0;
+ b[5] = 0;
+ b[6] = 0;
+ b[7] = 0;
+ }
+ else
+ {
+ b[4] = ~0;
+ b[5] = ~0;
+ b[6] = ~0;
+ b[7] = ~0;
+ }
#elif LONG_MAX == 9223372036854775807L
- b[4] = (signed char) (v >> 32);
- b[5] = (signed char) (v >> 40);
- b[6] = (signed char) (v >> 48);
- b[7] = (signed char) (v >> 56);
+ b[4] = (signed char) (v >> 32);
+ b[5] = (signed char) (v >> 40);
+ b[6] = (signed char) (v >> 48);
+ b[7] = (signed char) (v >> 56);
#else
-
- #error write<T> (T &out, signed long v) not implemented
+
+ #error write<T> (T &out, signed long v) not implemented
#endif
#if ULONG_MAX == 4294967295U
- b[4] = 0;
- b[5] = 0;
- b[6] = 0;
- b[7] = 0;
+ b[4] = 0;
+ b[5] = 0;
+ b[6] = 0;
+ b[7] = 0;
#elif ULONG_MAX == 18446744073709551615LU
- b[4] = (unsigned char) (v >> 32);
- b[5] = (unsigned char) (v >> 40);
- b[6] = (unsigned char) (v >> 48);
- b[7] = (unsigned char) (v >> 56);
+ b[4] = (unsigned char) (v >> 32);
+ b[5] = (unsigned char) (v >> 40);
+ b[6] = (unsigned char) (v >> 48);
+ b[7] = (unsigned char) (v >> 56);
#else
-
- #error write<T> (T &out, unsigned long v) not implemented
+
+ #error write<T> (T &out, unsigned long v) not implemented
#endif
{
while (*v)
{
- S::writeChars (out, v, 1);
- ++v;
+ S::writeChars (out, v, 1);
+ ++v;
}
S::writeChars (out, v, 1);
{
for (int i = 0; i < n; i++)
{
- const char c = 0;
- S::writeChars (out, &c, 1);
+ const char c = 0;
+ S::writeChars (out, &c, 1);
}
}
readSignedChars<S> (in, b, 2);
v = (b[0] & 0x00ff) |
- (b[1] << 8);
+ (b[1] << 8);
}
readUnsignedChars<S> (in, b, 2);
v = (b[0] & 0x00ff) |
- (b[1] << 8);
+ (b[1] << 8);
}
readSignedChars<S> (in, b, 4);
v = (b[0] & 0x000000ff) |
- ((b[1] << 8) & 0x0000ff00) |
- ((b[2] << 16) & 0x00ff0000) |
- (b[3] << 24);
+ ((b[1] << 8) & 0x0000ff00) |
+ ((b[2] << 16) & 0x00ff0000) |
+ (b[3] << 24);
}
readUnsignedChars<S> (in, b, 4);
v = (b[0] & 0x000000ff) |
- ((b[1] << 8) & 0x0000ff00) |
- ((b[2] << 16) & 0x00ff0000) |
- (b[3] << 24);
+ ((b[1] << 8) & 0x0000ff00) |
+ ((b[2] << 16) & 0x00ff0000) |
+ (b[3] << 24);
}
#if LONG_MAX == 2147483647
- v = (b[0] & 0x000000ff) |
- ((b[1] << 8) & 0x0000ff00) |
- ((b[2] << 16) & 0x00ff0000) |
- (b[3] << 24);
+ v = (b[0] & 0x000000ff) |
+ ((b[1] << 8) & 0x0000ff00) |
+ ((b[2] << 16) & 0x00ff0000) |
+ (b[3] << 24);
- if (( b[4] || b[5] || b[6] || b[7]) &&
- (~b[4] || ~b[5] || ~b[6] || ~b[7]))
- {
- throw Iex::OverflowExc ("Long int overflow - read a large "
- "64-bit integer in a 32-bit process.");
- }
+ if (( b[4] || b[5] || b[6] || b[7]) &&
+ (~b[4] || ~b[5] || ~b[6] || ~b[7]))
+ {
+ throw IEX_NAMESPACE::OverflowExc ("Long int overflow - read a large "
+ "64-bit integer in a 32-bit process.");
+ }
#elif LONG_MAX == 9223372036854775807L
- v = ((long) b[0] & 0x00000000000000ff) |
- (((long) b[1] << 8) & 0x000000000000ff00) |
- (((long) b[2] << 16) & 0x0000000000ff0000) |
- (((long) b[3] << 24) & 0x00000000ff000000) |
- (((long) b[4] << 32) & 0x000000ff00000000) |
- (((long) b[5] << 40) & 0x0000ff0000000000) |
- (((long) b[6] << 48) & 0x00ff000000000000) |
- ((long) b[7] << 56);
+ v = ((long) b[0] & 0x00000000000000ff) |
+ (((long) b[1] << 8) & 0x000000000000ff00) |
+ (((long) b[2] << 16) & 0x0000000000ff0000) |
+ (((long) b[3] << 24) & 0x00000000ff000000) |
+ (((long) b[4] << 32) & 0x000000ff00000000) |
+ (((long) b[5] << 40) & 0x0000ff0000000000) |
+ (((long) b[6] << 48) & 0x00ff000000000000) |
+ ((long) b[7] << 56);
#else
- #error read<T> (T &in, signed long &v) not implemented
+ #error read<T> (T &in, signed long &v) not implemented
#endif
}
#if ULONG_MAX == 4294967295U
- v = (b[0] & 0x000000ff) |
- ((b[1] << 8) & 0x0000ff00) |
- ((b[2] << 16) & 0x00ff0000) |
- (b[3] << 24);
+ v = (b[0] & 0x000000ff) |
+ ((b[1] << 8) & 0x0000ff00) |
+ ((b[2] << 16) & 0x00ff0000) |
+ (b[3] << 24);
- if (b[4] || b[5] || b[6] || b[7])
- {
- throw Iex::OverflowExc ("Long int overflow - read a large "
- "64-bit integer in a 32-bit process.");
- }
+ if (b[4] || b[5] || b[6] || b[7])
+ {
+ throw IEX_NAMESPACE::OverflowExc ("Long int overflow - read a large "
+ "64-bit integer in a 32-bit process.");
+ }
#elif ULONG_MAX == 18446744073709551615LU
- v = ((unsigned long) b[0] & 0x00000000000000ff) |
- (((unsigned long) b[1] << 8) & 0x000000000000ff00) |
- (((unsigned long) b[2] << 16) & 0x0000000000ff0000) |
- (((unsigned long) b[3] << 24) & 0x00000000ff000000) |
- (((unsigned long) b[4] << 32) & 0x000000ff00000000) |
- (((unsigned long) b[5] << 40) & 0x0000ff0000000000) |
- (((unsigned long) b[6] << 48) & 0x00ff000000000000) |
- ((unsigned long) b[7] << 56);
+ v = ((unsigned long) b[0] & 0x00000000000000ff) |
+ (((unsigned long) b[1] << 8) & 0x000000000000ff00) |
+ (((unsigned long) b[2] << 16) & 0x0000000000ff0000) |
+ (((unsigned long) b[3] << 24) & 0x00000000ff000000) |
+ (((unsigned long) b[4] << 32) & 0x000000ff00000000) |
+ (((unsigned long) b[5] << 40) & 0x0000ff0000000000) |
+ (((unsigned long) b[6] << 48) & 0x00ff000000000000) |
+ ((unsigned long) b[7] << 56);
#else
- #error read<T> (T &in, unsigned long &v) not implemented
+ #error read<T> (T &in, unsigned long &v) not implemented
#endif
}
readUnsignedChars<S> (in, b, 8);
v = ((Int64) b[0] & 0x00000000000000ffLL) |
- (((Int64) b[1] << 8) & 0x000000000000ff00LL) |
- (((Int64) b[2] << 16) & 0x0000000000ff0000LL) |
- (((Int64) b[3] << 24) & 0x00000000ff000000LL) |
- (((Int64) b[4] << 32) & 0x000000ff00000000LL) |
- (((Int64) b[5] << 40) & 0x0000ff0000000000LL) |
- (((Int64) b[6] << 48) & 0x00ff000000000000LL) |
- ((Int64) b[7] << 56);
+ (((Int64) b[1] << 8) & 0x000000000000ff00LL) |
+ (((Int64) b[2] << 16) & 0x0000000000ff0000LL) |
+ (((Int64) b[3] << 24) & 0x00000000ff000000LL) |
+ (((Int64) b[4] << 32) & 0x000000ff00000000LL) |
+ (((Int64) b[5] << 40) & 0x0000ff0000000000LL) |
+ (((Int64) b[6] << 48) & 0x00ff000000000000LL) |
+ ((Int64) b[7] << 56);
}
#endif
union {unsigned int i; float f;} u;
u.i = (b[0] & 0x000000ff) |
- ((b[1] << 8) & 0x0000ff00) |
- ((b[2] << 16) & 0x00ff0000) |
- (b[3] << 24);
+ ((b[1] << 8) & 0x0000ff00) |
+ ((b[2] << 16) & 0x00ff0000) |
+ (b[3] << 24);
v = u.f;
}
union {Int64 i; double d;} u;
u.i = ((Int64) b[0] & 0x00000000000000ffULL) |
- (((Int64) b[1] << 8) & 0x000000000000ff00ULL) |
- (((Int64) b[2] << 16) & 0x0000000000ff0000ULL) |
- (((Int64) b[3] << 24) & 0x00000000ff000000ULL) |
- (((Int64) b[4] << 32) & 0x000000ff00000000ULL) |
- (((Int64) b[5] << 40) & 0x0000ff0000000000ULL) |
- (((Int64) b[6] << 48) & 0x00ff000000000000ULL) |
- ((Int64) b[7] << 56);
+ (((Int64) b[1] << 8) & 0x000000000000ff00ULL) |
+ (((Int64) b[2] << 16) & 0x0000000000ff0000ULL) |
+ (((Int64) b[3] << 24) & 0x00000000ff000000ULL) |
+ (((Int64) b[4] << 32) & 0x000000ff00000000ULL) |
+ (((Int64) b[5] << 40) & 0x0000ff0000000000ULL) |
+ (((Int64) b[6] << 48) & 0x00ff000000000000ULL) |
+ ((Int64) b[7] << 56);
v = u.d;
}
{
while (n >= 0)
{
- S::readChars (in, v, 1);
+ S::readChars (in, v, 1);
- if (*v == 0)
- break;
+ if (*v == 0)
+ break;
- --n;
- ++v;
+ --n;
+ ++v;
}
}
while (n >= (int) sizeof (c))
{
- if (!S::readChars (in, c, sizeof (c)))
- return;
+ if (!S::readChars (in, c, sizeof (c)))
+ return;
- n -= sizeof (c);
+ n -= sizeof (c);
}
if (n >= 1)
- S::readChars (in, c, n);
+ S::readChars (in, c, n);
}
template <> inline int size <unsigned int> () {return 4;}
template <> inline int size <signed long> () {return 8;}
template <> inline int size <unsigned long> () {return 8;}
+template <> inline int size <unsigned long long> () {return 8;}
template <> inline int size <float> () {return 4;}
template <> inline int size <double> () {return 8;}
template <> inline int size <half> () {return 2;}
} // namespace Xdr
-} // namespace Imf
+OPENEXR_IMF_INTERNAL_NAMESPACE_HEADER_EXIT
+
+
+#if defined (OPENEXR_IMF_INTERNAL_NAMESPACE_AUTO_EXPOSE)
+namespace Imf{using namespace OPENEXR_IMF_INTERNAL_NAMESPACE;}
+#endif
+
#endif
--- /dev/null
+///////////////////////////////////////////////////////////////////////////
+//
+// Copyright (c) 2004, Industrial Light & Magic, a division of Lucas
+// Digital Ltd. LLC
+//
+// All rights reserved.
+//
+// Redistribution and use in source and binary forms, with or without
+// modification, are permitted provided that the following conditions are
+// met:
+// * Redistributions of source code must retain the above copyright
+// notice, this list of conditions and the following disclaimer.
+// * Redistributions in binary form must reproduce the above
+// copyright notice, this list of conditions and the following disclaimer
+// in the documentation and/or other materials provided with the
+// distribution.
+// * Neither the name of Industrial Light & Magic nor the names of
+// its contributors may be used to endorse or promote products derived
+// from this software without specific prior written permission.
+//
+// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+//
+///////////////////////////////////////////////////////////////////////////
+
+#include "ImfZip.h"
+#include "ImfCheckedArithmetic.h"
+#include "ImfNamespace.h"
+#include "ImfSimd.h"
+#include "Iex.h"
+
+#include <math.h>
+#include <zlib.h>
+
+OPENEXR_IMF_INTERNAL_NAMESPACE_SOURCE_ENTER
+
+Zip::Zip(size_t maxRawSize):
+ _maxRawSize(maxRawSize),
+ _tmpBuffer(0)
+{
+ _tmpBuffer = new char[_maxRawSize];
+}
+
+Zip::Zip(size_t maxScanLineSize, size_t numScanLines):
+ _maxRawSize(0),
+ _tmpBuffer(0)
+{
+ _maxRawSize = uiMult (maxScanLineSize, numScanLines);
+ _tmpBuffer = new char[_maxRawSize];
+}
+
+Zip::~Zip()
+{
+ if (_tmpBuffer) delete[] _tmpBuffer;
+}
+
+size_t
+Zip::maxRawSize()
+{
+ return _maxRawSize;
+}
+
+size_t
+Zip::maxCompressedSize()
+{
+ return uiAdd (uiAdd (_maxRawSize,
+ size_t (ceil (_maxRawSize * 0.01))),
+ size_t (100));
+}
+
+int
+Zip::compress(const char *raw, int rawSize, char *compressed)
+{
+ //
+ // Reorder the pixel data.
+ //
+
+ {
+ char *t1 = _tmpBuffer;
+ char *t2 = _tmpBuffer + (rawSize + 1) / 2;
+ const char *stop = raw + rawSize;
+
+ while (true)
+ {
+ if (raw < stop)
+ *(t1++) = *(raw++);
+ else
+ break;
+
+ if (raw < stop)
+ *(t2++) = *(raw++);
+ else
+ break;
+ }
+ }
+
+ //
+ // Predictor.
+ //
+
+ {
+ unsigned char *t = (unsigned char *) _tmpBuffer + 1;
+ unsigned char *stop = (unsigned char *) _tmpBuffer + rawSize;
+ int p = t[-1];
+
+ while (t < stop)
+ {
+ int d = int (t[0]) - p + (128 + 256);
+ p = t[0];
+ t[0] = d;
+ ++t;
+ }
+ }
+
+ //
+ // Compress the data using zlib
+ //
+
+ uLongf outSize = int(ceil(rawSize * 1.01)) + 100;
+
+ if (Z_OK != ::compress ((Bytef *)compressed, &outSize,
+ (const Bytef *) _tmpBuffer, rawSize))
+ {
+ throw IEX_NAMESPACE::BaseExc ("Data compression (zlib) failed.");
+ }
+
+ return outSize;
+}
+
+#ifdef IMF_HAVE_SSE4_1
+
+static void
+reconstruct_sse41(char *buf, size_t outSize)
+{
+ static const size_t bytesPerChunk = sizeof(__m128i);
+ const size_t vOutSize = outSize / bytesPerChunk;
+
+ const __m128i c = _mm_set1_epi8(-128);
+ const __m128i shuffleMask = _mm_set1_epi8(15);
+
+ // The first element doesn't have its high bit flipped during compression,
+ // so it must not be flipped here. To make the SIMD loop nice and
+ // uniform, we pre-flip the bit so that the loop will unflip it again.
+ buf[0] += -128;
+
+ __m128i *vBuf = reinterpret_cast<__m128i *>(buf);
+ __m128i vPrev = _mm_setzero_si128();
+ for (size_t i=0; i<vOutSize; ++i)
+ {
+ __m128i d = _mm_add_epi8(_mm_loadu_si128(vBuf), c);
+
+ // Compute the prefix sum of elements.
+ d = _mm_add_epi8(d, _mm_slli_si128(d, 1));
+ d = _mm_add_epi8(d, _mm_slli_si128(d, 2));
+ d = _mm_add_epi8(d, _mm_slli_si128(d, 4));
+ d = _mm_add_epi8(d, _mm_slli_si128(d, 8));
+ d = _mm_add_epi8(d, vPrev);
+
+ _mm_storeu_si128(vBuf++, d);
+
+ // Broadcast the high byte in our result to all lanes of the prev
+ // value for the next iteration.
+ vPrev = _mm_shuffle_epi8(d, shuffleMask);
+ }
+
+ unsigned char prev = _mm_extract_epi8(vPrev, 15);
+ for (size_t i=vOutSize*bytesPerChunk; i<outSize; ++i)
+ {
+ unsigned char d = prev + buf[i] - 128;
+ buf[i] = d;
+ prev = d;
+ }
+}
+
+#else
+
+static void
+reconstruct_scalar(char *buf, size_t outSize)
+{
+ unsigned char *t = (unsigned char *) buf + 1;
+ unsigned char *stop = (unsigned char *) buf + outSize;
+
+ while (t < stop)
+ {
+ int d = int (t[-1]) + int (t[0]) - 128;
+ t[0] = d;
+ ++t;
+ }
+}
+
+#endif
+
+
+#ifdef IMF_HAVE_SSE2
+
+static void
+interleave_sse2(const char *source, size_t outSize, char *out)
+{
+ static const size_t bytesPerChunk = 2*sizeof(__m128i);
+
+ const size_t vOutSize = outSize / bytesPerChunk;
+
+ const __m128i *v1 = reinterpret_cast<const __m128i *>(source);
+ const __m128i *v2 = reinterpret_cast<const __m128i *>(source + (outSize + 1) / 2);
+ __m128i *vOut = reinterpret_cast<__m128i *>(out);
+
+ for (size_t i=0; i<vOutSize; ++i) {
+ __m128i a = _mm_loadu_si128(v1++);
+ __m128i b = _mm_loadu_si128(v2++);
+
+ __m128i lo = _mm_unpacklo_epi8(a, b);
+ __m128i hi = _mm_unpackhi_epi8(a, b);
+
+ _mm_storeu_si128(vOut++, lo);
+ _mm_storeu_si128(vOut++, hi);
+ }
+
+ const char *t1 = reinterpret_cast<const char *>(v1);
+ const char *t2 = reinterpret_cast<const char *>(v2);
+ char *sOut = reinterpret_cast<char *>(vOut);
+
+ for (size_t i=vOutSize*bytesPerChunk; i<outSize; ++i)
+ {
+ *(sOut++) = (i%2==0) ? *(t1++) : *(t2++);
+ }
+}
+
+#else
+
+static void
+interleave_scalar(const char *source, size_t outSize, char *out)
+{
+ const char *t1 = source;
+ const char *t2 = source + (outSize + 1) / 2;
+ char *s = out;
+ char *const stop = s + outSize;
+
+ while (true)
+ {
+ if (s < stop)
+ *(s++) = *(t1++);
+ else
+ break;
+
+ if (s < stop)
+ *(s++) = *(t2++);
+ else
+ break;
+ }
+}
+
+#endif
+
+int
+Zip::uncompress(const char *compressed, int compressedSize,
+ char *raw)
+{
+ //
+ // Decompress the data using zlib
+ //
+
+ uLongf outSize = _maxRawSize;
+
+ if (Z_OK != ::uncompress ((Bytef *)_tmpBuffer, &outSize,
+ (const Bytef *) compressed, compressedSize))
+ {
+ throw IEX_NAMESPACE::InputExc ("Data decompression (zlib) failed.");
+ }
+
+ if (outSize == 0)
+ {
+ return outSize;
+ }
+
+ //
+ // Predictor.
+ //
+#ifdef IMF_HAVE_SSE4_1
+ reconstruct_sse41(_tmpBuffer, outSize);
+#else
+ reconstruct_scalar(_tmpBuffer, outSize);
+#endif
+
+ //
+ // Reorder the pixel data.
+ //
+#ifdef IMF_HAVE_SSE2
+ interleave_sse2(_tmpBuffer, outSize, raw);
+#else
+ interleave_scalar(_tmpBuffer, outSize, raw);
+#endif
+
+ return outSize;
+}
+
+OPENEXR_IMF_INTERNAL_NAMESPACE_SOURCE_EXIT
//
// Copyright (c) 2002, Industrial Light & Magic, a division of Lucas
// Digital Ltd. LLC
-//
+//
// All rights reserved.
-//
+//
// Redistribution and use in source and binary forms, with or without
// modification, are permitted provided that the following conditions are
// met:
// distribution.
// * Neither the name of Industrial Light & Magic nor the names of
// its contributors may be used to endorse or promote products derived
-// from this software without specific prior written permission.
-//
+// from this software without specific prior written permission.
+//
// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
///////////////////////////////////////////////////////////////////////////
+#ifndef INCLUDED_IMF_ZIP_H
+#define INCLUDED_IMF_ZIP_H
-#include <iostream>
-#include <iomanip>
+#include "ImfNamespace.h"
+#include "ImfExport.h"
-using namespace std;
+#include <cstddef>
-//-----------------------------------------------------
-// Compute a lookup table for float-to-half conversion.
-//
-// When indexed with the combined sign and exponent of
-// a float, the table either returns the combined sign
-// and exponent of the corresponding half, or zero if
-// the corresponding half may not be normalized (zero,
-// denormalized, overflow).
-//-----------------------------------------------------
+OPENEXR_IMF_INTERNAL_NAMESPACE_HEADER_ENTER
-void
-initELut (unsigned short eLut[])
+class Zip
{
- for (int i = 0; i < 0x100; i++)
- {
- int e = (i & 0x0ff) - (127 - 15);
+ public:
+ IMF_EXPORT
+ explicit Zip(size_t rawMaxSize);
+ IMF_EXPORT
+ Zip(size_t maxScanlineSize, size_t numScanLines);
+ IMF_EXPORT
+ ~Zip();
+
+ IMF_EXPORT
+ size_t maxRawSize();
+ IMF_EXPORT
+ size_t maxCompressedSize();
- if (e <= 0 || e >= 30)
- {
//
- // Special case
+ // Compress the raw data into the provided buffer.
+ // Returns the amount of compressed data.
//
+ IMF_EXPORT
+ int compress(const char *raw, int rawSize, char *compressed);
- eLut[i] = 0;
- eLut[i | 0x100] = 0;
- }
- else
- {
- //
- // Common case - normalized half, no exponent overflow possible
+ //
+ // Uncompress the compressed data into the provided
+ // buffer. Returns the amount of raw data actually decoded.
//
+ IMF_EXPORT
+ int uncompress(const char *compressed, int compressedSize,
+ char *raw);
- eLut[i] = (e << 10);
- eLut[i | 0x100] = ((e << 10) | 0x8000);
- }
- }
-}
-
-
-//------------------------------------------------------------
-// Main - prints the sign-and-exponent conversion lookup table
-//------------------------------------------------------------
-
-int
-main ()
-{
- const int tableSize = 1 << 9;
- unsigned short eLut[tableSize];
- initELut (eLut);
-
- cout << "//\n"
- "// This is an automatically generated file.\n"
- "// Do not edit.\n"
- "//\n\n";
-
- cout << "{\n ";
-
- for (int i = 0; i < tableSize; i++)
- {
- cout << setw (5) << eLut[i] << ", ";
+ private:
+ size_t _maxRawSize;
+ char *_tmpBuffer;
- if (i % 8 == 7)
- {
- cout << "\n";
+ Zip();
+ Zip(const Zip&);
+};
- if (i < tableSize - 1)
- cout << " ";
- }
- }
+OPENEXR_IMF_INTERNAL_NAMESPACE_HEADER_EXIT
- cout << "};\n";
- return 0;
-}
+#endif
//
// Copyright (c) 2004, Industrial Light & Magic, a division of Lucas
// Digital Ltd. LLC
-//
+//
// All rights reserved.
-//
+//
// Redistribution and use in source and binary forms, with or without
// modification, are permitted provided that the following conditions are
// met:
// distribution.
// * Neither the name of Industrial Light & Magic nor the names of
// its contributors may be used to endorse or promote products derived
-// from this software without specific prior written permission.
-//
+// from this software without specific prior written permission.
+//
// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
// class ZipCompressor
//
//-----------------------------------------------------------------------------
-//#define ZLIB_WINAPI
-#include <ImfZipCompressor.h>
-#include <ImfCheckedArithmetic.h>
+#include "ImfZipCompressor.h"
+#include "ImfCheckedArithmetic.h"
#include "Iex.h"
#include <zlib.h>
+#include "ImfNamespace.h"
-namespace Imf {
+OPENEXR_IMF_INTERNAL_NAMESPACE_SOURCE_ENTER
ZipCompressor::ZipCompressor
Compressor (hdr),
_maxScanLineSize (maxScanLineSize),
_numScanLines (numScanLines),
- _tmpBuffer (0),
- _outBuffer (0)
+ _outBuffer (0),
+ _zip(maxScanLineSize, numScanLines)
{
- size_t maxInBytes =
- uiMult (maxScanLineSize, numScanLines);
-
- size_t maxOutBytes =
- uiAdd (uiAdd (maxInBytes,
- size_t (ceil (maxInBytes * 0.01))),
- size_t (100));
-
- _tmpBuffer =
- new char [maxInBytes];
-
- _outBuffer =
- new char [maxOutBytes];
+ _outBuffer = new char[_zip.maxCompressedSize()];
}
ZipCompressor::~ZipCompressor ()
{
- delete [] _tmpBuffer;
delete [] _outBuffer;
}
int
ZipCompressor::compress (const char *inPtr,
- int inSize,
- int /*minY*/,
- const char *&outPtr)
+ int inSize,
+ int minY,
+ const char *&outPtr)
{
//
- // Special case Â- empty input buffer
+ // Special case �- empty input buffer
//
if (inSize == 0)
{
- outPtr = _outBuffer;
- return 0;
+ outPtr = _outBuffer;
+ return 0;
}
- //
- // Reorder the pixel data.
- //
-
- {
- char *t1 = _tmpBuffer;
- char *t2 = _tmpBuffer + (inSize + 1) / 2;
- const char *stop = inPtr + inSize;
-
- while (true)
- {
- if (inPtr < stop)
- *(t1++) = *(inPtr++);
- else
- break;
-
- if (inPtr < stop)
- *(t2++) = *(inPtr++);
- else
- break;
- }
- }
-
- //
- // Predictor.
- //
-
- {
- unsigned char *t = (unsigned char *) _tmpBuffer + 1;
- unsigned char *stop = (unsigned char *) _tmpBuffer + inSize;
- int p = t[-1];
-
- while (t < stop)
- {
- int d = int (t[0]) - p + (128 + 256);
- p = t[0];
- t[0] = d;
- ++t;
- }
- }
-
- //
- // Compress the data using zlib
- //
-
- uLongf outSize = int(ceil(inSize * 1.01)) + 100;
-
- if (Z_OK != ::compress ((Bytef *)_outBuffer, &outSize,
- (const Bytef *) _tmpBuffer, inSize))
- {
- throw Iex::BaseExc ("Data compression (zlib) failed.");
- }
+ int outSize = _zip.compress(inPtr, inSize, _outBuffer);
outPtr = _outBuffer;
return outSize;
int
ZipCompressor::uncompress (const char *inPtr,
- int inSize,
- int /*minY*/,
- const char *&outPtr)
+ int inSize,
+ int minY,
+ const char *&outPtr)
{
//
- // Special case Â- empty input buffer
+ // Special case �- empty input buffer
//
if (inSize == 0)
{
- outPtr = _outBuffer;
- return 0;
- }
-
- //
- // Decompress the data using zlib
- //
-
- uLongf outSize = _maxScanLineSize * _numScanLines;
-
- if (Z_OK != ::uncompress ((Bytef *)_tmpBuffer, &outSize,
- (const Bytef *) inPtr, inSize))
- {
- throw Iex::InputExc ("Data decompression (zlib) failed.");
- }
-
- //
- // Predictor.
- //
-
- {
- unsigned char *t = (unsigned char *) _tmpBuffer + 1;
- unsigned char *stop = (unsigned char *) _tmpBuffer + outSize;
-
- while (t < stop)
- {
- int d = int (t[-1]) + int (t[0]) - 128;
- t[0] = d;
- ++t;
+ outPtr = _outBuffer;
+ return 0;
}
- }
-
- //
- // Reorder the pixel data.
- //
- {
- const char *t1 = _tmpBuffer;
- const char *t2 = _tmpBuffer + (outSize + 1) / 2;
- char *s = _outBuffer;
- char *stop = s + outSize;
-
- while (true)
- {
- if (s < stop)
- *(s++) = *(t1++);
- else
- break;
-
- if (s < stop)
- *(s++) = *(t2++);
- else
- break;
- }
- }
+ int outSize = _zip.uncompress(inPtr, inSize, _outBuffer);
outPtr = _outBuffer;
return outSize;
}
-} // namespace Imf
+OPENEXR_IMF_INTERNAL_NAMESPACE_SOURCE_EXIT
+
//
// Copyright (c) 2002, Industrial Light & Magic, a division of Lucas
// Digital Ltd. LLC
-//
+//
// All rights reserved.
-//
+//
// Redistribution and use in source and binary forms, with or without
// modification, are permitted provided that the following conditions are
// met:
// distribution.
// * Neither the name of Industrial Light & Magic nor the names of
// its contributors may be used to endorse or promote products derived
-// from this software without specific prior written permission.
-//
+// from this software without specific prior written permission.
+//
// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
//
//-----------------------------------------------------------------------------
-#include <ImfCompressor.h>
+#include "ImfCompressor.h"
+#include "ImfZip.h"
+#include "ImfNamespace.h"
-namespace Imf {
+OPENEXR_IMF_INTERNAL_NAMESPACE_HEADER_ENTER
class ZipCompressor: public Compressor
{
public:
- ZipCompressor (const Header &hdr,
+ IMF_EXPORT
+ ZipCompressor (const Header &hdr,
size_t maxScanLineSize,
size_t numScanLines);
+ IMF_EXPORT
virtual ~ZipCompressor ();
+ IMF_EXPORT
virtual int numScanLines () const;
+ IMF_EXPORT
virtual int compress (const char *inPtr,
- int inSize,
- int minY,
- const char *&outPtr);
+ int inSize,
+ int minY,
+ const char *&outPtr);
+ IMF_EXPORT
virtual int uncompress (const char *inPtr,
- int inSize,
- int minY,
- const char *&outPtr);
+ int inSize,
+ int minY,
+ const char *&outPtr);
private:
int _maxScanLineSize;
int _numScanLines;
- char * _tmpBuffer;
char * _outBuffer;
+ Zip _zip;
};
-} // namespace Imf
+OPENEXR_IMF_INTERNAL_NAMESPACE_HEADER_EXIT
+
+
+
+
#endif
--- /dev/null
+///////////////////////////////////////////////////////////////////////////
+//
+// Copyright (c) 2009-2014 DreamWorks Animation LLC.
+//
+// All rights reserved.
+//
+// Redistribution and use in source and binary forms, with or without
+// modification, are permitted provided that the following conditions are
+// met:
+// * Redistributions of source code must retain the above copyright
+// notice, this list of conditions and the following disclaimer.
+// * Redistributions in binary form must reproduce the above
+// copyright notice, this list of conditions and the following disclaimer
+// in the documentation and/or other materials provided with the
+// distribution.
+// * Neither the name of DreamWorks Animation nor the names of
+// its contributors may be used to endorse or promote products derived
+// from this software without specific prior written permission.
+//
+// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+//
+///////////////////////////////////////////////////////////////////////////
+
+#define OPENEXR_BUILTIN_TABLES
+
+//
+// A program to generate various acceleration lookup tables
+// for Imf::DwaCompressor
+//
+
+#include <cstddef>
+#include <stdio.h>
+#include <stdlib.h>
+#include <math.h>
+#include <vector>
+
+#include <OpenEXRConfig.h>
+
+#ifndef OPENEXR_BUILTIN_TABLES
+#ifdef OPENEXR_IMF_HAVE_SYSCONF_NPROCESSORS_ONLN
+#include <unistd.h>
+#endif
+#endif // OPENEXR_BUILTIN_TABLES
+
+#include <half.h>
+#include <IlmThread.h>
+#include <IlmThreadSemaphore.h>
+#include <ImfIO.h>
+#include <ImfXdr.h>
+#include "ImfNamespace.h"
+
+using namespace OPENEXR_IMF_NAMESPACE;
+
+namespace {
+
+#ifdef OPENEXR_BUILTIN_TABLES
+static unsigned short dwaCompressorNoOp[0x10000] = {};
+static unsigned short dwaCompressorToLinear[0x10000] = {};
+static unsigned short dwaCompressorToNonlinear[0x10000] = {};
+
+//static unsigned int closestDataOffset[0x10000] = {};
+//static unsigned short closestData[0x80000] = {};
+#else
+
+ class LutHeaderWorker
+ {
+ public:
+ class Runner : public ILMTHREAD_NAMESPACE::Thread
+ {
+ public:
+ Runner(LutHeaderWorker &worker, bool output):
+ ILMTHREAD_NAMESPACE::Thread(),
+ _worker(worker),
+ _output(output)
+ {
+ start();
+ }
+
+ virtual ~Runner()
+ {
+ _semaphore.wait();
+ }
+
+ virtual void run()
+ {
+ _semaphore.post();
+ _worker.run(_output);
+ }
+
+ private:
+ LutHeaderWorker &_worker;
+ bool _output;
+ ILMTHREAD_NAMESPACE::Semaphore _semaphore;
+
+ }; // class LutHeaderWorker::Runner
+
+
+ LutHeaderWorker(size_t startValue,
+ size_t endValue):
+ _lastCandidateCount(0),
+ _startValue(startValue),
+ _endValue(endValue),
+ _numElements(0),
+ _offset(new size_t[numValues()]),
+ _elements(new unsigned short[1024*1024*2])
+ {
+ }
+
+ ~LutHeaderWorker()
+ {
+ delete[] _offset;
+ delete[] _elements;
+ }
+
+ size_t lastCandidateCount() const
+ {
+ return _lastCandidateCount;
+ }
+
+ size_t numValues() const
+ {
+ return _endValue - _startValue;
+ }
+
+ size_t numElements() const
+ {
+ return _numElements;
+ }
+
+ const size_t* offset() const
+ {
+ return _offset;
+ }
+
+ const unsigned short* elements() const
+ {
+ return _elements;
+ }
+
+ void run(bool outputProgress)
+ {
+ half candidate[16];
+ int candidateCount = 0;
+
+ for (size_t input=_startValue; input<_endValue; ++input) {
+
+ if (outputProgress) {
+#ifdef __GNUC__
+ if (input % 100 == 0) {
+ fprintf(stderr,
+ " Building acceleration for DwaCompressor, %.2f %% %c",
+ 100.*(float)input/(float)numValues(), 13);
+ }
+#else
+ if (input % 1000 == 0) {
+ fprintf(stderr,
+ " Building acceleration for DwaCompressor, %.2f %%\n",
+ 100.*(float)input/(float)numValues());
+ }
+#endif
+ }
+
+
+ int numSetBits = countSetBits(input);
+ half inputHalf, closestHalf;
+
+ inputHalf.setBits(input);
+
+ _offset[input - _startValue] = _numElements;
+
+ // Gather candidates
+ candidateCount = 0;
+ for (int targetNumSetBits=numSetBits-1; targetNumSetBits>=0;
+ --targetNumSetBits) {
+ bool valueFound = false;
+
+ for (int i=0; i<65536; ++i) {
+ if (countSetBits(i) != targetNumSetBits) continue;
+
+ if (!valueFound) {
+ closestHalf.setBits(i);
+ valueFound = true;
+ } else {
+ half tmpHalf;
+
+ tmpHalf.setBits(i);
+
+ if (fabs((float)inputHalf - (float)tmpHalf) <
+ fabs((float)inputHalf - (float)closestHalf)) {
+ closestHalf = tmpHalf;
+ }
+ }
+ }
+
+ if (valueFound == false) {
+ fprintf(stderr, "bork bork bork!\n");
+ }
+
+ candidate[candidateCount] = closestHalf;
+ candidateCount++;
+ }
+
+ // Sort candidates by increasing number of bits set
+ for (int i=0; i<candidateCount; ++i) {
+ for (int j=i+1; j<candidateCount; ++j) {
+
+ int iCnt = countSetBits(candidate[i].bits());
+ int jCnt = countSetBits(candidate[j].bits());
+
+ if (jCnt < iCnt) {
+ half tmp = candidate[i];
+ candidate[i] = candidate[j];
+ candidate[j] = tmp;
+ }
+ }
+ }
+
+ // Copy candidates to the data buffer;
+ for (int i=0; i<candidateCount; ++i) {
+ _elements[_numElements] = candidate[i].bits();
+ _numElements++;
+ }
+
+ if (input == _endValue-1) {
+ _lastCandidateCount = candidateCount;
+ }
+ }
+ }
+
+
+ private:
+ size_t _lastCandidateCount;
+ size_t _startValue;
+ size_t _endValue;
+ size_t _numElements;
+ size_t *_offset;
+ unsigned short *_elements;
+
+ //
+ // Precomputing the bit count runs faster than using
+ // the builtin instruction, at least in one case..
+ //
+ // Precomputing 8-bits is no slower than 16-bits,
+ // and saves a fair bit of overhead..
+ //
+ int countSetBits(unsigned short src)
+ {
+ static const unsigned short numBitsSet[256] =
+ {
+ 0, 1, 1, 2, 1, 2, 2, 3, 1, 2, 2, 3, 2, 3, 3, 4,
+ 1, 2, 2, 3, 2, 3, 3, 4, 2, 3, 3, 4, 3, 4, 4, 5,
+ 1, 2, 2, 3, 2, 3, 3, 4, 2, 3, 3, 4, 3, 4, 4, 5,
+ 2, 3, 3, 4, 3, 4, 4, 5, 3, 4, 4, 5, 4, 5, 5, 6,
+ 1, 2, 2, 3, 2, 3, 3, 4, 2, 3, 3, 4, 3, 4, 4, 5,
+ 2, 3, 3, 4, 3, 4, 4, 5, 3, 4, 4, 5, 4, 5, 5, 6,
+ 2, 3, 3, 4, 3, 4, 4, 5, 3, 4, 4, 5, 4, 5, 5, 6,
+ 3, 4, 4, 5, 4, 5, 5, 6, 4, 5, 5, 6, 5, 6, 6, 7,
+ 1, 2, 2, 3, 2, 3, 3, 4, 2, 3, 3, 4, 3, 4, 4, 5,
+ 2, 3, 3, 4, 3, 4, 4, 5, 3, 4, 4, 5, 4, 5, 5, 6,
+ 2, 3, 3, 4, 3, 4, 4, 5, 3, 4, 4, 5, 4, 5, 5, 6,
+ 3, 4, 4, 5, 4, 5, 5, 6, 4, 5, 5, 6, 5, 6, 6, 7,
+ 2, 3, 3, 4, 3, 4, 4, 5, 3, 4, 4, 5, 4, 5, 5, 6,
+ 3, 4, 4, 5, 4, 5, 5, 6, 4, 5, 5, 6, 5, 6, 6, 7,
+ 3, 4, 4, 5, 4, 5, 5, 6, 4, 5, 5, 6, 5, 6, 6, 7,
+ 4, 5, 5, 6, 5, 6, 6, 7, 5, 6, 6, 7, 6, 7, 7, 8
+ };
+
+ return numBitsSet[src & 0xff] + numBitsSet[src >> 8];
+ }
+
+ }; // class LutHeaderWorker
+
+#endif // OPENEXR_BUILTIN_TABLES
+
+} // namespace
+
+
+//
+// Generate a no-op LUT, to cut down in conditional branches
+//
+static void
+generateNoop()
+{
+#ifndef OPENEXR_BUILTIN_TABLES
+ printf("const unsigned short dwaCompressorNoOp[] = \n");
+ printf("{");
+#endif // OPENEXR_BUILTIN_TABLES
+ for (int i=0; i<65536; ++i) {
+#ifndef OPENEXR_BUILTIN_TABLES
+ if (i % 8 == 0) {
+ printf("\n ");
+ }
+#endif // OPENEXR_BUILTIN_TABLES
+ unsigned short dst;
+ char *tmp = (char *)(&dst);
+
+ unsigned short src = (unsigned short)i;
+ Xdr::write <CharPtrIO> (tmp, src);
+#ifndef OPENEXR_BUILTIN_TABLES
+ printf("0x%04x, ", dst);
+#else
+ dwaCompressorNoOp[i] = dst;
+#endif // OPENEXR_BUILTIN_TABLES
+ }
+#ifndef OPENEXR_BUILTIN_TABLES
+ printf("\n};\n");
+#endif // OPENEXR_BUILTIN_TABLES
+}
+
+//
+// Nonlinearly encode luminance. For values below 1.0, we want
+// to use a gamma 2.2 function to match what is fairly common
+// for storing output referred. However, > 1, gamma functions blow up,
+// and log functions are much better behaved. We could use a log
+// function everywhere, but it tends to over-sample dark
+// regions and undersample the brighter regions, when
+// compared to the way real devices reproduce values.
+//
+// So, above 1, use a log function which is a smooth blend
+// into the gamma function.
+//
+// Nonlinear(linear) =
+//
+// linear^(1./2.2) / linear <= 1.0
+// |
+// ln(linear)/ln(e^2.2) + 1 \ otherwise
+//
+//
+// toNonlinear[] needs to take in XDR format half float values,
+// and output NATIVE format float.
+//
+// toLinear[] does the opposite - takes in NATIVE half and
+// outputs XDR half values.
+//
+
+static void
+generateToLinear()
+{
+#ifndef OPENEXR_BUILTIN_TABLES
+ unsigned short toLinear[65536];
+#else
+ unsigned short* toLinear = dwaCompressorToLinear;
+#endif // OPENEXR_BUILTIN_TABLES
+
+ toLinear[0] = 0;
+
+ for (int i=1; i<65536; ++i) {
+ half h;
+ float sign = 1;
+ float logBase = pow(2.7182818, 2.2);
+
+ // map NaN and inf to 0
+ if ((i & 0x7c00) == 0x7c00) {
+ toLinear[i] = 0;
+ continue;
+ }
+
+ //
+ // _toLinear - assume i is NATIVE, but our output needs
+ // to get flipped to XDR
+ //
+ h.setBits(i);
+ sign = 1;
+ if ((float)h < 0) {
+ sign = -1;
+ }
+
+ if ( fabs( (float)h) <= 1.0 ) {
+ h = (half)(sign * pow((float)fabs((float)h), 2.2f));
+ } else {
+ h = (half)(sign * pow(logBase, (float)(fabs((float)h) - 1.0)));
+ }
+
+ {
+ char *tmp = (char *)(&toLinear[i]);
+
+ Xdr::write <CharPtrIO> ( tmp, h.bits());
+ }
+ }
+#ifndef OPENEXR_BUILTIN_TABLES
+ printf("const unsigned short dwaCompressorToLinear[] = \n");
+ printf("{");
+ for (int i=0; i<65536; ++i) {
+ if (i % 8 == 0) {
+ printf("\n ");
+ }
+ printf("0x%04x, ", toLinear[i]);
+ }
+ printf("\n};\n");
+#endif // OPENEXR_BUILTIN_TABLES
+}
+
+
+static void
+generateToNonlinear()
+{
+#ifndef OPENEXR_BUILTIN_TABLES
+ unsigned short toNonlinear[65536];
+#else
+ unsigned short* toNonlinear = dwaCompressorToNonlinear;
+#endif // OPENEXR_BUILTIN_TABLES
+
+ toNonlinear[0] = 0;
+
+ for (int i=1; i<65536; ++i) {
+ unsigned short usNative, usXdr;
+ half h;
+ float sign = 1;
+ float logBase = pow(2.7182818, 2.2);
+
+ usXdr = i;
+
+ {
+ const char *tmp = (char *)(&usXdr);
+
+ Xdr::read<CharPtrIO>(tmp, usNative);
+ }
+
+ // map NaN and inf to 0
+ if ((usNative & 0x7c00) == 0x7c00) {
+ toNonlinear[i] = 0;
+ continue;
+ }
+
+ //
+ // toNonlinear - assume i is XDR
+ //
+ h.setBits(usNative);
+ sign = 1;
+ if ((float)h < 0) {
+ sign = -1;
+ }
+
+ if ( fabs( (float)h ) <= 1.0) {
+ h = (half)(sign * pow(fabs((float)h), 1.f/2.2f));
+ } else {
+ h = (half)(sign * ( log(fabs((float)h)) / log(logBase) + 1.0) );
+ }
+ toNonlinear[i] = h.bits();
+ }
+#ifndef OPENEXR_BUILTIN_TABLES
+ printf("const unsigned short dwaCompressorToNonlinear[] = \n");
+ printf("{");
+ for (int i=0; i<65536; ++i) {
+ if (i % 8 == 0) {
+ printf("\n ");
+ }
+ printf("0x%04x, ", toNonlinear[i]);
+ }
+ printf("\n};\n");
+#endif // OPENEXR_BUILTIN_TABLES
+}
+
+
+#ifndef OPENEXR_BUILTIN_TABLES
+//
+// Attempt to get available CPUs in a somewhat portable way.
+//
+
+int
+cpuCount()
+{
+ if (!ILMTHREAD_NAMESPACE::supportsThreads()) return 1;
+
+ int cpuCount = 1;
+
+#if defined (OPENEXR_IMF_HAVE_SYSCONF_NPROCESSORS_ONLN)
+
+ cpuCount = sysconf(_SC_NPROCESSORS_ONLN);
+
+#elif defined (_WIN32)
+
+ SYSTEM_INFO sysinfo;
+ GetSystemInfo( &sysinfo );
+ cpuCount = sysinfo.dwNumberOfProcessors;
+
+#endif
+
+ if (cpuCount < 1) cpuCount = 1;
+ return cpuCount;
+}
+
+//
+// Generate acceleration luts for the quantization.
+//
+// For each possible input value, we want to find the closest numbers
+// which have one fewer bits set than before.
+//
+// This gives us num_bits(input)-1 values per input. If we alloc
+// space for everything, that's like a 2MB table. We can do better
+// by compressing all the values to be contigious and using offset
+// pointers.
+//
+// After we've found the candidates with fewer bits set, sort them
+// based on increasing numbers of bits set. This way, on quantize(),
+// we can scan through the list and halt once we find the first
+// candidate within the error range. For small values that can
+// be quantized to 0, 0 is the first value tested and the search
+// can exit fairly quickly.
+//
+
+void
+generateLutHeader()
+{
+ std::vector<LutHeaderWorker*> workers;
+
+ size_t numWorkers = cpuCount();
+ size_t workerInterval = 65536 / numWorkers;
+
+ for (size_t i=0; i<numWorkers; ++i) {
+ if (i != numWorkers-1) {
+ workers.push_back( new LutHeaderWorker( i *workerInterval,
+ (i+1)*workerInterval) );
+ } else {
+ workers.push_back( new LutHeaderWorker(i*workerInterval, 65536) );
+ }
+ }
+
+ if (ILMTHREAD_NAMESPACE::supportsThreads()) {
+ std::vector<LutHeaderWorker::Runner*> runners;
+ for (size_t i=0; i<workers.size(); ++i) {
+ runners.push_back( new LutHeaderWorker::Runner(*workers[i], (i==0)) );
+ }
+
+ for (size_t i=0; i<workers.size(); ++i) {
+ delete runners[i];
+ }
+ } else {
+ for (size_t i=0; i<workers.size(); ++i) {
+ workers[i]->run(i == 0);
+ }
+ }
+
+ printf("static unsigned int closestDataOffset[] = {\n");
+ int offsetIdx = 0;
+ int offsetPrev = 0;
+ for (size_t i=0; i<workers.size(); ++i) {
+ for (size_t value=0; value<workers[i]->numValues(); ++value) {
+ if (offsetIdx % 8 == 0) {
+ printf(" ");
+ }
+ printf("%6lu, ", workers[i]->offset()[value] + offsetPrev);
+ if (offsetIdx % 8 == 7) {
+ printf("\n");
+ }
+ offsetIdx++;
+ }
+ offsetPrev += workers[i]->offset()[workers[i]->numValues()-1] +
+ workers[i]->lastCandidateCount();
+ }
+ printf("};\n\n\n");
+
+
+ printf("static unsigned short closestData[] = {\n");
+ int elementIdx = 0;
+ for (size_t i=0; i<workers.size(); ++i) {
+ for (size_t element=0; element<workers[i]->numElements(); ++element) {
+ if (elementIdx % 8 == 0) {
+ printf(" ");
+ }
+ printf("%5d, ", workers[i]->elements()[element]);
+ if (elementIdx % 8 == 7) {
+ printf("\n");
+ }
+ elementIdx++;
+ }
+ }
+ printf("};\n\n\n");
+
+ for (size_t i=0; i<workers.size(); ++i) {
+ delete workers[i];
+ }
+}
+
+
+int
+main(int argc, char **argv)
+{
+ printf("#include <cstddef>\n");
+ printf("\n\n\n");
+
+ generateNoop();
+
+ printf("\n\n\n");
+
+ generateToLinear();
+
+ printf("\n\n\n");
+
+ generateToNonlinear();
+
+ printf("\n\n\n");
+
+ generateLutHeader();
+
+ return 0;
+}
+#else // OPENEXR_BUILTIN_TABLES
+
+#include "dwaLookups.h"
+
+OPENEXR_IMF_INTERNAL_NAMESPACE_SOURCE_ENTER
+
+static void init_dwa_()
+{
+ generateNoop();
+ generateToLinear();
+ generateToNonlinear();
+ // N/A: generateLutHeader();
+}
+
+static inline void init_dwa()
+{
+ static bool initialized = false;
+ if (!initialized)
+ {
+ init_dwa_();
+ initialized = true;
+ }
+}
+
+const unsigned short* get_dwaCompressorNoOp()
+{
+ init_dwa();
+ return dwaCompressorNoOp;
+}
+const unsigned short* get_dwaCompressorToLinear()
+{
+ init_dwa();
+ return dwaCompressorToLinear;
+}
+const unsigned short* get_dwaCompressorToNonlinear()
+{
+ init_dwa();
+ return dwaCompressorToNonlinear;
+}
+
+OPENEXR_IMF_INTERNAL_NAMESPACE_SOURCE_EXIT
+
+#endif // OPENEXR_BUILTIN_TABLES
--- /dev/null
+#include "ImfHeader.h"
+#include "ImfNamespace.h"
+#include "ImfExport.h"
+
+#include <cstddef>
+
+OPENEXR_IMF_INTERNAL_NAMESPACE_HEADER_ENTER
+
+
+const unsigned short* get_dwaCompressorNoOp();
+const unsigned short* get_dwaCompressorToLinear();
+const unsigned short* get_dwaCompressorToNonlinear();
+
+//const unsigned int* get_closestDataOffset();
+//const unsigned short* get_closestData();
+static inline
+const unsigned short* get_dwaClosest(int idx)
+{
+ throw std::runtime_error("OpenEXR: DW* compression tables are not available");
+}
+
+OPENEXR_IMF_INTERNAL_NAMESPACE_HEADER_EXIT
///////////////////////////////////////////////////////////////////////////
//
-// Copyright (c) 2005, Industrial Light & Magic, a division of Lucas
+// Copyright (c) 2005-2012, Industrial Light & Magic, a division of Lucas
// Digital Ltd. LLC
-//
+//
// All rights reserved.
-//
+//
// Redistribution and use in source and binary forms, with or without
// modification, are permitted provided that the following conditions are
// met:
// distribution.
// * Neither the name of Industrial Light & Magic nor the names of
// its contributors may be used to endorse or promote products derived
-// from this software without specific prior written permission.
-//
+// from this software without specific prior written permission.
+//
// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
//-----------------------------------------------------------------------------
//
-// class Thread -- dummy implementation for
-// platforms that do not support threading
+// class Thread -- this file contains two implementations of thread:
+// - dummy implementation for platforms that do not support threading
+// when OPENEXR_FORCE_CXX03 is on
+// - c++11 and newer version
//
//-----------------------------------------------------------------------------
#include "IlmBaseConfig.h"
-
-#if !defined (_WIN32) && !defined(_WIN64) && !(HAVE_PTHREAD)
-
#include "IlmThread.h"
#include "Iex.h"
-namespace IlmThread {
+ILMTHREAD_INTERNAL_NAMESPACE_SOURCE_ENTER
+
+#ifndef ILMBASE_FORCE_CXX03
+//-----------------------------------------------------------------------------
+// C++11 and newer implementation
+//-----------------------------------------------------------------------------
+bool
+supportsThreads ()
+{
+ return true;
+}
+
+Thread::Thread ()
+{
+ // empty
+}
+
+
+Thread::~Thread ()
+{
+ // hopefully the thread has basically exited and we are just
+ // cleaning up, because run is a virtual function, so the v-table
+ // has already been partly destroyed...
+ if ( _thread.joinable () )
+ _thread.join ();
+}
+void
+Thread::start ()
+{
+ _thread = std::thread (&Thread::run, this);
+}
+
+#else
+# if !defined (_WIN32) &&!(_WIN64) && !(HAVE_PTHREAD)
+//-----------------------------------------------------------------------------
+// OPENEXR_FORCE_CXX03 with no windows / pthread support
+//-----------------------------------------------------------------------------
bool
supportsThreads ()
{
Thread::Thread ()
{
- throw Iex::NoImplExc ("Threads not supported on this platform.");
+ throw IEX_NAMESPACE::NoImplExc ("Threads not supported on this platform.");
}
Thread::~Thread ()
{
- throw Iex::NoImplExc ("Threads not supported on this platform.");
+ throw IEX_NAMESPACE::NoImplExc ("Threads not supported on this platform.");
}
void
Thread::start ()
{
- throw Iex::NoImplExc ("Threads not supported on this platform.");
+ throw IEX_NAMESPACE::NoImplExc ("Threads not supported on this platform.");
}
+# endif
+#endif
-} // namespace IlmThread
+ILMTHREAD_INTERNAL_NAMESPACE_SOURCE_EXIT
-#endif
///////////////////////////////////////////////////////////////////////////
//
-// Copyright (c) 2005, Industrial Light & Magic, a division of Lucas
+// Copyright (c) 2005-2012, Industrial Light & Magic, a division of Lucas
// Digital Ltd. LLC
-//
+//
// All rights reserved.
-//
+//
// Redistribution and use in source and binary forms, with or without
// modification, are permitted provided that the following conditions are
// met:
// distribution.
// * Neither the name of Industrial Light & Magic nor the names of
// its contributors may be used to endorse or promote products derived
-// from this software without specific prior written permission.
-//
+// from this software without specific prior written permission.
+//
// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
//-----------------------------------------------------------------------------
#include "IlmBaseConfig.h"
-
-#if defined _WIN32 || defined _WIN64
- #ifdef NOMINMAX
- #undef NOMINMAX
- #endif
- #define NOMINMAX
- #include <windows.h>
- #include <process.h>
-#elif HAVE_PTHREAD
- #include <pthread.h>
-#endif
-
-#if defined(OPENEXR_DLL) && !defined(ZENO_STATIC)
- #ifdef ILMTHREAD_EXPORTS
- #define ILMTHREAD_EXPORT __declspec(dllexport)
- #else
- #define ILMTHREAD_EXPORT __declspec(dllimport)
- #endif
+#include "IlmThreadExport.h"
+#include "IlmThreadNamespace.h"
+
+#ifdef ILMBASE_FORCE_CXX03
+# if defined _WIN32 || defined _WIN64
+# ifdef NOMINMAX
+# undef NOMINMAX
+# endif
+# define NOMINMAX
+# include <windows.h>
+# include <process.h>
+# elif HAVE_PTHREAD
+# include <pthread.h>
+# endif
#else
- #define ILMTHREAD_EXPORT
+# include <thread>
#endif
-namespace IlmThread {
+ILMTHREAD_INTERNAL_NAMESPACE_HEADER_ENTER
//
// Query function to determine if the current platform supports
ILMTHREAD_EXPORT bool supportsThreads ();
-class ILMTHREAD_EXPORT Thread
+class Thread
{
public:
- Thread ();
- virtual ~Thread ();
+ ILMTHREAD_EXPORT Thread ();
+ ILMTHREAD_EXPORT virtual ~Thread ();
- void start ();
- virtual void run () = 0;
+ ILMTHREAD_EXPORT void start ();
+ ILMTHREAD_EXPORT virtual void run () = 0;
private:
- #if defined _WIN32 || defined _WIN64
- HANDLE _thread;
- #elif HAVE_PTHREAD
- pthread_t _thread;
- #endif
-
+#ifdef ILMBASE_FORCE_CXX03
+# if defined _WIN32 || defined _WIN64
+ HANDLE _thread;
+# elif HAVE_PTHREAD
+ pthread_t _thread;
+# endif
void operator = (const Thread& t); // not implemented
Thread (const Thread& t); // not implemented
+#else
+ std::thread _thread;
+
+ Thread &operator= (const Thread& t) = delete;
+ Thread (const Thread& t) = delete;
+#endif
};
-} // namespace IlmThread
+ILMTHREAD_INTERNAL_NAMESPACE_HEADER_EXIT
-#endif
+#endif // INCLUDED_ILM_THREAD_H
--- /dev/null
+///////////////////////////////////////////////////////////////////////////
+//
+// Copyright (c) 2012, Industrial Light & Magic, a division of Lucas
+// Digital Ltd. LLC
+//
+// All rights reserved.
+//
+// Redistribution and use in source and binary forms, with or without
+// modification, are permitted provided that the following conditions are
+// met:
+// * Redistributions of source code must retain the above copyright
+// notice, this list of conditions and the following disclaimer.
+// * Redistributions in binary form must reproduce the above
+// copyright notice, this list of conditions and the following disclaimer
+// in the documentation and/or other materials provided with the
+// distribution.
+// * Neither the name of Industrial Light & Magic nor the names of
+// its contributors may be used to endorse or promote products derived
+// from this software without specific prior written permission.
+//
+// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+//
+///////////////////////////////////////////////////////////////////////////
+
+#if defined(OPENEXR_DLL)
+ #if defined(ILMTHREAD_EXPORTS)
+ #define ILMTHREAD_EXPORT __declspec(dllexport)
+ #define ILMTHREAD_EXPORT_CONST extern __declspec(dllexport)
+ #else
+ #define ILMTHREAD_EXPORT __declspec(dllimport)
+ #define ILMTHREAD_EXPORT_CONST extern __declspec(dllimport)
+ #endif
+#else
+ #define ILMTHREAD_EXPORT
+ #define ILMTHREAD_EXPORT_CONST extern const
+#endif
--- /dev/null
+///////////////////////////////////////////////////////////////////////////
+//
+// Copyright (c) 2012, Industrial Light & Magic, a division of Lucas
+// Digital Ltd. LLC
+//
+// All rights reserved.
+//
+// Redistribution and use in source and binary forms, with or without
+// modification, are permitted provided that the following conditions are
+// met:
+// * Redistributions of source code must retain the above copyright
+// notice, this list of conditions and the following disclaimer.
+// * Redistributions in binary form must reproduce the above
+// copyright notice, this list of conditions and the following disclaimer
+// in the documentation and/or other materials provided with the
+// distribution.
+// * Neither the name of Industrial Light & Magic nor the names of
+// its contributors may be used to endorse or promote products derived
+// from this software without specific prior written permission.
+//
+// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+//
+///////////////////////////////////////////////////////////////////////////
+
+#ifndef INCLUDED_ILMTHREADFORWARD_H
+#define INCLUDED_ILMTHREADFORWARD_H
+
+#include "IlmThreadNamespace.h"
+
+#ifndef ILMBASE_FORCE_CXX03
+namespace std { class mutex; }
+#endif
+
+ILMTHREAD_INTERNAL_NAMESPACE_HEADER_ENTER
+
+class Thread;
+#ifdef ILMBASE_FORCE_CXX03
+class Mutex;
+#else
+using Mutex = std::mutex;
+#endif
+class Lock;
+class ThreadPool;
+class Task;
+class TaskGroup;
+class Semaphore;
+
+ILMTHREAD_INTERNAL_NAMESPACE_HEADER_EXIT
+
+#endif // INCLUDED_ILMTHREADFORWARD_H
///////////////////////////////////////////////////////////////////////////
//
-// Copyright (c) 2005, Industrial Light & Magic, a division of Lucas
+// Copyright (c) 2005-2012, Industrial Light & Magic, a division of Lucas
// Digital Ltd. LLC
-//
+//
// All rights reserved.
-//
+//
// Redistribution and use in source and binary forms, with or without
// modification, are permitted provided that the following conditions are
// met:
// distribution.
// * Neither the name of Industrial Light & Magic nor the names of
// its contributors may be used to endorse or promote products derived
-// from this software without specific prior written permission.
-//
+// from this software without specific prior written permission.
+//
// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
#include "IlmBaseConfig.h"
-#if !defined (_WIN32) && !(_WIN64) && !(HAVE_PTHREAD)
-
-#include "IlmThreadMutex.h"
+#ifdef ILMBASE_FORCE_CXX03
+# if !defined (_WIN32) && !(_WIN64) && !(HAVE_PTHREAD)
+# include "IlmThreadMutex.h"
-namespace IlmThread {
+ILMTHREAD_INTERNAL_NAMESPACE_SOURCE_ENTER
Mutex::Mutex () {}
void Mutex::unlock () const {}
-} // namespace IlmThread
+ILMTHREAD_INTERNAL_NAMESPACE_SOURCE_EXIT
+# endif
#endif
///////////////////////////////////////////////////////////////////////////
//
-// Copyright (c) 2005, Industrial Light & Magic, a division of Lucas
+// Copyright (c) 2005-2012, Industrial Light & Magic, a division of Lucas
// Digital Ltd. LLC
-//
+//
// All rights reserved.
-//
+//
// Redistribution and use in source and binary forms, with or without
// modification, are permitted provided that the following conditions are
// met:
// distribution.
// * Neither the name of Industrial Light & Magic nor the names of
// its contributors may be used to endorse or promote products derived
-// from this software without specific prior written permission.
-//
+// from this software without specific prior written permission.
+//
// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
// share a Lock object among multiple threads.
//
// Typical usage:
-//
+//
// Mutex mtx; // Create a Mutex object that is visible
// //to multiple threads
//
//
//-----------------------------------------------------------------------------
+#include "IlmThreadExport.h"
#include "IlmBaseConfig.h"
-
-#if defined _WIN32 || defined _WIN64
- #ifdef NOMINMAX
- #undef NOMINMAX
- #endif
- #define NOMINMAX
- #include <windows.h>
-#elif HAVE_PTHREAD
- #include <pthread.h>
+#include "IlmThreadNamespace.h"
+
+#ifdef ILMBASE_FORCE_CXX03
+# if defined _WIN32 || defined _WIN64
+# ifdef NOMINMAX
+# undef NOMINMAX
+# endif
+# define NOMINMAX
+# include <windows.h>
+# elif HAVE_PTHREAD
+# include <pthread.h>
+# endif
+#else
+# include <mutex>
#endif
-namespace IlmThread {
+ILMTHREAD_INTERNAL_NAMESPACE_HEADER_ENTER
-class Lock;
+// in c++11, this can just be
+//
+// using Mutex = std::mutex;
+// unfortunately we can't use std::unique_lock as a replacement for Lock since
+// they have different API.
+//
+// if we decide to break the API, we can just
+//
+// using Lock = std::lock_guard<std::mutex>;
+// or
+// using Lock = std::unique_lock<std::mutex>;
+//
+// (or eliminate the type completely and have people use the std library)
+#ifdef ILMBASE_FORCE_CXX03
-class Mutex
+class Lock;
+
+class ILMTHREAD_EXPORT Mutex
{
public:
void unlock () const;
#if defined _WIN32 || defined _WIN64
- mutable CRITICAL_SECTION _mutex;
+ mutable CRITICAL_SECTION _mutex;
#elif HAVE_PTHREAD
- mutable pthread_mutex_t _mutex;
+ mutable pthread_mutex_t _mutex;
#endif
void operator = (const Mutex& M); // not implemented
Mutex (const Mutex& M); // not implemented
-
+
friend class Lock;
};
+#else
+using Mutex = std::mutex;
+#endif
-
-class Lock
+class ILMTHREAD_EXPORT Lock
{
public:
Lock (const Mutex& m, bool autoLock = true):
- _mutex (m),
- _locked (false)
+ _mutex (const_cast<Mutex &>(m)), _locked (false)
{
if (autoLock)
{
_locked = true;
}
}
-
+
~Lock ()
{
if (_locked)
_mutex.unlock();
}
-
+
void acquire ()
{
_mutex.lock();
_locked = true;
}
-
+
void release ()
{
_mutex.unlock();
_locked = false;
}
-
+
bool locked ()
{
return _locked;
private:
- const Mutex & _mutex;
- bool _locked;
+ Mutex & _mutex;
+ bool _locked;
};
-} // namespace IlmThread
+ILMTHREAD_INTERNAL_NAMESPACE_HEADER_EXIT
-#endif
+#endif // INCLUDED_ILM_THREAD_MUTEX_H
///////////////////////////////////////////////////////////////////////////
//
-// Copyright (c) 2005, Industrial Light & Magic, a division of Lucas
+// Copyright (c) 2005-2012, Industrial Light & Magic, a division of Lucas
// Digital Ltd. LLC
-//
+//
// All rights reserved.
-//
+//
// Redistribution and use in source and binary forms, with or without
// modification, are permitted provided that the following conditions are
// met:
// distribution.
// * Neither the name of Industrial Light & Magic nor the names of
// its contributors may be used to endorse or promote products derived
-// from this software without specific prior written permission.
-//
+// from this software without specific prior written permission.
+//
// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
#include "IlmBaseConfig.h"
-#if HAVE_PTHREAD
+#ifdef ILMBASE_FORCE_CXX03
+# if HAVE_PTHREAD
-#include "IlmThreadMutex.h"
-#include "Iex.h"
-#include <assert.h>
+# include "IlmThreadMutex.h"
+# include "Iex.h"
+# include <assert.h>
-namespace IlmThread {
+ILMTHREAD_INTERNAL_NAMESPACE_SOURCE_ENTER
Mutex::Mutex ()
{
if (int error = ::pthread_mutex_init (&_mutex, 0))
- Iex::throwErrnoExc ("Cannot initialize mutex (%T).", error);
+ IEX_INTERNAL_NAMESPACE::throwErrnoExc ("Cannot initialize mutex (%T).", error);
}
Mutex::lock () const
{
if (int error = ::pthread_mutex_lock (&_mutex))
- Iex::throwErrnoExc ("Cannot lock mutex (%T).", error);
+ IEX_INTERNAL_NAMESPACE::throwErrnoExc ("Cannot lock mutex (%T).", error);
}
Mutex::unlock () const
{
if (int error = ::pthread_mutex_unlock (&_mutex))
- Iex::throwErrnoExc ("Cannot unlock mutex (%T).", error);
+ IEX_INTERNAL_NAMESPACE::throwErrnoExc ("Cannot unlock mutex (%T).", error);
}
-} // namespace IlmThread
+ILMTHREAD_INTERNAL_NAMESPACE_SOURCE_EXIT
+# endif
#endif
///////////////////////////////////////////////////////////////////////////
//
-// Copyright (c) 2005, Industrial Light & Magic, a division of Lucas
+// Copyright (c) 2005-2012, Industrial Light & Magic, a division of Lucas
// Digital Ltd. LLC
-//
+//
// All rights reserved.
-//
+//
// Redistribution and use in source and binary forms, with or without
// modification, are permitted provided that the following conditions are
// met:
// distribution.
// * Neither the name of Industrial Light & Magic nor the names of
// its contributors may be used to endorse or promote products derived
-// from this software without specific prior written permission.
-//
+// from this software without specific prior written permission.
+//
// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
//
//-----------------------------------------------------------------------------
-#include "IlmThreadMutex.h"
-#include "Iex.h"
+#include "IlmBaseConfig.h"
-namespace IlmThread {
+#ifdef ILMBASE_FORCE_CXX03
+# include "IlmThreadMutex.h"
+# include "Iex.h"
+
+ILMTHREAD_INTERNAL_NAMESPACE_SOURCE_ENTER
Mutex::Mutex ()
}
-} // namespace IlmThread
+ILMTHREAD_INTERNAL_NAMESPACE_SOURCE_EXIT
+
+#endif
--- /dev/null
+///////////////////////////////////////////////////////////////////////////
+//
+// Copyright (c) 2012, Industrial Light & Magic, a division of Lucas
+// Digital Ltd. LLC
+//
+// All rights reserved.
+//
+// Redistribution and use in source and binary forms, with or without
+// modification, are permitted provided that the following conditions are
+// met:
+// * Redistributions of source code must retain the above copyright
+// notice, this list of conditions and the following disclaimer.
+// * Redistributions in binary form must reproduce the above
+// copyright notice, this list of conditions and the following disclaimer
+// in the documentation and/or other materials provided with the
+// distribution.
+// * Neither the name of Industrial Light & Magic nor the names of
+// its contributors may be used to endorse or promote products derived
+// from this software without specific prior written permission.
+//
+// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+//
+///////////////////////////////////////////////////////////////////////////
+
+#ifndef INCLUDED_ILMTHREADNAMESPACE_H
+#define INCLUDED_ILMTHREADNAMESPACE_H
+
+//
+// The purpose of this file is to make it possible to specify an
+// ILMTHREAD_INTERNAL_NAMESPACE as a preprocessor definition and have all of
+// the IlmThread symbols defined within that namespace rather than the
+// standard IlmThread namespace. Those symbols are made available to client
+// code through the ILMTHREAD_NAMESPACE in addition to the
+// ILMTHREAD_INTERNAL_NAMESPACE.
+//
+// To ensure source code compatibility, the ILMTHREAD_NAMESPACE defaults to
+// IlmThread and then "using namespace ILMTHREAD_INTERNAL_NAMESPACE;" brings
+// all of the declarations from the ILMTHREAD_INTERNAL_NAMESPACE into the
+// ILMTHREAD_NAMESPACE. This means that client code can continue to use
+// syntax like IlmThread::Thread, but at link time it will resolve to a
+// mangled symbol based on the ILMTHREAD_INTERNAL_NAMESPACE.
+//
+// As an example, if one needed to build against a newer version of IlmThread
+// and have it run alongside an older version in the same application, it is
+// now possible to use an internal namespace to prevent collisions between
+// the older versions of IlmThread symbols and the newer ones. To do this,
+// the following could be defined at build time:
+//
+// ILMTHREAD_INTERNAL_NAMESPACE = IlmThread_v2
+//
+// This means that declarations inside IlmThread headers look like this
+// (after the preprocessor has done its work):
+//
+// namespace IlmThread_v2 {
+// ...
+// class declarations
+// ...
+// }
+//
+// namespace IlmThread {
+// using namespace IlmThread_v2;
+// }
+//
+
+//
+// Open Source version of this file pulls in the IlmBaseConfig.h file
+// for the configure time options.
+//
+#include "IlmBaseConfig.h"
+
+#ifndef ILMTHREAD_NAMESPACE
+#define ILMTHREAD_NAMESPACE IlmThread
+#endif
+
+#ifndef ILMTHREAD_INTERNAL_NAMESPACE
+#define ILMTHREAD_INTERNAL_NAMESPACE ILMTHREAD_NAMESPACE
+#endif
+
+//
+// We need to be sure that we import the internal namespace into the public one.
+// To do this, we use the small bit of code below which initially defines
+// ILMTHREAD_INTERNAL_NAMESPACE (so it can be referenced) and then defines
+// ILMTHREAD_NAMESPACE and pulls the internal symbols into the public
+// namespace.
+//
+
+namespace ILMTHREAD_INTERNAL_NAMESPACE {}
+namespace ILMTHREAD_NAMESPACE {
+ using namespace ILMTHREAD_INTERNAL_NAMESPACE;
+}
+
+//
+// There are identical pairs of HEADER/SOURCE ENTER/EXIT macros so that
+// future extension to the namespace mechanism is possible without changing
+// project source code.
+//
+
+#define ILMTHREAD_INTERNAL_NAMESPACE_HEADER_ENTER namespace ILMTHREAD_INTERNAL_NAMESPACE {
+#define ILMTHREAD_INTERNAL_NAMESPACE_HEADER_EXIT }
+
+#define ILMTHREAD_INTERNAL_NAMESPACE_SOURCE_ENTER namespace ILMTHREAD_INTERNAL_NAMESPACE {
+#define ILMTHREAD_INTERNAL_NAMESPACE_SOURCE_EXIT }
+
+#endif // INCLUDED_ILMTHREADNAMESPACE_H
///////////////////////////////////////////////////////////////////////////
//
-// Copyright (c) 2005, Industrial Light & Magic, a division of Lucas
+// Copyright (c) 2005-2012, Industrial Light & Magic, a division of Lucas
// Digital Ltd. LLC
-//
+//
// All rights reserved.
-//
+//
// Redistribution and use in source and binary forms, with or without
// modification, are permitted provided that the following conditions are
// met:
// distribution.
// * Neither the name of Industrial Light & Magic nor the names of
// its contributors may be used to endorse or promote products derived
-// from this software without specific prior written permission.
-//
+// from this software without specific prior written permission.
+//
// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
//-----------------------------------------------------------------------------
//
-// class Task, class ThreadPool, class TaskGroup
+// class Task, class ThreadPool, class TaskGroup
//
//-----------------------------------------------------------------------------
#include "IlmThreadSemaphore.h"
#include "IlmThreadPool.h"
#include "Iex.h"
-#include <list>
+#include <vector>
+#ifndef ILMBASE_FORCE_CXX03
+# include <memory>
+# include <atomic>
+# include <thread>
+#endif
using namespace std;
-namespace IlmThread {
-namespace {
-
-class WorkerThread: public Thread
-{
- public:
-
- WorkerThread (ThreadPool::Data* data);
-
- virtual void run ();
-
- private:
-
- ThreadPool::Data * _data;
-};
-
-} //namespace
+ILMTHREAD_INTERNAL_NAMESPACE_SOURCE_ENTER
+#if defined(__GNU_LIBRARY__) && ( __GLIBC__ < 2 || ( __GLIBC__ == 2 && __GLIBC_MINOR__ < 21 ) )
+# define ENABLE_SEM_DTOR_WORKAROUND
+#endif
struct TaskGroup::Data
{
Data ();
~Data ();
-
- void addTask () ;
- void removeTask ();
-
- Semaphore isEmpty; // used to signal that the taskgroup is empty
- int numPending; // number of pending tasks to still execute
+
+ void addTask () ;
+ void removeTask ();
+#ifndef ILMBASE_FORCE_CXX03
+ std::atomic<int> numPending;
+#else
+ int numPending; // number of pending tasks to still execute
+#endif
+ Semaphore isEmpty; // used to signal that the taskgroup is empty
+#if defined(ENABLE_SEM_DTOR_WORKAROUND) || defined(ILMBASE_FORCE_CXX03)
+ // this mutex is also used to lock numPending in the legacy c++ mode...
+ Mutex dtorMutex; // used to work around the glibc bug:
+ // http://sources.redhat.com/bugzilla/show_bug.cgi?id=12674
+#endif
};
struct ThreadPool::Data
{
+ typedef ThreadPoolProvider *TPPointer;
+
Data ();
~Data();
- void finish ();
- bool stopped () const;
- void stop ();
+ struct SafeProvider
+ {
+ SafeProvider (Data *d, ThreadPoolProvider *p) : _data( d ), _ptr( p )
+ {
+ }
+
+ ~SafeProvider()
+ {
+ if ( _data )
+ _data->coalesceProviderUse();
+ }
+ SafeProvider (const SafeProvider &o)
+ : _data( o._data ), _ptr( o._ptr )
+ {
+ if ( _data )
+ _data->bumpProviderUse();
+ }
+ SafeProvider &operator= (const SafeProvider &o)
+ {
+ if ( this != &o )
+ {
+ if ( o._data )
+ o._data->bumpProviderUse();
+ if ( _data )
+ _data->coalesceProviderUse();
+ _data = o._data;
+ _ptr = o._ptr;
+ }
+ return *this;
+ }
+#ifndef ILMBASE_FORCE_CXX03
+ SafeProvider( SafeProvider &&o )
+ : _data( o._data ), _ptr( o._ptr )
+ {
+ o._data = nullptr;
+ }
+ SafeProvider &operator=( SafeProvider &&o )
+ {
+ std::swap( _data, o._data );
+ std::swap( _ptr, o._ptr );
+ return *this;
+ }
+#endif
+ inline ThreadPoolProvider *get () const
+ {
+ return _ptr;
+ }
+ ThreadPoolProvider *operator-> () const
+ {
+ return get();
+ }
+ Data *_data;
+ ThreadPoolProvider *_ptr;
+ };
+
+ // NB: In C++20, there is full support for atomic shared_ptr, but that is not
+ // yet in use or finalized. Once stabilized, add appropriate usage here
+ inline SafeProvider getProvider ();
+ inline void coalesceProviderUse ();
+ inline void bumpProviderUse ();
+ inline void setProvider (ThreadPoolProvider *p);
+
+#ifdef ILMBASE_FORCE_CXX03
+ Semaphore provSem;
+ Mutex provMutex;
+ int provUsers;
+ ThreadPoolProvider *provider;
+ ThreadPoolProvider *oldprovider;
+#else
+ std::atomic<ThreadPoolProvider *> provider;
+ std::atomic<int> provUsers;
+#endif
+};
+
+
+
+namespace {
+
+class DefaultWorkerThread;
+
+struct DefaultWorkData
+{
Semaphore taskSemaphore; // threads wait on this for ready tasks
- Mutex taskMutex; // mutual exclusion for the tasks list
- list<Task*> tasks; // the list of tasks to execute
- size_t numTasks; // fast access to list size
- // (list::size() can be O(n))
+ mutable Mutex taskMutex; // mutual exclusion for the tasks list
+ vector<Task*> tasks; // the list of tasks to execute
Semaphore threadSemaphore; // signaled when a thread starts executing
- Mutex threadMutex; // mutual exclusion for threads list
- list<WorkerThread*> threads; // the list of all threads
- size_t numThreads; // fast access to list size
-
+ mutable Mutex threadMutex; // mutual exclusion for threads list
+ vector<DefaultWorkerThread*> threads; // the list of all threads
+
+#ifdef ILMBASE_FORCE_CXX03
bool stopping; // flag indicating whether to stop threads
- Mutex stopMutex; // mutual exclusion for stopping flag
-};
+ mutable Mutex stopMutex; // mutual exclusion for stopping flag
+#else
+ std::atomic<bool> hasThreads;
+ std::atomic<bool> stopping;
+#endif
+ inline bool stopped () const
+ {
+#ifdef ILMBASE_FORCE_CXX03
+ Lock lock (stopMutex);
+ return stopping;
+#else
+ return stopping.load( std::memory_order_relaxed );
+#endif
+ }
+ inline void stop ()
+ {
+#ifdef ILMBASE_FORCE_CXX03
+ Lock lock (stopMutex);
+#endif
+ stopping = true;
+ }
+};
//
// class WorkerThread
//
+class DefaultWorkerThread: public Thread
+{
+ public:
-WorkerThread::WorkerThread (ThreadPool::Data* data):
+ DefaultWorkerThread (DefaultWorkData* data);
+
+ virtual void run ();
+
+ private:
+
+ DefaultWorkData * _data;
+};
+
+
+DefaultWorkerThread::DefaultWorkerThread (DefaultWorkData* data):
_data (data)
{
start();
void
-WorkerThread::run ()
+DefaultWorkerThread::run ()
{
//
// Signal that the thread has started executing
while (true)
{
- //
+ //
// Wait for a task to become available
- //
+ //
_data->taskSemaphore.wait();
{
Lock taskLock (_data->taskMutex);
-
- //
+
+ //
// If there is a task pending, pop off the next task in the FIFO
- //
+ //
- if (_data->numTasks > 0)
+ if (!_data->tasks.empty())
{
- Task* task = _data->tasks.front();
- TaskGroup* taskGroup = task->group();
- _data->tasks.pop_front();
- _data->numTasks--;
-
+ Task* task = _data->tasks.back();
+ _data->tasks.pop_back();
taskLock.release();
+
+ TaskGroup* taskGroup = task->group();
task->execute();
- taskLock.acquire();
delete task;
- taskGroup->_data->removeTask();
+
+ taskGroup->_data->removeTask ();
}
else if (_data->stopped())
- {
+ {
break;
+ }
}
+ }
+}
+
+
+//
+// class DefaultThreadPoolProvider
+//
+class DefaultThreadPoolProvider : public ThreadPoolProvider
+{
+ public:
+ DefaultThreadPoolProvider(int count);
+ virtual ~DefaultThreadPoolProvider();
+
+ virtual int numThreads() const;
+ virtual void setNumThreads(int count);
+ virtual void addTask(Task *task);
+
+ virtual void finish();
+
+ private:
+ DefaultWorkData _data;
+};
+
+DefaultThreadPoolProvider::DefaultThreadPoolProvider (int count)
+{
+ setNumThreads(count);
+}
+
+DefaultThreadPoolProvider::~DefaultThreadPoolProvider ()
+{
+ finish();
+}
+
+int
+DefaultThreadPoolProvider::numThreads () const
+{
+ Lock lock (_data.threadMutex);
+ return static_cast<int> (_data.threads.size());
+}
+
+void
+DefaultThreadPoolProvider::setNumThreads (int count)
+{
+ //
+ // Lock access to thread list and size
+ //
+
+ Lock lock (_data.threadMutex);
+
+ size_t desired = static_cast<size_t>(count);
+ if (desired > _data.threads.size())
+ {
+ //
+ // Add more threads
+ //
+
+ while (_data.threads.size() < desired)
+ _data.threads.push_back (new DefaultWorkerThread (&_data));
+ }
+ else if ((size_t)count < _data.threads.size())
+ {
+ //
+ // Wait until all existing threads are finished processing,
+ // then delete all threads.
+ //
+ finish ();
+
+ //
+ // Add in new threads
+ //
+
+ while (_data.threads.size() < desired)
+ _data.threads.push_back (new DefaultWorkerThread (&_data));
+ }
+#ifndef ILMBASE_FORCE_CXX03
+ _data.hasThreads = !(_data.threads.empty());
+#endif
+}
+
+void
+DefaultThreadPoolProvider::addTask (Task *task)
+{
+ //
+ // Lock the threads, needed to access numThreads
+ //
+#ifdef ILMBASE_FORCE_CXX03
+ bool doPush;
+ {
+ Lock lock (_data.threadMutex);
+ doPush = !_data.threads.empty();
+ }
+#else
+ bool doPush = _data.hasThreads.load( std::memory_order_relaxed );
+#endif
+
+ if ( doPush )
+ {
+ //
+ // Get exclusive access to the tasks queue
+ //
+
+ {
+ Lock taskLock (_data.taskMutex);
+
+ //
+ // Push the new task into the FIFO
+ //
+ _data.tasks.push_back (task);
}
+
+ //
+ // Signal that we have a new task to process
+ //
+ _data.taskSemaphore.post ();
+ }
+ else
+ {
+ // this path shouldn't normally happen since we have the
+ // NullThreadPoolProvider, but just in case...
+ task->execute ();
+ task->group()->_data->removeTask ();
+ delete task;
}
}
+void
+DefaultThreadPoolProvider::finish ()
+{
+ _data.stop();
+
+ //
+ // Signal enough times to allow all threads to stop.
+ //
+ // Wait until all threads have started their run functions.
+ // If we do not wait before we destroy the threads then it's
+ // possible that the threads have not yet called their run
+ // functions.
+ // If this happens then the run function will be called off
+ // of an invalid object and we will crash, most likely with
+ // an error like: "pure virtual method called"
+ //
+
+ size_t curT = _data.threads.size();
+ for (size_t i = 0; i != curT; ++i)
+ {
+ _data.taskSemaphore.post();
+ _data.threadSemaphore.wait();
+ }
+
+ //
+ // Join all the threads
+ //
+ for (size_t i = 0; i != curT; ++i)
+ delete _data.threads[i];
+
+ Lock lock1 (_data.taskMutex);
+#ifdef ILMBASE_FORCE_CXX03
+ Lock lock2 (_data.stopMutex);
+#endif
+ _data.threads.clear();
+ _data.tasks.clear();
+
+ _data.stopping = false;
+}
+
+
+class NullThreadPoolProvider : public ThreadPoolProvider
+{
+ virtual ~NullThreadPoolProvider() {}
+ virtual int numThreads () const { return 0; }
+ virtual void setNumThreads (int count)
+ {
+ }
+ virtual void addTask (Task *t)
+ {
+ t->execute ();
+ t->group()->_data->removeTask ();
+ delete t;
+ }
+ virtual void finish () {}
+};
+
+} //namespace
+
//
// struct TaskGroup::Data
//
isEmpty.wait ();
+
+#ifdef ENABLE_SEM_DTOR_WORKAROUND
+ // Update: this was fixed in v. 2.2.21, so this ifdef checks for that
+ //
+ // Alas, given the current bug in glibc we need a secondary
+ // syncronisation primitive here to account for the fact that
+ // destructing the isEmpty Semaphore in this thread can cause
+ // an error for a separate thread that is issuing the post() call.
+ // We are entitled to destruct the semaphore at this point, however,
+ // that post() call attempts to access data out of the associated
+ // memory *after* it has woken the waiting threads, including this one,
+ // potentially leading to invalid memory reads.
+ // http://sources.redhat.com/bugzilla/show_bug.cgi?id=12674
+
+ Lock lock (dtorMutex);
+#endif
}
void
-TaskGroup::Data::addTask ()
+TaskGroup::Data::addTask ()
{
//
- // Any access to the taskgroup is protected by a mutex that is
- // held by the threadpool. Therefore it is safe to access
- // numPending before we wait on the semaphore.
+ // in c++11, we use an atomic to protect numPending to avoid the
+ // extra lock but for c++98, to add the ability for custom thread
+ // pool we add the lock here
//
-
+#if ILMBASE_FORCE_CXX03
+ Lock lock (dtorMutex);
+#endif
if (numPending++ == 0)
- isEmpty.wait ();
+ isEmpty.wait ();
}
void
TaskGroup::Data::removeTask ()
{
+ // Alas, given the current bug in glibc we need a secondary
+ // syncronisation primitive here to account for the fact that
+ // destructing the isEmpty Semaphore in a separate thread can
+ // cause an error. Issuing the post call here the current libc
+ // implementation attempts to access memory *after* it has woken
+ // waiting threads.
+ // Since other threads are entitled to delete the semaphore the
+ // access to the memory location can be invalid.
+ // http://sources.redhat.com/bugzilla/show_bug.cgi?id=12674
+ // Update: this bug has been fixed, but how do we know which
+ // glibc version we're in?
+
+ // Further update:
+ //
+ // we could remove this if it is a new enough glibc, however
+ // we've changed the API to enable a custom override of a
+ // thread pool. In order to provide safe access to the numPending,
+ // we need the lock anyway, except for c++11 or newer
+#ifdef ILMBASE_FORCE_CXX03
+ Lock lock (dtorMutex);
+
if (--numPending == 0)
- isEmpty.post ();
+ isEmpty.post ();
+#else
+ if (--numPending == 0)
+ {
+#ifdef ENABLE_SEM_DTOR_WORKAROUND
+ Lock lock (dtorMutex);
+#endif
+ isEmpty.post ();
+ }
+#endif
}
-
+
//
// struct ThreadPool::Data
//
-ThreadPool::Data::Data (): numTasks (0), numThreads (0), stopping (false)
+ThreadPool::Data::Data ():
+ provUsers (0), provider (NULL)
+#ifdef ILMBASE_FORCE_CXX03
+ , oldprovider (NULL)
+#else
+#endif
{
// empty
}
ThreadPool::Data::~Data()
{
- Lock lock (threadMutex);
- finish ();
+#ifdef ILMBASE_FORCE_CXX03
+ provider->finish();
+#else
+ ThreadPoolProvider *p = provider.load( std::memory_order_relaxed );
+ p->finish();
+#endif
}
-
-void
-ThreadPool::Data::finish ()
+inline ThreadPool::Data::SafeProvider
+ThreadPool::Data::getProvider ()
{
- stop();
+#ifdef ILMBASE_FORCE_CXX03
+ Lock provLock( provMutex );
+ ++provUsers;
+ return SafeProvider( this, provider );
+#else
+ provUsers.fetch_add( 1, std::memory_order_relaxed );
+ return SafeProvider( this, provider.load( std::memory_order_relaxed ) );
+#endif
+}
- //
- // Signal enough times to allow all threads to stop.
- //
- // Wait until all threads have started their run functions.
- // If we do not wait before we destroy the threads then it's
- // possible that the threads have not yet called their run
- // functions.
- // If this happens then the run function will be called off
- // of an invalid object and we will crash, most likely with
- // an error like: "pure virtual method called"
- //
- for (size_t i = 0; i < numThreads; i++)
+inline void
+ThreadPool::Data::coalesceProviderUse ()
+{
+#ifdef ILMBASE_FORCE_CXX03
+ Lock provLock( provMutex );
+ --provUsers;
+ if ( provUsers == 0 )
{
- taskSemaphore.post();
- threadSemaphore.wait();
+ if ( oldprovider )
+ provSem.post();
}
-
- //
- // Join all the threads
- //
-
- for (list<WorkerThread*>::iterator i = threads.begin();
- i != threads.end();
- ++i)
+#else
+ int ov = provUsers.fetch_sub( 1, std::memory_order_relaxed );
+ // ov is the previous value, so one means that now it might be 0
+ if ( ov == 1 )
{
- delete (*i);
+
}
-
- Lock lock1 (taskMutex);
- Lock lock2 (stopMutex);
- threads.clear();
- tasks.clear();
- numThreads = 0;
- numTasks = 0;
- stopping = false;
+#endif
}
-bool
-ThreadPool::Data::stopped () const
+inline void
+ThreadPool::Data::bumpProviderUse ()
{
- Lock lock (stopMutex);
- return stopping;
+#ifdef ILMBASE_FORCE_CXX03
+ Lock lock (provMutex);
+ ++provUsers;
+#else
+ provUsers.fetch_add( 1, std::memory_order_relaxed );
+#endif
}
-void
-ThreadPool::Data::stop ()
+inline void
+ThreadPool::Data::setProvider (ThreadPoolProvider *p)
{
- Lock lock (stopMutex);
- stopping = true;
-}
+#ifdef ILMBASE_FORCE_CXX03
+ Lock provLock( provMutex );
+
+ if ( oldprovider )
+ throw IEX_INTERNAL_NAMESPACE::ArgExc ("Attempt to set the thread pool provider while"
+ " another thread is currently setting the provider.");
+
+ oldprovider = provider;
+ provider = p;
+
+ while ( provUsers > 0 )
+ {
+ provLock.release();
+ provSem.wait();
+ provLock.acquire();
+ }
+ if ( oldprovider )
+ {
+ oldprovider->finish();
+ delete oldprovider;
+ oldprovider = NULL;
+ }
+#else
+ ThreadPoolProvider *old = provider.load( std::memory_order_relaxed );
+ do
+ {
+ if ( ! provider.compare_exchange_weak( old, p, std::memory_order_release, std::memory_order_relaxed ) )
+ continue;
+ } while ( false );
+ // wait for any other users to finish prior to deleting, given
+ // that these are just mostly to query the thread count or push a
+ // task to the queue (so fast), just spin...
+ //
+ // (well, and normally, people don't do this mid stream anyway, so
+ // this will be 0 99.999% of the time, but just to be safe)
+ //
+ while ( provUsers.load( std::memory_order_relaxed ) > 0 )
+ std::this_thread::yield();
+
+ if ( old )
+ {
+ old->finish();
+ delete old;
+ }
+
+ // NB: the shared_ptr mechanism is safer and means we don't have
+ // to have the provUsers counter since the shared_ptr keeps that
+ // for us. However, gcc 4.8/9 compilers which many people are
+ // still using even though it is 2018 forgot to add the shared_ptr
+ // functions... once that compiler is fully deprecated, switch to
+ // using the below, change provider to a std::shared_ptr and remove
+ // provUsers...
+ //
+// std::shared_ptr<ThreadPoolProvider> newp( p );
+// std::shared_ptr<ThreadPoolProvider> curp = std::atomic_load_explicit( &provider, std::memory_order_relaxed );
+// do
+// {
+// if ( ! std::atomic_compare_exchange_weak_explicit( &provider, &curp, newp, std::memory_order_release, std::memory_order_relaxed ) )
+// continue;
+// } while ( false );
+// if ( curp )
+// curp->finish();
+#endif
+}
//
// class Task
Task::Task (TaskGroup* g): _group(g)
{
- // empty
+ if ( g )
+ g->_data->addTask ();
}
}
+void
+TaskGroup::finishOneTask ()
+{
+ _data->removeTask ();
+}
+
+//
+// class ThreadPoolProvider
+//
+
+
+ThreadPoolProvider::ThreadPoolProvider()
+{
+}
+
+
+ThreadPoolProvider::~ThreadPoolProvider()
+{
+}
+
+
//
// class ThreadPool
//
ThreadPool::ThreadPool (unsigned nthreads):
- _data (new Data())
+ _data (new Data)
{
- setNumThreads (nthreads);
+ if ( nthreads == 0 )
+ _data->setProvider( new NullThreadPoolProvider );
+ else
+ _data->setProvider( new DefaultThreadPoolProvider( int(nthreads) ) );
}
int
ThreadPool::numThreads () const
{
- Lock lock (_data->threadMutex);
- return _data->numThreads;
+ return _data->getProvider ()->numThreads ();
}
ThreadPool::setNumThreads (int count)
{
if (count < 0)
- throw Iex::ArgExc ("Attempt to set the number of threads "
+ throw IEX_INTERNAL_NAMESPACE::ArgExc ("Attempt to set the number of threads "
"in a thread pool to a negative value.");
- //
- // Lock access to thread list and size
- //
-
- Lock lock (_data->threadMutex);
-
- if ((size_t)count > _data->numThreads)
+ bool doReset = false;
{
- //
- // Add more threads
- //
+ Data::SafeProvider sp = _data->getProvider ();
+ int curT = sp->numThreads ();
+ if ( curT == count )
+ return;
- while (_data->numThreads < (size_t)count)
+ if ( curT == 0 )
{
- _data->threads.push_back (new WorkerThread (_data));
- _data->numThreads++;
+ NullThreadPoolProvider *npp = dynamic_cast<NullThreadPoolProvider *>( sp.get() );
+ if ( npp )
+ doReset = true;
}
- }
- else if ((size_t)count < _data->numThreads)
- {
- //
- // Wait until all existing threads are finished processing,
- // then delete all threads.
- //
-
- _data->finish ();
-
- //
- // Add in new threads
- //
-
- while (_data->numThreads < (size_t)count)
+ else if ( count == 0 )
{
- _data->threads.push_back (new WorkerThread (_data));
- _data->numThreads++;
+ DefaultThreadPoolProvider *dpp = dynamic_cast<DefaultThreadPoolProvider *>( sp.get() );
+ if ( dpp )
+ doReset = true;
}
+ if ( ! doReset )
+ sp->setNumThreads( count );
}
-}
-
-void
-ThreadPool::addTask (Task* task)
-{
- //
- // Lock the threads, needed to access numThreads
- //
-
- Lock lock (_data->threadMutex);
-
- if (_data->numThreads == 0)
+ if ( doReset )
{
- task->execute ();
- delete task;
+ if ( count == 0 )
+ _data->setProvider( new NullThreadPoolProvider );
+ else
+ _data->setProvider( new DefaultThreadPoolProvider( count ) );
}
- else
- {
- //
- // Get exclusive access to the tasks queue
- //
+}
- {
- Lock taskLock (_data->taskMutex);
- //
- // Push the new task into the FIFO
- //
-
- _data->tasks.push_back (task);
- _data->numTasks++;
- task->group()->_data->addTask();
- }
+void
+ThreadPool::setThreadProvider (ThreadPoolProvider *provider)
+{
+ _data->setProvider (provider);
+}
- //
- // Signal that we have a new task to process
- //
- _data->taskSemaphore.post ();
- }
+void
+ThreadPool::addTask (Task* task)
+{
+ _data->getProvider ()->addTask (task);
}
//
// The global thread pool
//
-
+
static ThreadPool gThreadPool (0);
return gThreadPool;
}
-} // namespace IlmThread
+ILMTHREAD_INTERNAL_NAMESPACE_SOURCE_EXIT
///////////////////////////////////////////////////////////////////////////
//
-// Copyright (c) 2005, Industrial Light & Magic, a division of Lucas
+// Copyright (c) 2005-2012, Industrial Light & Magic, a division of Lucas
// Digital Ltd. LLC
-//
+//
// All rights reserved.
-//
+//
// Redistribution and use in source and binary forms, with or without
// modification, are permitted provided that the following conditions are
// met:
// distribution.
// * Neither the name of Industrial Light & Magic nor the names of
// its contributors may be used to endorse or promote products derived
-// from this software without specific prior written permission.
-//
+// from this software without specific prior written permission.
+//
// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
#ifndef INCLUDED_ILM_THREAD_POOL_H
#define INCLUDED_ILM_THREAD_POOL_H
+
//-----------------------------------------------------------------------------
//
// class Task, class ThreadPool, class TaskGroup
//
// Class ThreadPool manages a set of worker threads and accepts
// tasks for processing. Tasks added to the thread pool are
-// executed concurrently by the worker threads.
-//
-// Class Thread provides an abstract interface for a task which
+// executed concurrently by the worker threads.
+//
+// Class Task provides an abstract interface for a task which
// a ThreadPool works on. Derived classes need to implement the
// execute() function which performs the actual task.
//
-// Class TaskTroup allows synchronization on the completion of a set
+// Class TaskGroup allows synchronization on the completion of a set
// of tasks. Every task that is added to a ThreadPool belongs to a
// single TaskGroup. The destructor of the TaskGroup waits for all
// tasks in the group to finish.
//
//-----------------------------------------------------------------------------
-namespace IlmThread {
+#include "IlmThreadNamespace.h"
+#include "IlmThreadExport.h"
+
+ILMTHREAD_INTERNAL_NAMESPACE_HEADER_ENTER
class TaskGroup;
class Task;
+//-------------------------------------------------------
+// ThreadPoolProvider -- this is a pure virtual interface
+// enabling custom overloading of the threads used and how
+// the implementation of the processing of tasks
+// is implemented
+//-------------------------------------------------------
+class ILMTHREAD_EXPORT ThreadPoolProvider
+{
+ public:
+ ThreadPoolProvider();
+ virtual ~ThreadPoolProvider();
+
+ // as in ThreadPool below
+ virtual int numThreads () const = 0;
+ // as in ThreadPool below
+ virtual void setNumThreads (int count) = 0;
+ // as in ThreadPool below
+ virtual void addTask (Task* task) = 0;
+
+ // Ensure that all tasks in this set are finished
+ // and threads shutdown
+ virtual void finish () = 0;
+
+ // Make the provider non-copyable
+#if __cplusplus >= 201103L
+ ThreadPoolProvider (const ThreadPoolProvider &) = delete;
+ ThreadPoolProvider &operator= (const ThreadPoolProvider &) = delete;
+ ThreadPoolProvider (ThreadPoolProvider &&) = delete;
+ ThreadPoolProvider &operator= (ThreadPoolProvider &&) = delete;
+#else
+ private:
+ ThreadPoolProvider (const ThreadPoolProvider &);
+ ThreadPoolProvider &operator= (const ThreadPoolProvider &);
+#endif
+};
-class ThreadPool
+class ILMTHREAD_EXPORT ThreadPool
{
public:
+
//-------------------------------------------------------
// Constructor -- creates numThreads worker threads which
- // wait until a task is available.
+ // wait until a task is available,
+ // using a default ThreadPoolProvider
//-------------------------------------------------------
ThreadPool (unsigned numThreads = 0);
//-----------------------------------------------------------
virtual ~ThreadPool ();
-
+
//--------------------------------------------------------
// Query and set the number of worker threads in the pool.
// thread as this will almost certainly cause a deadlock
// or crash.
//--------------------------------------------------------
-
+
int numThreads () const;
void setNumThreads (int count);
+ //--------------------------------------------------------
+ // Set the thread provider for the pool.
+ //
+ // The ThreadPool takes ownership of the ThreadPoolProvider
+ // and will call delete on it when it is finished or when
+ // it is changed
+ //
+ // Warning: never call setThreadProvider from within a worker
+ // thread as this will almost certainly cause a deadlock
+ // or crash.
+ //--------------------------------------------------------
+ void setThreadProvider (ThreadPoolProvider *provider);
//------------------------------------------------------------
// Add a task for processing. The ThreadPool can handle any
//------------------------------------------------------------
void addTask (Task* task);
-
+
//-------------------------------------------
// Access functions for the global threadpool
//-------------------------------------------
-
+
static ThreadPool& globalThreadPool ();
static void addGlobalTask (Task* task);
};
-class Task
+class ILMTHREAD_EXPORT Task
{
public:
};
-class TaskGroup
+class ILMTHREAD_EXPORT TaskGroup
{
public:
- TaskGroup();
+ TaskGroup();
~TaskGroup();
+ // marks one task as finished
+ // should be used by the thread pool provider to notify
+ // as it finishes tasks
+ void finishOneTask ();
+
struct Data;
Data* const _data;
};
-} // namespace IlmThread
+ILMTHREAD_INTERNAL_NAMESPACE_HEADER_EXIT
-#endif
+#endif // INCLUDED_ILM_THREAD_POOL_H
///////////////////////////////////////////////////////////////////////////
//
-// Copyright (c) 2005, Industrial Light & Magic, a division of Lucas
+// Copyright (c) 2005-2012, Industrial Light & Magic, a division of Lucas
// Digital Ltd. LLC
-//
+//
// All rights reserved.
-//
+//
// Redistribution and use in source and binary forms, with or without
// modification, are permitted provided that the following conditions are
// met:
// distribution.
// * Neither the name of Industrial Light & Magic nor the names of
// its contributors may be used to endorse or promote products derived
-// from this software without specific prior written permission.
-//
+// from this software without specific prior written permission.
+//
// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
#include "IlmBaseConfig.h"
#if HAVE_PTHREAD
+#ifdef ILMBASE_FORCE_CXX03
#include "IlmThread.h"
#include "Iex.h"
typedef void * (* Start) (void *);
}
-namespace IlmThread {
+ILMTHREAD_INTERNAL_NAMESPACE_SOURCE_ENTER
bool
Thread::start ()
{
if (int error = ::pthread_create (&_thread, 0, Start (threadLoop), this))
- Iex::throwErrnoExc ("Cannot create new thread (%T).", error);
+ IEX_NAMESPACE::throwErrnoExc ("Cannot create new thread (%T).", error);
}
-} // namespace IlmThread
+ILMTHREAD_INTERNAL_NAMESPACE_SOURCE_EXIT
#endif
+#endif
///////////////////////////////////////////////////////////////////////////
//
-// Copyright (c) 2005, Industrial Light & Magic, a division of Lucas
+// Copyright (c) 2005-2012, Industrial Light & Magic, a division of Lucas
// Digital Ltd. LLC
-//
+//
// All rights reserved.
-//
+//
// Redistribution and use in source and binary forms, with or without
// modification, are permitted provided that the following conditions are
// met:
// distribution.
// * Neither the name of Industrial Light & Magic nor the names of
// its contributors may be used to endorse or promote products derived
-// from this software without specific prior written permission.
-//
+// from this software without specific prior written permission.
+//
// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
#if !defined (_WIN32) && !(_WIN64) && !(HAVE_PTHREAD)
#include "IlmThreadSemaphore.h"
-namespace IlmThread {
+ILMTHREAD_INTERNAL_NAMESPACE_SOURCE_ENTER
Semaphore::Semaphore (unsigned int value) {}
int Semaphore::value () const {return 0;}
-} // namespace IlmThread
+ILMTHREAD_INTERNAL_NAMESPACE_SOURCE_EXIT
#endif
///////////////////////////////////////////////////////////////////////////
//
-// Copyright (c) 2005, Industrial Light & Magic, a division of Lucas
+// Copyright (c) 2005-2012, Industrial Light & Magic, a division of Lucas
// Digital Ltd. LLC
-//
+//
// All rights reserved.
-//
+//
// Redistribution and use in source and binary forms, with or without
// modification, are permitted provided that the following conditions are
// met:
// distribution.
// * Neither the name of Industrial Light & Magic nor the names of
// its contributors may be used to endorse or promote products derived
-// from this software without specific prior written permission.
-//
+// from this software without specific prior written permission.
+//
// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
//-----------------------------------------------------------------------------
#include "IlmBaseConfig.h"
+#include "IlmThreadExport.h"
+#include "IlmThreadNamespace.h"
#if defined _WIN32 || defined _WIN64
- #ifdef NOMINMAX
- #undef NOMINMAX
- #endif
- #define NOMINMAX
- #include <windows.h>
-#elif HAVE_PTHREAD && !HAVE_POSIX_SEMAPHORES
- #include <pthread.h>
-#elif HAVE_PTHREAD && HAVE_POSIX_SEMAPHORES
- #include <semaphore.h>
+# ifdef NOMINMAX
+# undef NOMINMAX
+# endif
+# define NOMINMAX
+# include <windows.h>
+#elif HAVE_POSIX_SEMAPHORES
+# include <semaphore.h>
+#else
+# ifdef ILMBASE_FORCE_CXX03
+# if HAVE_PTHREAD
+# include <pthread.h>
+# endif
+# else
+# include <mutex>
+# include <condition_variable>
+# endif
#endif
-namespace IlmThread {
+ILMTHREAD_INTERNAL_NAMESPACE_HEADER_ENTER
-class Semaphore
+class ILMTHREAD_EXPORT Semaphore
{
public:
private:
- #if defined _WIN32 || defined _WIN64
-
- mutable HANDLE _semaphore;
-
- #elif HAVE_PTHREAD && !HAVE_POSIX_SEMAPHORES
-
- //
- // If the platform has Posix threads but no semapohores,
- // then we implement them ourselves using condition variables
- //
-
- struct sema_t
- {
- unsigned int count;
- unsigned long numWaiting;
- pthread_mutex_t mutex;
- pthread_cond_t nonZero;
- };
-
- mutable sema_t _semaphore;
-
- #elif HAVE_PTHREAD && HAVE_POSIX_SEMAPHORES
-
- mutable sem_t _semaphore;
+#if defined _WIN32 || defined _WIN64
- #endif
+ mutable HANDLE _semaphore;
+
+#elif HAVE_POSIX_SEMAPHORES
+
+ mutable sem_t _semaphore;
+
+#else
+ //
+ // If the platform has Posix threads but no semapohores,
+ // then we implement them ourselves using condition variables
+ //
+
+ struct sema_t
+ {
+ unsigned int count;
+ unsigned long numWaiting;
+# if ILMBASE_FORCE_CXX03
+# if HAVE_PTHREAD
+ pthread_mutex_t mutex;
+ pthread_cond_t nonZero;
+# else
+# error unhandled legacy setup
+# endif
+# else
+ std::mutex mutex;
+ std::condition_variable nonZero;
+# endif
+ };
+
+ mutable sema_t _semaphore;
+
+#endif
void operator = (const Semaphore& s); // not implemented
Semaphore (const Semaphore& s); // not implemented
};
-} // namespace IlmThread
+ILMTHREAD_INTERNAL_NAMESPACE_HEADER_EXIT
-#endif
+#endif // INCLUDED_ILM_THREAD_SEMAPHORE_H
///////////////////////////////////////////////////////////////////////////
//
-// Copyright (c) 2005, Industrial Light & Magic, a division of Lucas
+// Copyright (c) 2005-2012, Industrial Light & Magic, a division of Lucas
// Digital Ltd. LLC
-//
+//
// All rights reserved.
-//
+//
// Redistribution and use in source and binary forms, with or without
// modification, are permitted provided that the following conditions are
// met:
// distribution.
// * Neither the name of Industrial Light & Magic nor the names of
// its contributors may be used to endorse or promote products derived
-// from this software without specific prior written permission.
-//
+// from this software without specific prior written permission.
+//
// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
#include "IlmThreadSemaphore.h"
#include "Iex.h"
#include <assert.h>
+#include <errno.h>
-namespace IlmThread {
+ILMTHREAD_INTERNAL_NAMESPACE_SOURCE_ENTER
Semaphore::Semaphore (unsigned int value)
{
if (::sem_init (&_semaphore, 0, value))
- Iex::throwErrnoExc ("Cannot initialize semaphore (%T).");
+ IEX_NAMESPACE::throwErrnoExc ("Cannot initialize semaphore (%T).");
}
void
Semaphore::wait ()
{
- ::sem_wait (&_semaphore);
+ while( ::sem_wait( &_semaphore ) == -1 && errno == EINTR )
+ {
+ }
}
Semaphore::post ()
{
if (::sem_post (&_semaphore))
- Iex::throwErrnoExc ("Post operation on semaphore failed (%T).");
+ IEX_NAMESPACE::throwErrnoExc ("Post operation on semaphore failed (%T).");
}
int value;
if (::sem_getvalue (&_semaphore, &value))
- Iex::throwErrnoExc ("Cannot read semaphore value (%T).");
+ IEX_NAMESPACE::throwErrnoExc ("Cannot read semaphore value (%T).");
return value;
}
-} // namespace IlmThread
+ILMTHREAD_INTERNAL_NAMESPACE_SOURCE_EXIT
#endif
///////////////////////////////////////////////////////////////////////////
//
-// Copyright (c) 2005, Industrial Light & Magic, a division of Lucas
+// Copyright (c) 2005-2012, Industrial Light & Magic, a division of Lucas
// Digital Ltd. LLC
-//
+//
// All rights reserved.
-//
+//
// Redistribution and use in source and binary forms, with or without
// modification, are permitted provided that the following conditions are
// met:
// distribution.
// * Neither the name of Industrial Light & Magic nor the names of
// its contributors may be used to endorse or promote products derived
-// from this software without specific prior written permission.
-//
+// from this software without specific prior written permission.
+//
// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
#include "IlmBaseConfig.h"
-#if HAVE_PTHREAD && !HAVE_POSIX_SEMAPHORES
+#if (!HAVE_POSIX_SEMAPHORES) && !defined (_WIN32) && ! defined (_WIN64)
#include "IlmThreadSemaphore.h"
#include "Iex.h"
#include <assert.h>
-namespace IlmThread {
-
+ILMTHREAD_INTERNAL_NAMESPACE_SOURCE_ENTER
+#if ILMBASE_FORCE_CXX03 && HAVE_PTHREAD
Semaphore::Semaphore (unsigned int value)
{
if (int error = ::pthread_mutex_init (&_semaphore.mutex, 0))
- Iex::throwErrnoExc ("Cannot initialize mutex (%T).", error);
+ IEX_NAMESPACE::throwErrnoExc ("Cannot initialize mutex (%T).", error);
if (int error = ::pthread_cond_init (&_semaphore.nonZero, 0))
- Iex::throwErrnoExc ("Cannot initialize condition variable (%T).",
+ IEX_NAMESPACE::throwErrnoExc ("Cannot initialize condition variable (%T).",
error);
_semaphore.count = value;
{
if (int error = ::pthread_cond_wait (&_semaphore.nonZero,
&_semaphore.mutex))
- {
+ {
::pthread_mutex_unlock (&_semaphore.mutex);
- Iex::throwErrnoExc ("Cannot wait on condition variable (%T).",
- error);
- }
+ IEX_NAMESPACE::throwErrnoExc ("Cannot wait on condition variable (%T).",
+ error);
+ }
}
_semaphore.numWaiting--;
Semaphore::tryWait ()
{
::pthread_mutex_lock (&_semaphore.mutex);
-
+
if (_semaphore.count == 0)
{
::pthread_mutex_unlock (&_semaphore.mutex);
if (_semaphore.numWaiting > 0)
{
- if (int error = ::pthread_cond_signal (&_semaphore.nonZero))
- {
+ int error;
+ if (_semaphore.numWaiting > 1 && _semaphore.count > 1)
+ {
+ error = ::pthread_cond_broadcast (&_semaphore.nonZero);
+ }
+ else
+ {
+ error = ::pthread_cond_signal (&_semaphore.nonZero);
+ }
+ if (error)
+ {
::pthread_mutex_unlock (&_semaphore.mutex);
- Iex::throwErrnoExc ("Cannot signal condition variable (%T).",
+ IEX_NAMESPACE::throwErrnoExc ("Cannot signal condition variable (%T).",
error);
- }
+ }
}
_semaphore.count++;
::pthread_mutex_unlock (&_semaphore.mutex);
return value;
}
+#else
+Semaphore::Semaphore (unsigned int value)
+{
+ _semaphore.count = value;
+ _semaphore.numWaiting = 0;
+}
+
+
+Semaphore::~Semaphore ()
+{
+}
+
+
+void
+Semaphore::wait ()
+{
+ std::unique_lock<std::mutex> lk(_semaphore.mutex);
+
+ _semaphore.numWaiting++;
+
+ while (_semaphore.count == 0)
+ _semaphore.nonZero.wait (lk);
+
+ _semaphore.numWaiting--;
+ _semaphore.count--;
+}
+
+
+bool
+Semaphore::tryWait ()
+{
+ std::lock_guard<std::mutex> lk(_semaphore.mutex);
+
+ if (_semaphore.count == 0)
+ return false;
+
+ _semaphore.count--;
+ return true;
+}
+
+
+void
+Semaphore::post ()
+{
+ std::lock_guard<std::mutex> lk(_semaphore.mutex);
+
+ _semaphore.count++;
+ if (_semaphore.numWaiting > 0)
+ {
+ if (_semaphore.count > 1)
+ _semaphore.nonZero.notify_all();
+ else
+ _semaphore.nonZero.notify_one();
+ }
+}
+
+int
+Semaphore::value () const
+{
+ std::lock_guard<std::mutex> lk(_semaphore.mutex);
+ return _semaphore.count;
+}
+#endif
-} // namespace IlmThread
+ILMTHREAD_INTERNAL_NAMESPACE_SOURCE_EXIT
#endif
///////////////////////////////////////////////////////////////////////////
//
-// Copyright (c) 2005, Industrial Light & Magic, a division of Lucas
+// Copyright (c) 2005-2012, Industrial Light & Magic, a division of Lucas
// Digital Ltd. LLC
-//
+//
// All rights reserved.
-//
+//
// Redistribution and use in source and binary forms, with or without
// modification, are permitted provided that the following conditions are
// met:
// distribution.
// * Neither the name of Industrial Light & Magic nor the names of
// its contributors may be used to endorse or promote products derived
-// from this software without specific prior written permission.
-//
+// from this software without specific prior written permission.
+//
// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
#include <assert.h>
#include <iostream>
-namespace IlmThread {
+ILMTHREAD_INTERNAL_NAMESPACE_SOURCE_ENTER
-using namespace Iex;
+using namespace IEX_NAMESPACE;
namespace {
std::string message;
//
- // Call FormatMessage() to allow for message
+ // Call FormatMessage() to allow for message
// text to be acquired from the system.
//
if (bufferLength = FormatMessageA (FORMAT_MESSAGE_ALLOCATE_BUFFER |
- FORMAT_MESSAGE_IGNORE_INSERTS |
- FORMAT_MESSAGE_FROM_SYSTEM,
- 0,
- GetLastError (),
- MAKELANGID (LANG_NEUTRAL,
- SUBLANG_DEFAULT),
- (LPSTR) &messageBuffer,
- 0,
- NULL))
+ FORMAT_MESSAGE_IGNORE_INSERTS |
+ FORMAT_MESSAGE_FROM_SYSTEM,
+ 0,
+ GetLastError (),
+ MAKELANGID (LANG_NEUTRAL,
+ SUBLANG_DEFAULT),
+ (LPSTR) &messageBuffer,
+ 0,
+ NULL))
{
- message = messageBuffer;
+ message = messageBuffer;
LocalFree (messageBuffer);
}
{
if ((_semaphore = ::CreateSemaphore (0, value, 0x7fffffff, 0)) == 0)
{
- THROW (LogicExc, "Could not create semaphore "
- "(" << errorString() << ").");
+ THROW (LogicExc, "Could not create semaphore "
+ "(" << errorString() << ").");
}
}
{
if (::WaitForSingleObject (_semaphore, INFINITE) != WAIT_OBJECT_0)
{
- THROW (LogicExc, "Could not wait on semaphore "
- "(" << errorString() << ").");
+ THROW (LogicExc, "Could not wait on semaphore "
+ "(" << errorString() << ").");
}
}
{
if (!::ReleaseSemaphore (_semaphore, 1, 0))
{
- THROW (LogicExc, "Could not post on semaphore "
- "(" << errorString() << ").");
+ THROW (LogicExc, "Could not post on semaphore "
+ "(" << errorString() << ").");
}
}
if (!::ReleaseSemaphore (_semaphore, 0, &v) || v < 0)
{
- THROW (LogicExc, "Could not get value of semaphore "
- "(" << errorString () << ").");
+ THROW (LogicExc, "Could not get value of semaphore "
+ "(" << errorString () << ").");
}
return v;
}
-} // namespace IlmThread
+
+ILMTHREAD_INTERNAL_NAMESPACE_SOURCE_EXIT
///////////////////////////////////////////////////////////////////////////
//
-// Copyright (c) 2005, Industrial Light & Magic, a division of Lucas
+// Copyright (c) 2005-2012, Industrial Light & Magic, a division of Lucas
// Digital Ltd. LLC
-//
+//
// All rights reserved.
-//
+//
// Redistribution and use in source and binary forms, with or without
// modification, are permitted provided that the following conditions are
// met:
// distribution.
// * Neither the name of Industrial Light & Magic nor the names of
// its contributors may be used to endorse or promote products derived
-// from this software without specific prior written permission.
-//
+// from this software without specific prior written permission.
+//
// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
//-----------------------------------------------------------------------------
+#include "IlmBaseConfig.h"
+
+#ifdef ILMBASE_FORCE_CXX03
+
#include "IlmThread.h"
#include "Iex.h"
#include <iostream>
#include <assert.h>
-namespace IlmThread {
+ILMTHREAD_INTERNAL_NAMESPACE_SOURCE_ENTER
bool
_thread = (HANDLE)::_beginthreadex (0, 0, &threadLoop, this, 0, &id);
if (_thread == 0)
- Iex::throwErrnoExc ("Cannot create new thread (%T).");
+ IEX_NAMESPACE::throwErrnoExc ("Cannot create new thread (%T).");
}
-} // namespace IlmThread
+ILMTHREAD_INTERNAL_NAMESPACE_SOURCE_EXIT
+
+#endif
--- /dev/null
+///////////////////////////////////////////////////////////////////////////
+//
+// Copyright (c) 2004, Industrial Light & Magic, a division of Lucas
+// Digital Ltd. LLC
+//
+// All rights reserved.
+//
+// Redistribution and use in source and binary forms, with or without
+// modification, are permitted provided that the following conditions are
+// met:
+// * Redistributions of source code must retain the above copyright
+// notice, this list of conditions and the following disclaimer.
+// * Redistributions in binary form must reproduce the above
+// copyright notice, this list of conditions and the following disclaimer
+// in the documentation and/or other materials provided with the
+// distribution.
+// * Neither the name of Industrial Light & Magic nor the names of
+// its contributors may be used to endorse or promote products derived
+// from this software without specific prior written permission.
+//
+// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+//
+///////////////////////////////////////////////////////////////////////////
+
+#include "ImathBox.h"
+
+// this file is necessary for template instantiation on windows
///////////////////////////////////////////////////////////////////////////
//
-// Copyright (c) 2004, Industrial Light & Magic, a division of Lucas
+// Copyright (c) 2004-2012, Industrial Light & Magic, a division of Lucas
// Digital Ltd. LLC
-//
+//
// All rights reserved.
-//
+//
// Redistribution and use in source and binary forms, with or without
// modification, are permitted provided that the following conditions are
// met:
// distribution.
// * Neither the name of Industrial Light & Magic nor the names of
// its contributors may be used to endorse or promote products derived
-// from this software without specific prior written permission.
-//
+// from this software without specific prior written permission.
+//
// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
// class Imath::Box<class T>
// --------------------------------
//
-// This class imposes the following requirements on its
+// This class imposes the following requirements on its
// parameter class:
-//
+//
// 1) The class T must implement these operators:
-// + - < > <= >= =
-// with the signature (T,T) and the expected
-// return values for a numeric type.
+// + - < > <= >= =
+// with the signature (T,T) and the expected
+// return values for a numeric type.
//
// 2) The class T must implement operator=
// with the signature (T,float and/or double)
//-------------------------------------------------------------------
#include "ImathVec.h"
+#include "ImathNamespace.h"
-namespace Imath {
+IMATH_INTERNAL_NAMESPACE_HEADER_ENTER
-template <class T>
+template <class T>
class Box
{
public:
// Constructors - an "empty" box is created by default
//-----------------------------------------------------
- Box ();
+ Box ();
Box (const T &point);
Box (const T &minT, const T &maxT);
//--------------------
// Operators: ==, !=
//--------------------
-
+
bool operator == (const Box<T> &src) const;
bool operator != (const Box<T> &src) const;
void makeEmpty ();
void extendBy (const T &point);
void extendBy (const Box<T> &box);
- void makeInfinite ();
+ void makeInfinite ();
//---------------------------------------------------
// Query functions - these compute results each time
{
for (unsigned int i = 0; i < min.dimensions(); i++)
{
- if (point[i] < min[i])
- min[i] = point[i];
+ if (point[i] < min[i])
+ min[i] = point[i];
- if (point[i] > max[i])
- max[i] = point[i];
+ if (point[i] > max[i])
+ max[i] = point[i];
}
}
{
for (unsigned int i = 0; i < min.dimensions(); i++)
{
- if (box.min[i] < min[i])
- min[i] = box.min[i];
+ if (box.min[i] < min[i])
+ min[i] = box.min[i];
- if (box.max[i] > max[i])
- max[i] = box.max[i];
+ if (box.max[i] > max[i])
+ max[i] = box.max[i];
}
}
for (unsigned int i = 0; i < min.dimensions(); i++)
{
if (point[i] < min[i] || point[i] > max[i])
- return false;
+ return false;
}
return true;
for (unsigned int i = 0; i < min.dimensions(); i++)
{
if (box.max[i] < min[i] || box.min[i] > max[i])
- return false;
+ return false;
}
return true;
}
-template <class T>
+template <class T>
inline T
-Box<T>::size() const
-{
+Box<T>::size() const
+{
if (isEmpty())
- return T (0);
+ return T (0);
return max - min;
}
-template <class T>
+template <class T>
inline T
-Box<T>::center() const
-{
+Box<T>::center() const
+{
return (max + min) / 2;
}
for (unsigned int i = 0; i < min.dimensions(); i++)
{
if (max[i] < min[i])
- return true;
+ return true;
}
return false;
for (unsigned int i = 0; i < min.dimensions(); i++)
{
if (min[i] != T::baseTypeMin() || max[i] != T::baseTypeMax())
- return false;
+ return false;
}
return true;
for (unsigned int i = 0; i < min.dimensions(); i++)
{
if (max[i] <= min[i])
- return false;
+ return false;
}
return true;
for (unsigned int i = 1; i < min.dimensions(); i++)
{
- if (s[i] > s[major])
- major = i;
+ if (s[i] > s[major])
+ major = i;
}
return major;
// Constructors - an "empty" box is created by default
//-----------------------------------------------------
- Box();
+ Box();
Box (const Vec2<T> &point);
Box (const Vec2<T> &minT, const Vec2<T> &maxT);
}
-template <class T>
+template <class T>
inline Vec2<T>
-Box<Vec2<T> >::size() const
-{
+Box<Vec2<T> >::size() const
+{
if (isEmpty())
return Vec2<T> (0);
}
-template <class T>
+template <class T>
inline Vec2<T>
-Box<Vec2<T> >::center() const
-{
+Box<Vec2<T> >::center() const
+{
return (max + min) / 2;
}
if (min[0] != limits<T>::min() || max[0] != limits<T>::max() ||
min[1] != limits<T>::min() || max[1] != limits<T>::max())
return false;
-
+
return true;
}
// Constructors - an "empty" box is created by default
//-----------------------------------------------------
- Box();
+ Box();
Box (const Vec3<T> &point);
Box (const Vec3<T> &minT, const Vec3<T> &maxT);
}
-template <class T>
+template <class T>
inline Vec3<T>
-Box<Vec3<T> >::size() const
-{
+Box<Vec3<T> >::size() const
+{
if (isEmpty())
return Vec3<T> (0);
}
-template <class T>
+template <class T>
inline Vec3<T>
-Box<Vec3<T> >::center() const
-{
+Box<Vec3<T> >::center() const
+{
return (max + min) / 2;
}
min[1] != limits<T>::min() || max[1] != limits<T>::max() ||
min[2] != limits<T>::min() || max[2] != limits<T>::max())
return false;
-
+
return true;
}
}
+IMATH_INTERNAL_NAMESPACE_HEADER_EXIT
-
-} // namespace Imath
-
-#endif
+#endif // INCLUDED_IMATHBOX_H
///////////////////////////////////////////////////////////////////////////
//
-// Copyright (c) 2002-2010, Industrial Light & Magic, a division of Lucas
+// Copyright (c) 2002-2012, Industrial Light & Magic, a division of Lucas
// Digital Ltd. LLC
-//
+//
// All rights reserved.
-//
+//
// Redistribution and use in source and binary forms, with or without
// modification, are permitted provided that the following conditions are
// met:
// distribution.
// * Neither the name of Industrial Light & Magic nor the names of
// its contributors may be used to endorse or promote products derived
-// from this software without specific prior written permission.
-//
+// from this software without specific prior written permission.
+//
// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
// Vec3<T> &enterPoint,
// Vec3<T> &exitPoint)
//
-// bool intersects(const Box<Vec3<T>> &box,
-// const Line3<T> &ray,
+// bool intersects(const Box<Vec3<T>> &box,
+// const Line3<T> &ray,
// Vec3<T> intersectionPoint)
//
// bool intersects(const Box<Vec3<T>> &box, const Line3<T> &ray)
#include "ImathMatrix.h"
#include "ImathLineAlgo.h"
#include "ImathPlane.h"
+#include "ImathNamespace.h"
-namespace Imath {
+IMATH_INTERNAL_NAMESPACE_HEADER_ENTER
template <class T>
for (int i = 0; i < int (box.min.dimensions()); i++)
{
- if (p[i] < box.min[i])
- q[i] = box.min[i];
- else if (p[i] > box.max[i])
- q[i] = box.max[i];
- else
- q[i] = p[i];
+ if (p[i] < box.min[i])
+ q[i] = box.min[i];
+ else if (p[i] > box.max[i])
+ q[i] = box.max[i];
+ else
+ q[i] = p[i];
}
return q;
//
if (box.isEmpty())
- return p;
+ return p;
Vec3<T> q = closestPointInBox (p, box);
if (q == p)
{
- Vec3<T> d1 = p - box.min;
- Vec3<T> d2 = box.max - p;
+ Vec3<T> d1 = p - box.min;
+ Vec3<T> d2 = box.max - p;
- Vec3<T> d ((d1.x < d2.x)? d1.x: d2.x,
- (d1.y < d2.y)? d1.y: d2.y,
- (d1.z < d2.z)? d1.z: d2.z);
+ Vec3<T> d ((d1.x < d2.x)? d1.x: d2.x,
+ (d1.y < d2.y)? d1.y: d2.y,
+ (d1.z < d2.z)? d1.z: d2.z);
- if (d.x < d.y && d.x < d.z)
- {
- q.x = (d1.x < d2.x)? box.min.x: box.max.x;
- }
- else if (d.y < d.z)
- {
- q.y = (d1.y < d2.y)? box.min.y: box.max.y;
- }
- else
- {
- q.z = (d1.z < d2.z)? box.min.z: box.max.z;
- }
+ if (d.x < d.y && d.x < d.z)
+ {
+ q.x = (d1.x < d2.x)? box.min.x: box.max.x;
+ }
+ else if (d.y < d.z)
+ {
+ q.y = (d1.y < d2.y)? box.min.y: box.max.y;
+ }
+ else
+ {
+ q.z = (d1.z < d2.z)? box.min.z: box.max.z;
+ }
}
return q;
//
if (box.isEmpty() || box.isInfinite())
- return box;
+ return box;
//
// If the last column of m is (0 0 0 1) then m is an affine
if (m[0][3] == 0 && m[1][3] == 0 && m[2][3] == 0 && m[3][3] == 1)
{
- Box< Vec3<S> > newBox;
+ Box< Vec3<S> > newBox;
- for (int i = 0; i < 3; i++)
+ for (int i = 0; i < 3; i++)
{
- newBox.min[i] = newBox.max[i] = (S) m[3][i];
+ newBox.min[i] = newBox.max[i] = (S) m[3][i];
- for (int j = 0; j < 3; j++)
+ for (int j = 0; j < 3; j++)
{
- S a, b;
+ S a, b;
- a = (S) m[j][i] * box.min[j];
- b = (S) m[j][i] * box.max[j];
+ a = (S) m[j][i] * box.min[j];
+ b = (S) m[j][i] * box.max[j];
- if (a < b)
+ if (a < b)
{
- newBox.min[i] += a;
- newBox.max[i] += b;
- }
- else
+ newBox.min[i] += a;
+ newBox.max[i] += b;
+ }
+ else
{
- newBox.min[i] += b;
- newBox.max[i] += a;
- }
- }
- }
+ newBox.min[i] += b;
+ newBox.max[i] += a;
+ }
+ }
+ }
- return newBox;
+ return newBox;
}
//
Box< Vec3<S> > newBox;
- for (int i = 0; i < 8; i++)
- newBox.extendBy (points[i] * m);
+ for (int i = 0; i < 8; i++)
+ newBox.extendBy (points[i] * m);
return newBox;
}
if (box.isEmpty() || box.isInfinite())
{
- return;
+ return;
}
//
if (m[0][3] == 0 && m[1][3] == 0 && m[2][3] == 0 && m[3][3] == 1)
{
- for (int i = 0; i < 3; i++)
+ for (int i = 0; i < 3; i++)
{
- result.min[i] = result.max[i] = (S) m[3][i];
+ result.min[i] = result.max[i] = (S) m[3][i];
- for (int j = 0; j < 3; j++)
+ for (int j = 0; j < 3; j++)
{
- S a, b;
+ S a, b;
- a = (S) m[j][i] * box.min[j];
- b = (S) m[j][i] * box.max[j];
+ a = (S) m[j][i] * box.min[j];
+ b = (S) m[j][i] * box.max[j];
- if (a < b)
+ if (a < b)
{
- result.min[i] += a;
- result.max[i] += b;
- }
- else
+ result.min[i] += a;
+ result.max[i] += b;
+ }
+ else
{
- result.min[i] += b;
- result.max[i] += a;
- }
- }
- }
+ result.min[i] += b;
+ result.max[i] += a;
+ }
+ }
+ }
- return;
+ return;
}
//
points[0][2] = points[2][2] = points[4][2] = points[6][2] = box.min[2];
points[1][2] = points[3][2] = points[5][2] = points[7][2] = box.max[2];
- for (int i = 0; i < 8; i++)
- result.extendBy (points[i] * m);
+ for (int i = 0; i < 8; i++)
+ result.extendBy (points[i] * m);
}
if (box.isEmpty() || box.isInfinite())
{
- //
- // A transformed empty or infinite box is still empty or infinite
- //
+ //
+ // A transformed empty or infinite box is still empty or infinite
+ //
- return box;
+ return box;
}
Box< Vec3<S> > newBox;
- for (int i = 0; i < 3; i++)
+ for (int i = 0; i < 3; i++)
{
- newBox.min[i] = newBox.max[i] = (S) m[3][i];
+ newBox.min[i] = newBox.max[i] = (S) m[3][i];
- for (int j = 0; j < 3; j++)
- {
- S a, b;
+ for (int j = 0; j < 3; j++)
+ {
+ S a, b;
- a = (S) m[j][i] * box.min[j];
- b = (S) m[j][i] * box.max[j];
+ a = (S) m[j][i] * box.min[j];
+ b = (S) m[j][i] * box.max[j];
- if (a < b)
- {
- newBox.min[i] += a;
- newBox.max[i] += b;
- }
- else
- {
- newBox.min[i] += b;
- newBox.max[i] += a;
- }
- }
+ if (a < b)
+ {
+ newBox.min[i] += a;
+ newBox.max[i] += b;
+ }
+ else
+ {
+ newBox.min[i] += b;
+ newBox.max[i] += a;
+ }
+ }
}
return newBox;
if (box.isEmpty())
{
- //
- // A transformed empty box is still empty
- //
+ //
+ // A transformed empty box is still empty
+ //
result.makeEmpty();
- return;
+ return;
}
if (box.isInfinite())
{
- //
- // A transformed infinite box is still infinite
- //
+ //
+ // A transformed infinite box is still infinite
+ //
result.makeInfinite();
- return;
+ return;
}
- for (int i = 0; i < 3; i++)
+ for (int i = 0; i < 3; i++)
{
- result.min[i] = result.max[i] = (S) m[3][i];
+ result.min[i] = result.max[i] = (S) m[3][i];
- for (int j = 0; j < 3; j++)
- {
- S a, b;
+ for (int j = 0; j < 3; j++)
+ {
+ S a, b;
- a = (S) m[j][i] * box.min[j];
- b = (S) m[j][i] * box.max[j];
+ a = (S) m[j][i] * box.min[j];
+ b = (S) m[j][i] * box.max[j];
- if (a < b)
- {
- result.min[i] += a;
- result.max[i] += b;
- }
- else
- {
- result.min[i] += b;
- result.max[i] += a;
- }
- }
+ if (a < b)
+ {
+ result.min[i] += a;
+ result.max[i] += b;
+ }
+ else
+ {
+ result.min[i] += b;
+ result.max[i] += a;
+ }
+ }
}
}
template <class T>
bool
findEntryAndExitPoints (const Line3<T> &r,
- const Box<Vec3<T> > &b,
- Vec3<T> &entry,
- Vec3<T> &exit)
+ const Box<Vec3<T> > &b,
+ Vec3<T> &entry,
+ Vec3<T> &exit)
{
//
// Compute the points where a ray, r, enters and exits a box, b:
if (b.isEmpty())
{
- //
- // No ray intersects an empty box
- //
+ //
+ // No ray intersects an empty box
+ //
- return false;
+ return false;
}
//
if (r.dir.x >= 0)
{
- T d1 = b.max.x - r.pos.x;
- T d2 = b.min.x - r.pos.x;
-
- if (r.dir.x > 1 ||
- (abs (d1) < TMAX * r.dir.x &&
- abs (d2) < TMAX * r.dir.x))
- {
- T t1 = d1 / r.dir.x;
- T t2 = d2 / r.dir.x;
-
- if (tBackMin > t1)
- {
- tBackMin = t1;
-
- exit.x = b.max.x;
- exit.y = clamp (r.pos.y + t1 * r.dir.y, b.min.y, b.max.y);
- exit.z = clamp (r.pos.z + t1 * r.dir.z, b.min.z, b.max.z);
- }
-
- if (tFrontMax < t2)
- {
- tFrontMax = t2;
-
- entry.x = b.min.x;
- entry.y = clamp (r.pos.y + t2 * r.dir.y, b.min.y, b.max.y);
- entry.z = clamp (r.pos.z + t2 * r.dir.z, b.min.z, b.max.z);
- }
- }
- else if (r.pos.x < b.min.x || r.pos.x > b.max.x)
- {
- return false;
- }
+ T d1 = b.max.x - r.pos.x;
+ T d2 = b.min.x - r.pos.x;
+
+ if (r.dir.x > 1 ||
+ (abs (d1) < TMAX * r.dir.x &&
+ abs (d2) < TMAX * r.dir.x))
+ {
+ T t1 = d1 / r.dir.x;
+ T t2 = d2 / r.dir.x;
+
+ if (tBackMin > t1)
+ {
+ tBackMin = t1;
+
+ exit.x = b.max.x;
+ exit.y = clamp (r.pos.y + t1 * r.dir.y, b.min.y, b.max.y);
+ exit.z = clamp (r.pos.z + t1 * r.dir.z, b.min.z, b.max.z);
+ }
+
+ if (tFrontMax < t2)
+ {
+ tFrontMax = t2;
+
+ entry.x = b.min.x;
+ entry.y = clamp (r.pos.y + t2 * r.dir.y, b.min.y, b.max.y);
+ entry.z = clamp (r.pos.z + t2 * r.dir.z, b.min.z, b.max.z);
+ }
+ }
+ else if (r.pos.x < b.min.x || r.pos.x > b.max.x)
+ {
+ return false;
+ }
}
else // r.dir.x < 0
{
- T d1 = b.min.x - r.pos.x;
- T d2 = b.max.x - r.pos.x;
+ T d1 = b.min.x - r.pos.x;
+ T d2 = b.max.x - r.pos.x;
- if (r.dir.x < -1 ||
- (abs (d1) < -TMAX * r.dir.x &&
- abs (d2) < -TMAX * r.dir.x))
- {
- T t1 = d1 / r.dir.x;
- T t2 = d2 / r.dir.x;
+ if (r.dir.x < -1 ||
+ (abs (d1) < -TMAX * r.dir.x &&
+ abs (d2) < -TMAX * r.dir.x))
+ {
+ T t1 = d1 / r.dir.x;
+ T t2 = d2 / r.dir.x;
- if (tBackMin > t1)
- {
- tBackMin = t1;
+ if (tBackMin > t1)
+ {
+ tBackMin = t1;
- exit.x = b.min.x;
- exit.y = clamp (r.pos.y + t1 * r.dir.y, b.min.y, b.max.y);
- exit.z = clamp (r.pos.z + t1 * r.dir.z, b.min.z, b.max.z);
- }
+ exit.x = b.min.x;
+ exit.y = clamp (r.pos.y + t1 * r.dir.y, b.min.y, b.max.y);
+ exit.z = clamp (r.pos.z + t1 * r.dir.z, b.min.z, b.max.z);
+ }
- if (tFrontMax < t2)
- {
- tFrontMax = t2;
+ if (tFrontMax < t2)
+ {
+ tFrontMax = t2;
- entry.x = b.max.x;
- entry.y = clamp (r.pos.y + t2 * r.dir.y, b.min.y, b.max.y);
- entry.z = clamp (r.pos.z + t2 * r.dir.z, b.min.z, b.max.z);
- }
- }
- else if (r.pos.x < b.min.x || r.pos.x > b.max.x)
- {
- return false;
- }
+ entry.x = b.max.x;
+ entry.y = clamp (r.pos.y + t2 * r.dir.y, b.min.y, b.max.y);
+ entry.z = clamp (r.pos.z + t2 * r.dir.z, b.min.z, b.max.z);
+ }
+ }
+ else if (r.pos.x < b.min.x || r.pos.x > b.max.x)
+ {
+ return false;
+ }
}
//
if (r.dir.y >= 0)
{
- T d1 = b.max.y - r.pos.y;
- T d2 = b.min.y - r.pos.y;
-
- if (r.dir.y > 1 ||
- (abs (d1) < TMAX * r.dir.y &&
- abs (d2) < TMAX * r.dir.y))
- {
- T t1 = d1 / r.dir.y;
- T t2 = d2 / r.dir.y;
-
- if (tBackMin > t1)
- {
- tBackMin = t1;
-
- exit.x = clamp (r.pos.x + t1 * r.dir.x, b.min.x, b.max.x);
- exit.y = b.max.y;
- exit.z = clamp (r.pos.z + t1 * r.dir.z, b.min.z, b.max.z);
- }
-
- if (tFrontMax < t2)
- {
- tFrontMax = t2;
-
- entry.x = clamp (r.pos.x + t2 * r.dir.x, b.min.x, b.max.x);
- entry.y = b.min.y;
- entry.z = clamp (r.pos.z + t2 * r.dir.z, b.min.z, b.max.z);
- }
- }
- else if (r.pos.y < b.min.y || r.pos.y > b.max.y)
- {
- return false;
- }
+ T d1 = b.max.y - r.pos.y;
+ T d2 = b.min.y - r.pos.y;
+
+ if (r.dir.y > 1 ||
+ (abs (d1) < TMAX * r.dir.y &&
+ abs (d2) < TMAX * r.dir.y))
+ {
+ T t1 = d1 / r.dir.y;
+ T t2 = d2 / r.dir.y;
+
+ if (tBackMin > t1)
+ {
+ tBackMin = t1;
+
+ exit.x = clamp (r.pos.x + t1 * r.dir.x, b.min.x, b.max.x);
+ exit.y = b.max.y;
+ exit.z = clamp (r.pos.z + t1 * r.dir.z, b.min.z, b.max.z);
+ }
+
+ if (tFrontMax < t2)
+ {
+ tFrontMax = t2;
+
+ entry.x = clamp (r.pos.x + t2 * r.dir.x, b.min.x, b.max.x);
+ entry.y = b.min.y;
+ entry.z = clamp (r.pos.z + t2 * r.dir.z, b.min.z, b.max.z);
+ }
+ }
+ else if (r.pos.y < b.min.y || r.pos.y > b.max.y)
+ {
+ return false;
+ }
}
else // r.dir.y < 0
{
- T d1 = b.min.y - r.pos.y;
- T d2 = b.max.y - r.pos.y;
+ T d1 = b.min.y - r.pos.y;
+ T d2 = b.max.y - r.pos.y;
- if (r.dir.y < -1 ||
- (abs (d1) < -TMAX * r.dir.y &&
- abs (d2) < -TMAX * r.dir.y))
- {
- T t1 = d1 / r.dir.y;
- T t2 = d2 / r.dir.y;
+ if (r.dir.y < -1 ||
+ (abs (d1) < -TMAX * r.dir.y &&
+ abs (d2) < -TMAX * r.dir.y))
+ {
+ T t1 = d1 / r.dir.y;
+ T t2 = d2 / r.dir.y;
- if (tBackMin > t1)
- {
- tBackMin = t1;
+ if (tBackMin > t1)
+ {
+ tBackMin = t1;
- exit.x = clamp (r.pos.x + t1 * r.dir.x, b.min.x, b.max.x);
- exit.y = b.min.y;
- exit.z = clamp (r.pos.z + t1 * r.dir.z, b.min.z, b.max.z);
- }
+ exit.x = clamp (r.pos.x + t1 * r.dir.x, b.min.x, b.max.x);
+ exit.y = b.min.y;
+ exit.z = clamp (r.pos.z + t1 * r.dir.z, b.min.z, b.max.z);
+ }
- if (tFrontMax < t2)
- {
- tFrontMax = t2;
+ if (tFrontMax < t2)
+ {
+ tFrontMax = t2;
- entry.x = clamp (r.pos.x + t2 * r.dir.x, b.min.x, b.max.x);
- entry.y = b.max.y;
- entry.z = clamp (r.pos.z + t2 * r.dir.z, b.min.z, b.max.z);
- }
- }
- else if (r.pos.y < b.min.y || r.pos.y > b.max.y)
- {
- return false;
- }
+ entry.x = clamp (r.pos.x + t2 * r.dir.x, b.min.x, b.max.x);
+ entry.y = b.max.y;
+ entry.z = clamp (r.pos.z + t2 * r.dir.z, b.min.z, b.max.z);
+ }
+ }
+ else if (r.pos.y < b.min.y || r.pos.y > b.max.y)
+ {
+ return false;
+ }
}
//
if (r.dir.z >= 0)
{
- T d1 = b.max.z - r.pos.z;
- T d2 = b.min.z - r.pos.z;
-
- if (r.dir.z > 1 ||
- (abs (d1) < TMAX * r.dir.z &&
- abs (d2) < TMAX * r.dir.z))
- {
- T t1 = d1 / r.dir.z;
- T t2 = d2 / r.dir.z;
-
- if (tBackMin > t1)
- {
- tBackMin = t1;
-
- exit.x = clamp (r.pos.x + t1 * r.dir.x, b.min.x, b.max.x);
- exit.y = clamp (r.pos.y + t1 * r.dir.y, b.min.y, b.max.y);
- exit.z = b.max.z;
- }
-
- if (tFrontMax < t2)
- {
- tFrontMax = t2;
-
- entry.x = clamp (r.pos.x + t2 * r.dir.x, b.min.x, b.max.x);
- entry.y = clamp (r.pos.y + t2 * r.dir.y, b.min.y, b.max.y);
- entry.z = b.min.z;
- }
- }
- else if (r.pos.z < b.min.z || r.pos.z > b.max.z)
- {
- return false;
- }
+ T d1 = b.max.z - r.pos.z;
+ T d2 = b.min.z - r.pos.z;
+
+ if (r.dir.z > 1 ||
+ (abs (d1) < TMAX * r.dir.z &&
+ abs (d2) < TMAX * r.dir.z))
+ {
+ T t1 = d1 / r.dir.z;
+ T t2 = d2 / r.dir.z;
+
+ if (tBackMin > t1)
+ {
+ tBackMin = t1;
+
+ exit.x = clamp (r.pos.x + t1 * r.dir.x, b.min.x, b.max.x);
+ exit.y = clamp (r.pos.y + t1 * r.dir.y, b.min.y, b.max.y);
+ exit.z = b.max.z;
+ }
+
+ if (tFrontMax < t2)
+ {
+ tFrontMax = t2;
+
+ entry.x = clamp (r.pos.x + t2 * r.dir.x, b.min.x, b.max.x);
+ entry.y = clamp (r.pos.y + t2 * r.dir.y, b.min.y, b.max.y);
+ entry.z = b.min.z;
+ }
+ }
+ else if (r.pos.z < b.min.z || r.pos.z > b.max.z)
+ {
+ return false;
+ }
}
else // r.dir.z < 0
{
- T d1 = b.min.z - r.pos.z;
- T d2 = b.max.z - r.pos.z;
+ T d1 = b.min.z - r.pos.z;
+ T d2 = b.max.z - r.pos.z;
- if (r.dir.z < -1 ||
- (abs (d1) < -TMAX * r.dir.z &&
- abs (d2) < -TMAX * r.dir.z))
- {
- T t1 = d1 / r.dir.z;
- T t2 = d2 / r.dir.z;
+ if (r.dir.z < -1 ||
+ (abs (d1) < -TMAX * r.dir.z &&
+ abs (d2) < -TMAX * r.dir.z))
+ {
+ T t1 = d1 / r.dir.z;
+ T t2 = d2 / r.dir.z;
- if (tBackMin > t1)
- {
- tBackMin = t1;
+ if (tBackMin > t1)
+ {
+ tBackMin = t1;
- exit.x = clamp (r.pos.x + t1 * r.dir.x, b.min.x, b.max.x);
- exit.y = clamp (r.pos.y + t1 * r.dir.y, b.min.y, b.max.y);
- exit.z = b.min.z;
- }
+ exit.x = clamp (r.pos.x + t1 * r.dir.x, b.min.x, b.max.x);
+ exit.y = clamp (r.pos.y + t1 * r.dir.y, b.min.y, b.max.y);
+ exit.z = b.min.z;
+ }
- if (tFrontMax < t2)
- {
- tFrontMax = t2;
+ if (tFrontMax < t2)
+ {
+ tFrontMax = t2;
- entry.x = clamp (r.pos.x + t2 * r.dir.x, b.min.x, b.max.x);
- entry.y = clamp (r.pos.y + t2 * r.dir.y, b.min.y, b.max.y);
- entry.z = b.max.z;
- }
- }
- else if (r.pos.z < b.min.z || r.pos.z > b.max.z)
- {
- return false;
- }
+ entry.x = clamp (r.pos.x + t2 * r.dir.x, b.min.x, b.max.x);
+ entry.y = clamp (r.pos.y + t2 * r.dir.y, b.min.y, b.max.y);
+ entry.z = b.max.z;
+ }
+ }
+ else if (r.pos.z < b.min.z || r.pos.z > b.max.z)
+ {
+ return false;
+ }
}
return tFrontMax <= tBackMin;
if (b.isEmpty())
{
- //
- // No ray intersects an empty box
- //
+ //
+ // No ray intersects an empty box
+ //
- return false;
+ return false;
}
if (b.intersects (r.pos))
{
- //
- // The ray starts inside the box
- //
+ //
+ // The ray starts inside the box
+ //
- ip = r.pos;
- return true;
+ ip = r.pos;
+ return true;
}
//
if (r.dir.x > 0)
{
- if (r.pos.x > b.max.x)
- return false;
+ if (r.pos.x > b.max.x)
+ return false;
- T d = b.max.x - r.pos.x;
+ T d = b.max.x - r.pos.x;
- if (r.dir.x > 1 || d < TMAX * r.dir.x)
- {
- T t = d / r.dir.x;
+ if (r.dir.x > 1 || d < TMAX * r.dir.x)
+ {
+ T t = d / r.dir.x;
- if (tBackMin > t)
- tBackMin = t;
- }
+ if (tBackMin > t)
+ tBackMin = t;
+ }
- if (r.pos.x <= b.min.x)
- {
- T d = b.min.x - r.pos.x;
- T t = (r.dir.x > 1 || d < TMAX * r.dir.x)? d / r.dir.x: TMAX;
+ if (r.pos.x <= b.min.x)
+ {
+ T d = b.min.x - r.pos.x;
+ T t = (r.dir.x > 1 || d < TMAX * r.dir.x)? d / r.dir.x: TMAX;
- if (tFrontMax < t)
- {
- tFrontMax = t;
+ if (tFrontMax < t)
+ {
+ tFrontMax = t;
- ip.x = b.min.x;
- ip.y = clamp (r.pos.y + t * r.dir.y, b.min.y, b.max.y);
- ip.z = clamp (r.pos.z + t * r.dir.z, b.min.z, b.max.z);
- }
- }
+ ip.x = b.min.x;
+ ip.y = clamp (r.pos.y + t * r.dir.y, b.min.y, b.max.y);
+ ip.z = clamp (r.pos.z + t * r.dir.z, b.min.z, b.max.z);
+ }
+ }
}
else if (r.dir.x < 0)
{
- if (r.pos.x < b.min.x)
- return false;
+ if (r.pos.x < b.min.x)
+ return false;
- T d = b.min.x - r.pos.x;
+ T d = b.min.x - r.pos.x;
- if (r.dir.x < -1 || d > TMAX * r.dir.x)
- {
- T t = d / r.dir.x;
+ if (r.dir.x < -1 || d > TMAX * r.dir.x)
+ {
+ T t = d / r.dir.x;
- if (tBackMin > t)
- tBackMin = t;
- }
+ if (tBackMin > t)
+ tBackMin = t;
+ }
- if (r.pos.x >= b.max.x)
- {
- T d = b.max.x - r.pos.x;
- T t = (r.dir.x < -1 || d > TMAX * r.dir.x)? d / r.dir.x: TMAX;
+ if (r.pos.x >= b.max.x)
+ {
+ T d = b.max.x - r.pos.x;
+ T t = (r.dir.x < -1 || d > TMAX * r.dir.x)? d / r.dir.x: TMAX;
- if (tFrontMax < t)
- {
- tFrontMax = t;
+ if (tFrontMax < t)
+ {
+ tFrontMax = t;
- ip.x = b.max.x;
- ip.y = clamp (r.pos.y + t * r.dir.y, b.min.y, b.max.y);
- ip.z = clamp (r.pos.z + t * r.dir.z, b.min.z, b.max.z);
- }
- }
+ ip.x = b.max.x;
+ ip.y = clamp (r.pos.y + t * r.dir.y, b.min.y, b.max.y);
+ ip.z = clamp (r.pos.z + t * r.dir.z, b.min.z, b.max.z);
+ }
+ }
}
else // r.dir.x == 0
{
- if (r.pos.x < b.min.x || r.pos.x > b.max.x)
- return false;
+ if (r.pos.x < b.min.x || r.pos.x > b.max.x)
+ return false;
}
//
if (r.dir.y > 0)
{
- if (r.pos.y > b.max.y)
- return false;
+ if (r.pos.y > b.max.y)
+ return false;
- T d = b.max.y - r.pos.y;
+ T d = b.max.y - r.pos.y;
- if (r.dir.y > 1 || d < TMAX * r.dir.y)
- {
- T t = d / r.dir.y;
+ if (r.dir.y > 1 || d < TMAX * r.dir.y)
+ {
+ T t = d / r.dir.y;
- if (tBackMin > t)
- tBackMin = t;
- }
+ if (tBackMin > t)
+ tBackMin = t;
+ }
- if (r.pos.y <= b.min.y)
- {
- T d = b.min.y - r.pos.y;
- T t = (r.dir.y > 1 || d < TMAX * r.dir.y)? d / r.dir.y: TMAX;
+ if (r.pos.y <= b.min.y)
+ {
+ T d = b.min.y - r.pos.y;
+ T t = (r.dir.y > 1 || d < TMAX * r.dir.y)? d / r.dir.y: TMAX;
- if (tFrontMax < t)
- {
- tFrontMax = t;
+ if (tFrontMax < t)
+ {
+ tFrontMax = t;
- ip.x = clamp (r.pos.x + t * r.dir.x, b.min.x, b.max.x);
- ip.y = b.min.y;
- ip.z = clamp (r.pos.z + t * r.dir.z, b.min.z, b.max.z);
- }
- }
+ ip.x = clamp (r.pos.x + t * r.dir.x, b.min.x, b.max.x);
+ ip.y = b.min.y;
+ ip.z = clamp (r.pos.z + t * r.dir.z, b.min.z, b.max.z);
+ }
+ }
}
else if (r.dir.y < 0)
{
- if (r.pos.y < b.min.y)
- return false;
+ if (r.pos.y < b.min.y)
+ return false;
- T d = b.min.y - r.pos.y;
+ T d = b.min.y - r.pos.y;
- if (r.dir.y < -1 || d > TMAX * r.dir.y)
- {
- T t = d / r.dir.y;
+ if (r.dir.y < -1 || d > TMAX * r.dir.y)
+ {
+ T t = d / r.dir.y;
- if (tBackMin > t)
- tBackMin = t;
- }
+ if (tBackMin > t)
+ tBackMin = t;
+ }
- if (r.pos.y >= b.max.y)
- {
- T d = b.max.y - r.pos.y;
- T t = (r.dir.y < -1 || d > TMAX * r.dir.y)? d / r.dir.y: TMAX;
+ if (r.pos.y >= b.max.y)
+ {
+ T d = b.max.y - r.pos.y;
+ T t = (r.dir.y < -1 || d > TMAX * r.dir.y)? d / r.dir.y: TMAX;
+
+ if (tFrontMax < t)
+ {
+ tFrontMax = t;
- if (tFrontMax < t)
- {
- tFrontMax = t;
-
- ip.x = clamp (r.pos.x + t * r.dir.x, b.min.x, b.max.x);
- ip.y = b.max.y;
- ip.z = clamp (r.pos.z + t * r.dir.z, b.min.z, b.max.z);
- }
- }
+ ip.x = clamp (r.pos.x + t * r.dir.x, b.min.x, b.max.x);
+ ip.y = b.max.y;
+ ip.z = clamp (r.pos.z + t * r.dir.z, b.min.z, b.max.z);
+ }
+ }
}
else // r.dir.y == 0
{
- if (r.pos.y < b.min.y || r.pos.y > b.max.y)
- return false;
+ if (r.pos.y < b.min.y || r.pos.y > b.max.y)
+ return false;
}
//
if (r.dir.z > 0)
{
- if (r.pos.z > b.max.z)
- return false;
+ if (r.pos.z > b.max.z)
+ return false;
- T d = b.max.z - r.pos.z;
+ T d = b.max.z - r.pos.z;
- if (r.dir.z > 1 || d < TMAX * r.dir.z)
- {
- T t = d / r.dir.z;
+ if (r.dir.z > 1 || d < TMAX * r.dir.z)
+ {
+ T t = d / r.dir.z;
- if (tBackMin > t)
- tBackMin = t;
- }
+ if (tBackMin > t)
+ tBackMin = t;
+ }
- if (r.pos.z <= b.min.z)
- {
- T d = b.min.z - r.pos.z;
- T t = (r.dir.z > 1 || d < TMAX * r.dir.z)? d / r.dir.z: TMAX;
-
- if (tFrontMax < t)
- {
- tFrontMax = t;
+ if (r.pos.z <= b.min.z)
+ {
+ T d = b.min.z - r.pos.z;
+ T t = (r.dir.z > 1 || d < TMAX * r.dir.z)? d / r.dir.z: TMAX;
+
+ if (tFrontMax < t)
+ {
+ tFrontMax = t;
- ip.x = clamp (r.pos.x + t * r.dir.x, b.min.x, b.max.x);
- ip.y = clamp (r.pos.y + t * r.dir.y, b.min.y, b.max.y);
- ip.z = b.min.z;
- }
- }
+ ip.x = clamp (r.pos.x + t * r.dir.x, b.min.x, b.max.x);
+ ip.y = clamp (r.pos.y + t * r.dir.y, b.min.y, b.max.y);
+ ip.z = b.min.z;
+ }
+ }
}
else if (r.dir.z < 0)
{
- if (r.pos.z < b.min.z)
- return false;
+ if (r.pos.z < b.min.z)
+ return false;
- T d = b.min.z - r.pos.z;
+ T d = b.min.z - r.pos.z;
- if (r.dir.z < -1 || d > TMAX * r.dir.z)
- {
- T t = d / r.dir.z;
+ if (r.dir.z < -1 || d > TMAX * r.dir.z)
+ {
+ T t = d / r.dir.z;
- if (tBackMin > t)
- tBackMin = t;
- }
+ if (tBackMin > t)
+ tBackMin = t;
+ }
- if (r.pos.z >= b.max.z)
- {
- T d = b.max.z - r.pos.z;
- T t = (r.dir.z < -1 || d > TMAX * r.dir.z)? d / r.dir.z: TMAX;
+ if (r.pos.z >= b.max.z)
+ {
+ T d = b.max.z - r.pos.z;
+ T t = (r.dir.z < -1 || d > TMAX * r.dir.z)? d / r.dir.z: TMAX;
+
+ if (tFrontMax < t)
+ {
+ tFrontMax = t;
- if (tFrontMax < t)
- {
- tFrontMax = t;
-
- ip.x = clamp (r.pos.x + t * r.dir.x, b.min.x, b.max.x);
- ip.y = clamp (r.pos.y + t * r.dir.y, b.min.y, b.max.y);
- ip.z = b.max.z;
- }
- }
+ ip.x = clamp (r.pos.x + t * r.dir.x, b.min.x, b.max.x);
+ ip.y = clamp (r.pos.y + t * r.dir.y, b.min.y, b.max.y);
+ ip.z = b.max.z;
+ }
+ }
}
else // r.dir.z == 0
{
- if (r.pos.z < b.min.z || r.pos.z > b.max.z)
- return false;
+ if (r.pos.z < b.min.z || r.pos.z > b.max.z)
+ return false;
}
return tFrontMax <= tBackMin;
}
-} // namespace Imath
+IMATH_INTERNAL_NAMESPACE_HEADER_EXIT
-#endif
+#endif // INCLUDED_IMATHBOXALGO_H
///////////////////////////////////////////////////////////////////////////
//
-// Copyright (c) 2004, Industrial Light & Magic, a division of Lucas
+// Copyright (c) 2004-2012, Industrial Light & Magic, a division of Lucas
// Digital Ltd. LLC
-//
+//
// All rights reserved.
-//
+//
// Redistribution and use in source and binary forms, with or without
// modification, are permitted provided that the following conditions are
// met:
// distribution.
// * Neither the name of Industrial Light & Magic nor the names of
// its contributors may be used to endorse or promote products derived
-// from this software without specific prior written permission.
-//
+// from this software without specific prior written permission.
+//
// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
//----------------------------------------------------
#include "ImathVec.h"
+#include "ImathNamespace.h"
#include "half.h"
-namespace Imath {
+IMATH_INTERNAL_NAMESPACE_HEADER_ENTER
template <class T>
}
template <class T>
-inline Color3<T>
+inline Color3<T>
Color3<T>::operator + (const Color3 &c) const
{
return Color3 (*(Vec3<T> *)this + (const Vec3<T> &)c);
}
template <class T>
-inline Color3<T>
+inline Color3<T>
Color3<T>::operator - (const Color3 &c) const
{
return Color3 (*(Vec3<T> *)this - (const Vec3<T> &)c);
}
template <class T>
-inline Color3<T>
+inline Color3<T>
Color3<T>::operator - () const
{
return Color3 (-(*(Vec3<T> *)this));
}
template <class T>
-inline Color3<T>
+inline Color3<T>
Color3<T>::operator * (const Color3 &c) const
{
return Color3 (*(Vec3<T> *)this * (const Vec3<T> &)c);
}
template <class T>
-inline Color3<T>
+inline Color3<T>
Color3<T>::operator * (T a) const
{
return Color3 (*(Vec3<T> *)this * a);
}
template <class T>
-inline Color3<T>
+inline Color3<T>
Color3<T>::operator / (const Color3 &c) const
{
return Color3 (*(Vec3<T> *)this / (const Vec3<T> &)c);
}
template <class T>
-inline Color3<T>
+inline Color3<T>
Color3<T>::operator / (T a) const
{
return Color3 (*(Vec3<T> *)this / a);
return Color4<T> (x * v.r, x * v.g, x * v.b, x * v.a);
}
-} // namespace Imath
-#endif
+IMATH_INTERNAL_NAMESPACE_HEADER_EXIT
+
+#endif // INCLUDED_IMATHCOLOR_H
///////////////////////////////////////////////////////////////////////////
//
-// Copyright (c) 2002, Industrial Light & Magic, a division of Lucas
+// Copyright (c) 2002-2012, Industrial Light & Magic, a division of Lucas
// Digital Ltd. LLC
-//
+//
// All rights reserved.
-//
+//
// Redistribution and use in source and binary forms, with or without
// modification, are permitted provided that the following conditions are
// met:
// distribution.
// * Neither the name of Industrial Light & Magic nor the names of
// its contributors may be used to endorse or promote products derived
-// from this software without specific prior written permission.
-//
+// from this software without specific prior written permission.
+//
// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
#include "ImathColorAlgo.h"
-namespace Imath {
+IMATH_INTERNAL_NAMESPACE_SOURCE_ENTER
Vec3<double>
double val = hsv.z;
double x = 0.0, y = 0.0, z = 0.0;
-
+
if (hue == 1) hue = 0;
else hue *= 6;
double q = val*(1-(sat*f));
double t = val*(1-(sat*(1-f)));
- switch (i)
+ switch (i)
{
case 0: x = val; y = t; z = p; break;
case 1: x = q; y = val; z = p; break;
}
-Color4<double>
+Color4<double>
hsv2rgb_d(const Color4<double> &hsv)
{
double hue = hsv.r;
double val = hsv.b;
double r = 0.0, g = 0.0, b = 0.0;
-
+
if (hue == 1) hue = 0;
else hue *= 6;
double q = val*(1-(sat*f));
double t = val*(1-(sat*(1-f)));
- switch (i)
+ switch (i)
{
case 0: r = val; g = t; b = p; break;
case 1: r = q; g = val; b = p; break;
double val = max;
double sat = 0;
double hue = 0;
-
+
if (max != 0) sat = range/max;
-
- if (sat != 0)
+
+ if (sat != 0)
{
- double h;
-
- if (x == max) h = (y - z) / range;
- else if (y == max) h = 2 + (z - x) / range;
- else h = 4 + (x - y) / range;
-
- hue = h/6.;
-
- if (hue < 0.)
- hue += 1.0;
+ double h;
+
+ if (x == max) h = (y - z) / range;
+ else if (y == max) h = 2 + (z - x) / range;
+ else h = 4 + (x - y) / range;
+
+ hue = h/6.;
+
+ if (hue < 0.)
+ hue += 1.0;
}
return Vec3<double>(hue,sat,val);
}
double val = max;
double sat = 0;
double hue = 0;
-
+
if (max != 0) sat = range/max;
-
- if (sat != 0)
+
+ if (sat != 0)
{
- double h;
-
- if (r == max) h = (g - b) / range;
- else if (g == max) h = 2 + (b - r) / range;
- else h = 4 + (r - g) / range;
-
- hue = h/6.;
-
- if (hue < 0.)
- hue += 1.0;
+ double h;
+
+ if (r == max) h = (g - b) / range;
+ else if (g == max) h = 2 + (b - r) / range;
+ else h = 4 + (r - g) / range;
+
+ hue = h/6.;
+
+ if (hue < 0.)
+ hue += 1.0;
}
return Color4<double>(hue,sat,val,c.a);
}
-} // namespace Imath
+IMATH_INTERNAL_NAMESPACE_SOURCE_EXIT
///////////////////////////////////////////////////////////////////////////
//
-// Copyright (c) 2002, Industrial Light & Magic, a division of Lucas
+// Copyright (c) 2002-2012, Industrial Light & Magic, a division of Lucas
// Digital Ltd. LLC
-//
+//
// All rights reserved.
-//
+//
// Redistribution and use in source and binary forms, with or without
// modification, are permitted provided that the following conditions are
// met:
// distribution.
// * Neither the name of Industrial Light & Magic nor the names of
// its contributors may be used to endorse or promote products derived
-// from this software without specific prior written permission.
-//
+// from this software without specific prior written permission.
+//
// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
#include "ImathColor.h"
+#include "ImathExport.h"
#include "ImathMath.h"
#include "ImathLimits.h"
+#include "ImathNamespace.h"
-namespace Imath {
+IMATH_INTERNAL_NAMESPACE_HEADER_ENTER
//
// These routines eliminate type warnings under g++.
//
-Vec3<double> hsv2rgb_d(const Vec3<double> &hsv);
-
-Color4<double> hsv2rgb_d(const Color4<double> &hsv);
+IMATH_EXPORT Vec3<double> hsv2rgb_d(const Vec3<double> &hsv);
+IMATH_EXPORT Color4<double> hsv2rgb_d(const Color4<double> &hsv);
-Vec3<double> rgb2hsv_d(const Vec3<double> &rgb);
+IMATH_EXPORT Vec3<double> rgb2hsv_d(const Vec3<double> &rgb);
-Color4<double> rgb2hsv_d(const Color4<double> &rgb);
+IMATH_EXPORT Color4<double> rgb2hsv_d(const Color4<double> &rgb);
//
// see each funtion definition for details.
//
-template<class T>
-Vec3<T>
+template<class T>
+Vec3<T>
hsv2rgb(const Vec3<T> &hsv)
{
if ( limits<T>::isIntegral() )
{
- Vec3<double> v = Vec3<double>(hsv.x / double(limits<T>::max()),
- hsv.y / double(limits<T>::max()),
- hsv.z / double(limits<T>::max()));
- Vec3<double> c = hsv2rgb_d(v);
- return Vec3<T>((T) (c.x * limits<T>::max()),
- (T) (c.y * limits<T>::max()),
- (T) (c.z * limits<T>::max()));
+ Vec3<double> v = Vec3<double>(hsv.x / double(limits<T>::max()),
+ hsv.y / double(limits<T>::max()),
+ hsv.z / double(limits<T>::max()));
+ Vec3<double> c = hsv2rgb_d(v);
+ return Vec3<T>((T) (c.x * limits<T>::max()),
+ (T) (c.y * limits<T>::max()),
+ (T) (c.z * limits<T>::max()));
}
else
{
- Vec3<double> v = Vec3<double>(hsv.x, hsv.y, hsv.z);
- Vec3<double> c = hsv2rgb_d(v);
- return Vec3<T>((T) c.x, (T) c.y, (T) c.z);
+ Vec3<double> v = Vec3<double>(hsv.x, hsv.y, hsv.z);
+ Vec3<double> c = hsv2rgb_d(v);
+ return Vec3<T>((T) c.x, (T) c.y, (T) c.z);
}
}
-template<class T>
-Color4<T>
+template<class T>
+Color4<T>
hsv2rgb(const Color4<T> &hsv)
{
if ( limits<T>::isIntegral() )
{
- Color4<double> v = Color4<double>(hsv.r / float(limits<T>::max()),
- hsv.g / float(limits<T>::max()),
- hsv.b / float(limits<T>::max()),
- hsv.a / float(limits<T>::max()));
- Color4<double> c = hsv2rgb_d(v);
- return Color4<T>((T) (c.r * limits<T>::max()),
- (T) (c.g * limits<T>::max()),
- (T) (c.b * limits<T>::max()),
- (T) (c.a * limits<T>::max()));
+ Color4<double> v = Color4<double>(hsv.r / float(limits<T>::max()),
+ hsv.g / float(limits<T>::max()),
+ hsv.b / float(limits<T>::max()),
+ hsv.a / float(limits<T>::max()));
+ Color4<double> c = hsv2rgb_d(v);
+ return Color4<T>((T) (c.r * limits<T>::max()),
+ (T) (c.g * limits<T>::max()),
+ (T) (c.b * limits<T>::max()),
+ (T) (c.a * limits<T>::max()));
}
else
{
- Color4<double> v = Color4<double>(hsv.r, hsv.g, hsv.b, hsv.a);
- Color4<double> c = hsv2rgb_d(v);
- return Color4<T>((T) c.r, (T) c.g, (T) c.b, (T) c.a);
+ Color4<double> v = Color4<double>(hsv.r, hsv.g, hsv.b, hsv.a);
+ Color4<double> c = hsv2rgb_d(v);
+ return Color4<T>((T) c.r, (T) c.g, (T) c.b, (T) c.a);
}
}
-template<class T>
-Vec3<T>
+template<class T>
+Vec3<T>
rgb2hsv(const Vec3<T> &rgb)
{
if ( limits<T>::isIntegral() )
{
- Vec3<double> v = Vec3<double>(rgb.x / double(limits<T>::max()),
- rgb.y / double(limits<T>::max()),
- rgb.z / double(limits<T>::max()));
- Vec3<double> c = rgb2hsv_d(v);
- return Vec3<T>((T) (c.x * limits<T>::max()),
- (T) (c.y * limits<T>::max()),
- (T) (c.z * limits<T>::max()));
+ Vec3<double> v = Vec3<double>(rgb.x / double(limits<T>::max()),
+ rgb.y / double(limits<T>::max()),
+ rgb.z / double(limits<T>::max()));
+ Vec3<double> c = rgb2hsv_d(v);
+ return Vec3<T>((T) (c.x * limits<T>::max()),
+ (T) (c.y * limits<T>::max()),
+ (T) (c.z * limits<T>::max()));
}
else
{
- Vec3<double> v = Vec3<double>(rgb.x, rgb.y, rgb.z);
- Vec3<double> c = rgb2hsv_d(v);
- return Vec3<T>((T) c.x, (T) c.y, (T) c.z);
+ Vec3<double> v = Vec3<double>(rgb.x, rgb.y, rgb.z);
+ Vec3<double> c = rgb2hsv_d(v);
+ return Vec3<T>((T) c.x, (T) c.y, (T) c.z);
}
}
-template<class T>
-Color4<T>
+template<class T>
+Color4<T>
rgb2hsv(const Color4<T> &rgb)
{
if ( limits<T>::isIntegral() )
{
- Color4<double> v = Color4<double>(rgb.r / float(limits<T>::max()),
- rgb.g / float(limits<T>::max()),
- rgb.b / float(limits<T>::max()),
- rgb.a / float(limits<T>::max()));
- Color4<double> c = rgb2hsv_d(v);
- return Color4<T>((T) (c.r * limits<T>::max()),
- (T) (c.g * limits<T>::max()),
- (T) (c.b * limits<T>::max()),
- (T) (c.a * limits<T>::max()));
+ Color4<double> v = Color4<double>(rgb.r / float(limits<T>::max()),
+ rgb.g / float(limits<T>::max()),
+ rgb.b / float(limits<T>::max()),
+ rgb.a / float(limits<T>::max()));
+ Color4<double> c = rgb2hsv_d(v);
+ return Color4<T>((T) (c.r * limits<T>::max()),
+ (T) (c.g * limits<T>::max()),
+ (T) (c.b * limits<T>::max()),
+ (T) (c.a * limits<T>::max()));
}
else
{
- Color4<double> v = Color4<double>(rgb.r, rgb.g, rgb.b, rgb.a);
- Color4<double> c = rgb2hsv_d(v);
- return Color4<T>((T) c.r, (T) c.g, (T) c.b, (T) c.a);
+ Color4<double> v = Color4<double>(rgb.r, rgb.g, rgb.b, rgb.a);
+ Color4<double> c = rgb2hsv_d(v);
+ return Color4<T>((T) c.r, (T) c.g, (T) c.b, (T) c.a);
}
}
{
if ( limits<T>::isIntegral() )
{
- float x = c.x / float(limits<T>::max());
- float y = c.y / float(limits<T>::max());
- float z = c.z / float(limits<T>::max());
- return rgb2packed( V3f(x,y,z) );
+ float x = c.x / float(limits<T>::max());
+ float y = c.y / float(limits<T>::max());
+ float z = c.z / float(limits<T>::max());
+ return rgb2packed( V3f(x,y,z) );
}
else
{
- return ( (PackedColor) (c.x * 255) |
- (((PackedColor) (c.y * 255)) << 8) |
- (((PackedColor) (c.z * 255)) << 16) | 0xFF000000 );
+ return ( (PackedColor) (c.x * 255) |
+ (((PackedColor) (c.y * 255)) << 8) |
+ (((PackedColor) (c.z * 255)) << 16) | 0xFF000000 );
}
}
{
if ( limits<T>::isIntegral() )
{
- float r = c.r / float(limits<T>::max());
- float g = c.g / float(limits<T>::max());
- float b = c.b / float(limits<T>::max());
- float a = c.a / float(limits<T>::max());
- return rgb2packed( C4f(r,g,b,a) );
+ float r = c.r / float(limits<T>::max());
+ float g = c.g / float(limits<T>::max());
+ float b = c.b / float(limits<T>::max());
+ float a = c.a / float(limits<T>::max());
+ return rgb2packed( C4f(r,g,b,a) );
}
else
{
- return ( (PackedColor) (c.r * 255) |
- (((PackedColor) (c.g * 255)) << 8) |
- (((PackedColor) (c.b * 255)) << 16) |
- (((PackedColor) (c.a * 255)) << 24));
+ return ( (PackedColor) (c.r * 255) |
+ (((PackedColor) (c.g * 255)) << 8) |
+ (((PackedColor) (c.b * 255)) << 16) |
+ (((PackedColor) (c.a * 255)) << 24));
}
}
{
if ( limits<T>::isIntegral() )
{
- T f = limits<T>::max() / ((PackedColor)0xFF);
- out.x = (packed & 0xFF) * f;
- out.y = ((packed & 0xFF00) >> 8) * f;
- out.z = ((packed & 0xFF0000) >> 16) * f;
+ T f = limits<T>::max() / ((PackedColor)0xFF);
+ out.x = (packed & 0xFF) * f;
+ out.y = ((packed & 0xFF00) >> 8) * f;
+ out.z = ((packed & 0xFF0000) >> 16) * f;
}
else
{
- T f = T(1) / T(255);
- out.x = (packed & 0xFF) * f;
- out.y = ((packed & 0xFF00) >> 8) * f;
- out.z = ((packed & 0xFF0000) >> 16) * f;
+ T f = T(1) / T(255);
+ out.x = (packed & 0xFF) * f;
+ out.y = ((packed & 0xFF00) >> 8) * f;
+ out.z = ((packed & 0xFF0000) >> 16) * f;
}
}
{
if ( limits<T>::isIntegral() )
{
- T f = limits<T>::max() / ((PackedColor)0xFF);
- out.r = (packed & 0xFF) * f;
- out.g = ((packed & 0xFF00) >> 8) * f;
- out.b = ((packed & 0xFF0000) >> 16) * f;
- out.a = ((packed & 0xFF000000) >> 24) * f;
+ T f = limits<T>::max() / ((PackedColor)0xFF);
+ out.r = (packed & 0xFF) * f;
+ out.g = ((packed & 0xFF00) >> 8) * f;
+ out.b = ((packed & 0xFF0000) >> 16) * f;
+ out.a = ((packed & 0xFF000000) >> 24) * f;
}
else
{
- T f = T(1) / T(255);
- out.r = (packed & 0xFF) * f;
- out.g = ((packed & 0xFF00) >> 8) * f;
- out.b = ((packed & 0xFF0000) >> 16) * f;
- out.a = ((packed & 0xFF000000) >> 24) * f;
+ T f = T(1) / T(255);
+ out.r = (packed & 0xFF) * f;
+ out.g = ((packed & 0xFF00) >> 8) * f;
+ out.b = ((packed & 0xFF0000) >> 16) * f;
+ out.a = ((packed & 0xFF000000) >> 24) * f;
}
}
-} // namespace Imath
+IMATH_INTERNAL_NAMESPACE_HEADER_EXIT
-#endif
+#endif // INCLUDED_IMATHCOLORALGO_H
///////////////////////////////////////////////////////////////////////////
//
-// Copyright (c) 2002, Industrial Light & Magic, a division of Lucas
+// Copyright (c) 2002-2012, Industrial Light & Magic, a division of Lucas
// Digital Ltd. LLC
-//
+//
// All rights reserved.
-//
+//
// Redistribution and use in source and binary forms, with or without
// modification, are permitted provided that the following conditions are
// met:
// distribution.
// * Neither the name of Industrial Light & Magic nor the names of
// its contributors may be used to endorse or promote products derived
-// from this software without specific prior written permission.
-//
+// from this software without specific prior written permission.
+//
// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
// There are 24 possible combonations of Euler angle
// representations of which 12 are common in CG and you will
// probably only use 6 of these which in this scheme are the
-// non-relative-non-repeating types.
+// non-relative-non-repeating types.
//
// The representations can be partitioned according to two
// criteria:
// When you construct a given representation from scratch you
// must order the angles according to their priorities. So, the
// easiest is a softimage or aerospace (yaw/pitch/roll) ordering
-// of ZYX.
+// of ZYX.
//
// float x_rot = 1;
// float y_rot = 2;
// If you want to set the Euler with an XYZVector use the
// optional layout argument:
//
-// Eulerf angles(x_rot, y_rot, z_rot,
+// Eulerf angles(x_rot, y_rot, z_rot,
// Eulerf::YXZ,
// Eulerf::XYZLayout);
//
// This is the same as:
//
// Eulerf angles(y_rot, x_rot, z_rot, Eulerf::YXZ);
-//
+//
// Note that this won't do anything intelligent if you have a
// repeated axis in the euler angles (e.g. XYX)
//
// If you need to use the "relative" versions of these, you will
-// need to use the "r" enums.
+// need to use the "r" enums.
//
// The units of the rotation angles are assumed to be radians.
//
#include "ImathQuat.h"
#include "ImathMatrix.h"
#include "ImathLimits.h"
+#include "ImathNamespace.h"
+
#include <iostream>
-namespace Imath {
+IMATH_INTERNAL_NAMESPACE_HEADER_ENTER
#if (defined _WIN32 || defined _WIN64) && defined _MSC_VER
// Disable MS VC++ warnings about conversion from double to float
class Euler : public Vec3<T>
{
public:
-
+
using Vec3<T>::x;
using Vec3<T>::y;
using Vec3<T>::z;
enum Order
{
- //
- // All 24 possible orderings
- //
-
- XYZ = 0x0101, // "usual" orderings
- XZY = 0x0001,
- YZX = 0x1101,
- YXZ = 0x1001,
- ZXY = 0x2101,
- ZYX = 0x2001,
-
- XZX = 0x0011, // first axis repeated
- XYX = 0x0111,
- YXY = 0x1011,
- YZY = 0x1111,
- ZYZ = 0x2011,
- ZXZ = 0x2111,
-
- XYZr = 0x2000, // relative orderings -- not common
- XZYr = 0x2100,
- YZXr = 0x1000,
- YXZr = 0x1100,
- ZXYr = 0x0000,
- ZYXr = 0x0100,
-
- XZXr = 0x2110, // relative first axis repeated
- XYXr = 0x2010,
- YXYr = 0x1110,
- YZYr = 0x1010,
- ZYZr = 0x0110,
- ZXZr = 0x0010,
- // ||||
- // VVVV
- // Legend: ABCD
- // A -> Initial Axis (0==x, 1==y, 2==z)
- // B -> Parity Even (1==true)
- // C -> Initial Repeated (1==true)
- // D -> Frame Static (1==true)
- //
-
- Legal = XYZ | XZY | YZX | YXZ | ZXY | ZYX |
- XZX | XYX | YXY | YZY | ZYZ | ZXZ |
- XYZr| XZYr| YZXr| YXZr| ZXYr| ZYXr|
- XZXr| XYXr| YXYr| YZYr| ZYZr| ZXZr,
-
- Min = 0x0000,
- Max = 0x2111,
- Default = XYZ
+ //
+ // All 24 possible orderings
+ //
+
+ XYZ = 0x0101, // "usual" orderings
+ XZY = 0x0001,
+ YZX = 0x1101,
+ YXZ = 0x1001,
+ ZXY = 0x2101,
+ ZYX = 0x2001,
+
+ XZX = 0x0011, // first axis repeated
+ XYX = 0x0111,
+ YXY = 0x1011,
+ YZY = 0x1111,
+ ZYZ = 0x2011,
+ ZXZ = 0x2111,
+
+ XYZr = 0x2000, // relative orderings -- not common
+ XZYr = 0x2100,
+ YZXr = 0x1000,
+ YXZr = 0x1100,
+ ZXYr = 0x0000,
+ ZYXr = 0x0100,
+
+ XZXr = 0x2110, // relative first axis repeated
+ XYXr = 0x2010,
+ YXYr = 0x1110,
+ YZYr = 0x1010,
+ ZYZr = 0x0110,
+ ZXZr = 0x0010,
+ // ||||
+ // VVVV
+ // Legend: ABCD
+ // A -> Initial Axis (0==x, 1==y, 2==z)
+ // B -> Parity Even (1==true)
+ // C -> Initial Repeated (1==true)
+ // D -> Frame Static (1==true)
+ //
+
+ Legal = XYZ | XZY | YZX | YXZ | ZXY | ZYX |
+ XZX | XYX | YXY | YZY | ZYZ | ZXZ |
+ XYZr| XZYr| YZXr| YXZr| ZXYr| ZYXr|
+ XZXr| XYXr| YXYr| YZYr| ZYZr| ZXZr,
+
+ Min = 0x0000,
+ Max = 0x2111,
+ Default = XYZ
};
enum Axis { X = 0, Y = 1, Z = 2 };
//--------------------------------------------------------
// Set the euler value
- // This does NOT convert the angles, but setXYZVector()
+ // This does NOT convert the angles, but setXYZVector()
// does reorder the input vector.
//--------------------------------------------------------
void setOrder(Order);
void set(Axis initial,
- bool relative,
- bool parityEven,
- bool firstRepeats);
+ bool relative,
+ bool parityEven,
+ bool firstRepeats);
//------------------------------------------------------------
// Conversions, toXYZVector() reorders the angles so that
// Use this function to determine mapping from xyz to ijk
// - reshuffles the xyz to match the order
//---------------------------------------------------
-
+
void angleMapping(int &i, int &j, int &k) const;
//----------------------------------------------------------------------
static float angleMod (T angle);
static void simpleXYZRotation (Vec3<T> &xyzRot,
- const Vec3<T> &targetXyzRot);
+ const Vec3<T> &targetXyzRot);
static void nearestRotation (Vec3<T> &xyzRot,
- const Vec3<T> &targetXyzRot,
- Order order = XYZ);
+ const Vec3<T> &targetXyzRot,
+ Order order = XYZ);
void makeNear (const Euler<T> &target);
}
template<class T>
-inline Euler<T>::Euler( const Vec3<T> &v,
- typename Euler<T>::Order p,
- typename Euler<T>::InputLayout l )
+inline Euler<T>::Euler( const Vec3<T> &v,
+ typename Euler<T>::Order p,
+ typename Euler<T>::InputLayout l )
{
- setOrder(p);
+ setOrder(p);
if ( l == XYZLayout ) setXYZVector(v);
else { x = v.x; y = v.y; z = v.z; }
}
}
template<class T>
-inline Euler<T>::Euler( T xi, T yi, T zi,
- typename Euler<T>::Order p,
- typename Euler<T>::InputLayout l)
+inline Euler<T>::Euler( T xi, T yi, T zi,
+ typename Euler<T>::Order p,
+ typename Euler<T>::InputLayout l)
{
setOrder(p);
if ( l == XYZLayout ) setXYZVector(Vec3<T>(xi,yi,zi));
if (_initialRepeated)
{
- //
- // Extract the first angle, x.
- //
-
- x = Math<T>::atan2 (M[j][i], M[k][i]);
-
- //
- // Remove the x rotation from M, so that the remaining
- // rotation, N, is only around two axes, and gimbal lock
- // cannot occur.
- //
-
- Vec3<T> r (0, 0, 0);
- r[i] = (_parityEven? -x: x);
-
- Matrix44<T> N;
- N.rotate (r);
-
- N = N * Matrix44<T> (M[0][0], M[0][1], M[0][2], 0,
- M[1][0], M[1][1], M[1][2], 0,
- M[2][0], M[2][1], M[2][2], 0,
- 0, 0, 0, 1);
- //
- // Extract the other two angles, y and z, from N.
- //
-
- T sy = Math<T>::sqrt (N[j][i]*N[j][i] + N[k][i]*N[k][i]);
- y = Math<T>::atan2 (sy, N[i][i]);
- z = Math<T>::atan2 (N[j][k], N[j][j]);
+ //
+ // Extract the first angle, x.
+ //
+
+ x = Math<T>::atan2 (M[j][i], M[k][i]);
+
+ //
+ // Remove the x rotation from M, so that the remaining
+ // rotation, N, is only around two axes, and gimbal lock
+ // cannot occur.
+ //
+
+ Vec3<T> r (0, 0, 0);
+ r[i] = (_parityEven? -x: x);
+
+ Matrix44<T> N;
+ N.rotate (r);
+
+ N = N * Matrix44<T> (M[0][0], M[0][1], M[0][2], 0,
+ M[1][0], M[1][1], M[1][2], 0,
+ M[2][0], M[2][1], M[2][2], 0,
+ 0, 0, 0, 1);
+ //
+ // Extract the other two angles, y and z, from N.
+ //
+
+ T sy = Math<T>::sqrt (N[j][i]*N[j][i] + N[k][i]*N[k][i]);
+ y = Math<T>::atan2 (sy, N[i][i]);
+ z = Math<T>::atan2 (N[j][k], N[j][j]);
}
else
{
- //
- // Extract the first angle, x.
- //
-
- x = Math<T>::atan2 (M[j][k], M[k][k]);
-
- //
- // Remove the x rotation from M, so that the remaining
- // rotation, N, is only around two axes, and gimbal lock
- // cannot occur.
- //
-
- Vec3<T> r (0, 0, 0);
- r[i] = (_parityEven? -x: x);
-
- Matrix44<T> N;
- N.rotate (r);
-
- N = N * Matrix44<T> (M[0][0], M[0][1], M[0][2], 0,
- M[1][0], M[1][1], M[1][2], 0,
- M[2][0], M[2][1], M[2][2], 0,
- 0, 0, 0, 1);
- //
- // Extract the other two angles, y and z, from N.
- //
-
- T cy = Math<T>::sqrt (N[i][i]*N[i][i] + N[i][j]*N[i][j]);
- y = Math<T>::atan2 (-N[i][k], cy);
- z = Math<T>::atan2 (-N[j][i], N[j][j]);
+ //
+ // Extract the first angle, x.
+ //
+
+ x = Math<T>::atan2 (M[j][k], M[k][k]);
+
+ //
+ // Remove the x rotation from M, so that the remaining
+ // rotation, N, is only around two axes, and gimbal lock
+ // cannot occur.
+ //
+
+ Vec3<T> r (0, 0, 0);
+ r[i] = (_parityEven? -x: x);
+
+ Matrix44<T> N;
+ N.rotate (r);
+
+ N = N * Matrix44<T> (M[0][0], M[0][1], M[0][2], 0,
+ M[1][0], M[1][1], M[1][2], 0,
+ M[2][0], M[2][1], M[2][2], 0,
+ 0, 0, 0, 1);
+ //
+ // Extract the other two angles, y and z, from N.
+ //
+
+ T cy = Math<T>::sqrt (N[i][i]*N[i][i] + N[i][j]*N[i][j]);
+ y = Math<T>::atan2 (-N[i][k], cy);
+ z = Math<T>::atan2 (-N[j][i], N[j][j]);
}
if (!_parityEven)
- *this *= -1;
+ *this *= -1;
if (!_frameStatic)
{
- T t = x;
- x = z;
- z = t;
+ T t = x;
+ x = z;
+ z = t;
}
}
if (_initialRepeated)
{
- //
- // Extract the first angle, x.
- //
+ //
+ // Extract the first angle, x.
+ //
- x = Math<T>::atan2 (M[j][i], M[k][i]);
+ x = Math<T>::atan2 (M[j][i], M[k][i]);
- //
- // Remove the x rotation from M, so that the remaining
- // rotation, N, is only around two axes, and gimbal lock
- // cannot occur.
- //
+ //
+ // Remove the x rotation from M, so that the remaining
+ // rotation, N, is only around two axes, and gimbal lock
+ // cannot occur.
+ //
- Vec3<T> r (0, 0, 0);
- r[i] = (_parityEven? -x: x);
+ Vec3<T> r (0, 0, 0);
+ r[i] = (_parityEven? -x: x);
- Matrix44<T> N;
- N.rotate (r);
- N = N * M;
+ Matrix44<T> N;
+ N.rotate (r);
+ N = N * M;
- //
- // Extract the other two angles, y and z, from N.
- //
+ //
+ // Extract the other two angles, y and z, from N.
+ //
- T sy = Math<T>::sqrt (N[j][i]*N[j][i] + N[k][i]*N[k][i]);
- y = Math<T>::atan2 (sy, N[i][i]);
- z = Math<T>::atan2 (N[j][k], N[j][j]);
+ T sy = Math<T>::sqrt (N[j][i]*N[j][i] + N[k][i]*N[k][i]);
+ y = Math<T>::atan2 (sy, N[i][i]);
+ z = Math<T>::atan2 (N[j][k], N[j][j]);
}
else
{
- //
- // Extract the first angle, x.
- //
+ //
+ // Extract the first angle, x.
+ //
- x = Math<T>::atan2 (M[j][k], M[k][k]);
+ x = Math<T>::atan2 (M[j][k], M[k][k]);
- //
- // Remove the x rotation from M, so that the remaining
- // rotation, N, is only around two axes, and gimbal lock
- // cannot occur.
- //
+ //
+ // Remove the x rotation from M, so that the remaining
+ // rotation, N, is only around two axes, and gimbal lock
+ // cannot occur.
+ //
- Vec3<T> r (0, 0, 0);
- r[i] = (_parityEven? -x: x);
+ Vec3<T> r (0, 0, 0);
+ r[i] = (_parityEven? -x: x);
- Matrix44<T> N;
- N.rotate (r);
- N = N * M;
+ Matrix44<T> N;
+ N.rotate (r);
+ N = N * M;
- //
- // Extract the other two angles, y and z, from N.
- //
+ //
+ // Extract the other two angles, y and z, from N.
+ //
- T cy = Math<T>::sqrt (N[i][i]*N[i][i] + N[i][j]*N[i][j]);
- y = Math<T>::atan2 (-N[i][k], cy);
- z = Math<T>::atan2 (-N[j][i], N[j][j]);
+ T cy = Math<T>::sqrt (N[i][i]*N[i][i] + N[i][j]*N[i][j]);
+ y = Math<T>::atan2 (-N[i][k], cy);
+ z = Math<T>::atan2 (-N[j][i], N[j][j]);
}
if (!_parityEven)
- *this *= -1;
+ *this *= -1;
if (!_frameStatic)
{
- T t = x;
- x = z;
- z = t;
+ T t = x;
+ x = z;
+ z = t;
}
}
if ( _initialRepeated )
{
- M[i][i] = cj; M[j][i] = sj*si; M[k][i] = sj*ci;
- M[i][j] = sj*sh; M[j][j] = -cj*ss+cc; M[k][j] = -cj*cs-sc;
- M[i][k] = -sj*ch; M[j][k] = cj*sc+cs; M[k][k] = cj*cc-ss;
+ M[i][i] = cj; M[j][i] = sj*si; M[k][i] = sj*ci;
+ M[i][j] = sj*sh; M[j][j] = -cj*ss+cc; M[k][j] = -cj*cs-sc;
+ M[i][k] = -sj*ch; M[j][k] = cj*sc+cs; M[k][k] = cj*cc-ss;
}
else
{
- M[i][i] = cj*ch; M[j][i] = sj*sc-cs; M[k][i] = sj*cc+ss;
- M[i][j] = cj*sh; M[j][j] = sj*ss+cc; M[k][j] = sj*cs-sc;
- M[i][k] = -sj; M[j][k] = cj*si; M[k][k] = cj*ci;
+ M[i][i] = cj*ch; M[j][i] = sj*sc-cs; M[k][i] = sj*cc+ss;
+ M[i][j] = cj*sh; M[j][j] = sj*ss+cc; M[k][j] = sj*cs-sc;
+ M[i][k] = -sj; M[j][k] = cj*si; M[k][k] = cj*ci;
}
return M;
if ( _initialRepeated )
{
- M[i][i] = cj; M[j][i] = sj*si; M[k][i] = sj*ci;
- M[i][j] = sj*sh; M[j][j] = -cj*ss+cc; M[k][j] = -cj*cs-sc;
- M[i][k] = -sj*ch; M[j][k] = cj*sc+cs; M[k][k] = cj*cc-ss;
+ M[i][i] = cj; M[j][i] = sj*si; M[k][i] = sj*ci;
+ M[i][j] = sj*sh; M[j][j] = -cj*ss+cc; M[k][j] = -cj*cs-sc;
+ M[i][k] = -sj*ch; M[j][k] = cj*sc+cs; M[k][k] = cj*cc-ss;
}
else
{
- M[i][i] = cj*ch; M[j][i] = sj*sc-cs; M[k][i] = sj*cc+ss;
- M[i][j] = cj*sh; M[j][j] = sj*ss+cc; M[k][j] = sj*cs-sc;
- M[i][k] = -sj; M[j][k] = cj*si; M[k][k] = cj*ci;
+ M[i][i] = cj*ch; M[j][i] = sj*sc-cs; M[k][i] = sj*cc+ss;
+ M[i][j] = cj*sh; M[j][j] = sj*ss+cc; M[k][j] = sj*cs-sc;
+ M[i][k] = -sj; M[j][k] = cj*si; M[k][k] = cj*ci;
}
return M;
if ( _initialRepeated )
{
- a[i] = cj*(cs + sc);
- a[j] = sj*(cc + ss) * parity,
- a[k] = sj*(cs - sc);
- q.r = cj*(cc - ss);
+ a[i] = cj*(cs + sc);
+ a[j] = sj*(cc + ss) * parity,
+ a[k] = sj*(cs - sc);
+ q.r = cj*(cc - ss);
}
else
{
- a[i] = cj*sc - sj*cs,
- a[j] = (cj*ss + sj*cc) * parity,
- a[k] = cj*cs - sj*sc;
- q.r = cj*cc + sj*ss;
+ a[i] = cj*sc - sj*cs,
+ a[j] = (cj*ss + sj*cc) * parity,
+ a[k] = cj*cs - sj*sc;
+ q.r = cj*cc + sj*ss;
}
q.v = a;
inline void Euler<T>::setOrder(typename Euler<T>::Order p)
{
set( p & 0x2000 ? Z : (p & 0x1000 ? Y : X), // initial axis
- !(p & 0x1), // static?
- !!(p & 0x100), // permutation even?
- !!(p & 0x10)); // initial repeats?
+ !(p & 0x1), // static?
+ !!(p & 0x100), // permutation even?
+ !!(p & 0x10)); // initial repeats?
}
template<class T>
void Euler<T>::set(typename Euler<T>::Axis axis,
- bool relative,
- bool parityEven,
- bool firstRepeats)
+ bool relative,
+ bool parityEven,
+ bool firstRepeats)
{
_initialAxis = axis;
_frameStatic = !relative;
if ( euler.initialRepeated() ) k = i;
return o << "("
- << euler.x << " "
- << euler.y << " "
- << euler.z << " "
- << a[i] << a[j] << a[k] << r << ")";
+ << euler.x << " "
+ << euler.y << " "
+ << euler.z << " "
+ << a[i] << a[j] << a[k] << r << ")";
}
template <class T>
float
Euler<T>::angleMod (T angle)
{
- angle = fmod(T (angle), T (2 * M_PI));
+ const T pi = static_cast<T>(M_PI);
+ angle = fmod(T (angle), T (2 * pi));
- if (angle < -M_PI) angle += 2 * M_PI;
- if (angle > +M_PI) angle -= 2 * M_PI;
+ if (angle < -pi) angle += 2 * pi;
+ if (angle > +pi) angle -= 2 * pi;
return angle;
}
template <class T>
void
Euler<T>::nearestRotation (Vec3<T> &xyzRot, const Vec3<T> &targetXyzRot,
- Order order)
+ Order order)
{
int i,j,k;
Euler<T> e (0,0,0, order);
otherXyzRot[k] = M_PI+xyzRot[k];
simpleXYZRotation(otherXyzRot, targetXyzRot);
-
+
Vec3<T> d = xyzRot - targetXyzRot;
Vec3<T> od = otherXyzRot - targetXyzRot;
T dMag = d.dot(d);
if (odMag < dMag)
{
- xyzRot = otherXyzRot;
+ xyzRot = otherXyzRot;
}
}
#pragma warning(default:4244)
#endif
-} // namespace Imath
+IMATH_INTERNAL_NAMESPACE_HEADER_EXIT
-#endif
+#endif // INCLUDED_IMATHEULER_H
///////////////////////////////////////////////////////////////////////////
//
-// Copyright (c) 2002, Industrial Light & Magic, a division of Lucas
+// Copyright (c) 2002-2012, Industrial Light & Magic, a division of Lucas
// Digital Ltd. LLC
-//
+//
// All rights reserved.
-//
+//
// Redistribution and use in source and binary forms, with or without
// modification, are permitted provided that the following conditions are
// met:
// distribution.
// * Neither the name of Industrial Light & Magic nor the names of
// its contributors may be used to endorse or promote products derived
-// from this software without specific prior written permission.
-//
+// from this software without specific prior written permission.
+//
// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
///////////////////////////////////////////////////////////////////////////
-
#ifndef INCLUDED_IMATHEXC_H
#define INCLUDED_IMATHEXC_H
//
//-----------------------------------------------
+#include "ImathNamespace.h"
#include "IexBaseExc.h"
+#include "ImathExport.h"
-namespace Imath {
+IMATH_INTERNAL_NAMESPACE_HEADER_ENTER
+// Attempt to normalize null vector
+DEFINE_EXC_EXP (IMATH_EXPORT, NullVecExc, ::IEX_NAMESPACE::MathExc)
-DEFINE_EXC (NullVecExc, ::Iex::MathExc) // Attempt to normalize
- // null vector
+// Attempt to normalize a point at infinity
+DEFINE_EXC_EXP (IMATH_EXPORT, InfPointExc, ::IEX_NAMESPACE::MathExc)
-DEFINE_EXC (InfPointExc, ::Iex::MathExc) // Attempt to normalize
- // a point at infinity
+// Attempt to normalize null quaternion
+DEFINE_EXC_EXP (IMATH_EXPORT, NullQuatExc, ::IEX_NAMESPACE::MathExc)
-DEFINE_EXC (NullQuatExc, ::Iex::MathExc) // Attempt to normalize
- // null quaternion
+// Attempt to invert singular matrix
+DEFINE_EXC_EXP (IMATH_EXPORT, SingMatrixExc, ::IEX_NAMESPACE::MathExc)
-DEFINE_EXC (SingMatrixExc, ::Iex::MathExc) // Attempt to invert
- // singular matrix
+// Attempt to remove zero scaling from matrix
+DEFINE_EXC_EXP (IMATH_EXPORT, ZeroScaleExc, ::IEX_NAMESPACE::MathExc)
-DEFINE_EXC (ZeroScaleExc, ::Iex::MathExc) // Attempt to remove zero
- // scaling from matrix
+// Attempt to normalize a vector of whose elementsare an integer type
+DEFINE_EXC_EXP (IMATH_EXPORT, IntVecNormalizeExc, ::IEX_NAMESPACE::MathExc)
-DEFINE_EXC (IntVecNormalizeExc, ::Iex::MathExc) // Attempt to normalize
- // a vector of whose elements
- // are an integer type
-} // namespace Imath
+IMATH_INTERNAL_NAMESPACE_HEADER_EXIT
-#endif
+#endif // INCLUDED_IMATHEXC_H
--- /dev/null
+///////////////////////////////////////////////////////////////////////////
+//
+// Copyright (c) 2012, Industrial Light & Magic, a division of Lucas
+// Digital Ltd. LLC
+//
+// All rights reserved.
+//
+// Redistribution and use in source and binary forms, with or without
+// modification, are permitted provided that the following conditions are
+// met:
+// * Redistributions of source code must retain the above copyright
+// notice, this list of conditions and the following disclaimer.
+// * Redistributions in binary form must reproduce the above
+// copyright notice, this list of conditions and the following disclaimer
+// in the documentation and/or other materials provided with the
+// distribution.
+// * Neither the name of Industrial Light & Magic nor the names of
+// its contributors may be used to endorse or promote products derived
+// from this software without specific prior written permission.
+//
+// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+//
+///////////////////////////////////////////////////////////////////////////
+
+#if defined(OPENEXR_DLL)
+ #if defined(IMATH_EXPORTS)
+ #define IMATH_EXPORT __declspec(dllexport)
+ #define IMATH_EXPORT_CONST extern __declspec(dllexport)
+ #else
+ #define IMATH_EXPORT __declspec(dllimport)
+ #define IMATH_EXPORT_CONST extern __declspec(dllimport)
+ #endif
+#else
+ #define IMATH_EXPORT
+ #define IMATH_EXPORT_CONST extern const
+#endif
--- /dev/null
+///////////////////////////////////////////////////////////////////////////
+//
+// Copyright (c) 2012, Industrial Light & Magic, a division of Lucas
+// Digital Ltd. LLC
+//
+// All rights reserved.
+//
+// Redistribution and use in source and binary forms, with or without
+// modification, are permitted provided that the following conditions are
+// met:
+// * Redistributions of source code must retain the above copyright
+// notice, this list of conditions and the following disclaimer.
+// * Redistributions in binary form must reproduce the above
+// copyright notice, this list of conditions and the following disclaimer
+// in the documentation and/or other materials provided with the
+// distribution.
+// * Neither the name of Industrial Light & Magic nor the names of
+// its contributors may be used to endorse or promote products derived
+// from this software without specific prior written permission.
+//
+// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+//
+///////////////////////////////////////////////////////////////////////////
+
+#ifndef INCLUDED_IMATHFORWARD_H
+#define INCLUDED_IMATHFORWARD_H
+
+#include "ImathNamespace.h"
+
+IMATH_INTERNAL_NAMESPACE_HEADER_ENTER
+
+//
+// Basic template type declarations.
+//
+
+template <class T> class Box;
+template <class T> class Color3;
+template <class T> class Color4;
+template <class T> class Euler;
+template <class T> class Frustum;
+template <class T> class FrustumTest;
+template <class T> class Interval;
+template <class T> class Line3;
+template <class T> class Matrix33;
+template <class T> class Matrix44;
+template <class T> class Plane3;
+template <class T> class Quat;
+template <class T> class Shear6;
+template <class T> class Sphere3;
+template <class T> class TMatrix;
+template <class T> class TMatrixBase;
+template <class T> class TMatrixData;
+template <class T> class Vec2;
+template <class T> class Vec3;
+template <class T> class Vec4;
+
+class Rand32;
+class Rand48;
+
+IMATH_INTERNAL_NAMESPACE_HEADER_EXIT
+
+#endif // INCLUDED_IMATHFORWARD_H
///////////////////////////////////////////////////////////////////////////
//
-// Copyright (c) 2002, Industrial Light & Magic, a division of Lucas
+// Copyright (c) 2002-2012, Industrial Light & Magic, a division of Lucas
// Digital Ltd. LLC
-//
+//
// All rights reserved.
-//
+//
// Redistribution and use in source and binary forms, with or without
// modification, are permitted provided that the following conditions are
// met:
// distribution.
// * Neither the name of Industrial Light & Magic nor the names of
// its contributors may be used to endorse or promote products derived
-// from this software without specific prior written permission.
-//
+// from this software without specific prior written permission.
+//
// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
#ifndef INCLUDED_IMATHFRAME_H
#define INCLUDED_IMATHFRAME_H
-namespace Imath {
+#include "ImathNamespace.h"
+
+IMATH_INTERNAL_NAMESPACE_HEADER_ENTER
template<class T> class Vec3;
template<class T> class Matrix44;
//
// These methods compute a set of reference frames, defined by their
-// transformation matrix, along a curve. It is designed so that the
-// array of points and the array of matrices used to fetch these routines
+// transformation matrix, along a curve. It is designed so that the
+// array of points and the array of matrices used to fetch these routines
// don't need to be ordered as the curve.
-//
+//
// A typical usage would be :
//
-// m[0] = Imath::firstFrame( p[0], p[1], p[2] );
+// m[0] = IMATH_INTERNAL_NAMESPACE::firstFrame( p[0], p[1], p[2] );
// for( int i = 1; i < n - 1; i++ )
// {
-// m[i] = Imath::nextFrame( m[i-1], p[i-1], p[i], t[i-1], t[i] );
+// m[i] = IMATH_INTERNAL_NAMESPACE::nextFrame( m[i-1], p[i-1], p[i], t[i-1], t[i] );
// }
-// m[n-1] = Imath::lastFrame( m[n-2], p[n-2], p[n-1] );
+// m[n-1] = IMATH_INTERNAL_NAMESPACE::lastFrame( m[n-2], p[n-2], p[n-1] );
//
// See Graphics Gems I for the underlying algorithm.
-//
+//
template<class T> Matrix44<T> firstFrame( const Vec3<T>&, // First point
- const Vec3<T>&, // Second point
+ const Vec3<T>&, // Second point
const Vec3<T>& ); // Third point
template<class T> Matrix44<T> nextFrame( const Matrix44<T>&, // Previous matrix
//
template<class T> Matrix44<T> firstFrame
-(
+(
const Vec3<T>& pi, // First point
const Vec3<T>& pj, // Second point
const Vec3<T>& pk ) // Third point
//
// nextFrame - Compute the next reference frame along a curve.
//
-// This function returns the transformation matrix to the next reference
+// This function returns the transformation matrix to the next reference
// frame defined by the previously computed transformation matrix and the
// new point and tangent vector along the curve.
//
template<class T> Matrix44<T> nextFrame
-(
+(
const Matrix44<T>& Mi, // Previous matrix
const Vec3<T>& pi, // Previous point
const Vec3<T>& pj, // Current point
if( ti.length() != 0.0 && tj.length() != 0.0 )
{
ti.normalize(); tj.normalize();
- T dot = ti.dot( tj );
+ T dot = ti.dot( tj );
//
// This is *really* necessary :
//
- if( dot > 1.0 ) dot = 1.0;
+ if( dot > 1.0 ) dot = 1.0;
else if( dot < -1.0 ) dot = -1.0;
r = acosf( dot );
//
// lastFrame - Compute the last reference frame along a curve.
//
-// This function returns the transformation matrix to the last reference
+// This function returns the transformation matrix to the last reference
// frame defined by the previously computed transformation matrix and the
// last point along the curve.
//
template<class T> Matrix44<T> lastFrame
-(
+(
const Matrix44<T>& Mi, // Previous matrix
const Vec3<T>& pi, // Previous point
const Vec3<T>& pj ) // Last point
return Mi * Tr;
}
-} // namespace Imath
+IMATH_INTERNAL_NAMESPACE_HEADER_EXIT
-#endif
+#endif // INCLUDED_IMATHFRAME_H
///////////////////////////////////////////////////////////////////////////
//
-// Copyright (c) 2002, Industrial Light & Magic, a division of Lucas
+// Copyright (c) 2002-2012, Industrial Light & Magic, a division of Lucas
// Digital Ltd. LLC
-//
+//
// All rights reserved.
-//
+//
// Redistribution and use in source and binary forms, with or without
// modification, are permitted provided that the following conditions are
// met:
// distribution.
// * Neither the name of Industrial Light & Magic nor the names of
// its contributors may be used to endorse or promote products derived
-// from this software without specific prior written permission.
-//
+// from this software without specific prior written permission.
+//
// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
#include "ImathMatrix.h"
#include "ImathLimits.h"
#include "ImathFun.h"
+#include "ImathNamespace.h"
+
#include "IexMathExc.h"
-namespace Imath {
+IMATH_INTERNAL_NAMESPACE_HEADER_ENTER
//
-// template class Frustum<T>
+// template class Frustum<T>
//
-// The frustum is always located with the eye point at the
-// origin facing down -Z. This makes the Frustum class
-// compatable with OpenGL (or anything that assumes a camera
-// looks down -Z, hence with a right-handed coordinate system)
-// but not with RenderMan which assumes the camera looks down
-// +Z. Additional functions are provided for conversion from
-// and from various camera coordinate spaces.
+// The frustum is always located with the eye point at the
+// origin facing down -Z. This makes the Frustum class
+// compatable with OpenGL (or anything that assumes a camera
+// looks down -Z, hence with a right-handed coordinate system)
+// but not with RenderMan which assumes the camera looks down
+// +Z. Additional functions are provided for conversion from
+// and from various camera coordinate spaces.
//
-// nearPlane/farPlane: near/far are keywords used by Microsoft's
-// compiler, so we use nearPlane/farPlane instead to avoid
-// issues.
+// nearPlane/farPlane: near/far are keywords used by Microsoft's
+// compiler, so we use nearPlane/farPlane instead to avoid
+// issues.
template<class T>
// Assignment operator
//--------------------
- const Frustum &operator = (const Frustum &);
+ const Frustum & operator = (const Frustum &);
//--------------------
// Operators: ==, !=
//--------------------
-
- bool operator == (const Frustum<T> &src) const;
- bool operator != (const Frustum<T> &src) const;
+
+ bool operator == (const Frustum<T> &src) const;
+ bool operator != (const Frustum<T> &src) const;
//--------------------------------------------------------
// Set functions change the entire state of the Frustum
//--------------------------------------------------------
- void set(T nearPlane, T farPlane,
- T left, T right,
- T top, T bottom,
- bool ortho=false);
+ void set(T nearPlane, T farPlane,
+ T left, T right,
+ T top, T bottom,
+ bool ortho=false);
- void set(T nearPlane, T farPlane, T fovx, T fovy, T aspect);
+ void set(T nearPlane, T farPlane, T fovx, T fovy, T aspect);
//------------------------------------------------------
// These functions modify an already valid frustum state
//------------------------------------------------------
- void modifyNearAndFar(T nearPlane, T farPlane);
- void setOrthographic(bool);
+ void modifyNearAndFar(T nearPlane, T farPlane);
+ void setOrthographic(bool);
//--------------
// Access
//--------------
-
- bool orthographic() const { return _orthographic; }
- T nearPlane() const { return _nearPlane; }
- T hither() const { return _nearPlane; }
- T farPlane() const { return _farPlane; }
- T yon() const { return _farPlane; }
- T left() const { return _left; }
- T right() const { return _right; }
- T bottom() const { return _bottom; }
- T top() const { return _top; }
+
+ bool orthographic() const { return _orthographic; }
+ T nearPlane() const { return _nearPlane; }
+ T hither() const { return _nearPlane; }
+ T farPlane() const { return _farPlane; }
+ T yon() const { return _farPlane; }
+ T left() const { return _left; }
+ T right() const { return _right; }
+ T bottom() const { return _bottom; }
+ T top() const { return _top; }
//-----------------------------------------------------------------------
// Sets the planes in p to be the six bounding planes of the frustum, in
// to transform the frustum before setting the planes.
//-----------------------------------------------------------------------
- void planes(Plane3<T> p[6]);
- void planes(Plane3<T> p[6], const Matrix44<T> &M);
+ void planes(Plane3<T> p[6]) const;
+ void planes(Plane3<T> p[6], const Matrix44<T> &M) const;
//----------------------
// Derived Quantities
//----------------------
- T fovx() const;
- T fovy() const;
- T aspect() const;
- Matrix44<T> projectionMatrix() const;
- bool degenerate() const;
+ T fovx() const;
+ T fovy() const;
+ T aspect() const;
+ Matrix44<T> projectionMatrix() const;
+ bool degenerate() const;
//-----------------------------------------------------------------------
- // Takes a rectangle in the screen space (i.e., -1 <= left <= right <= 1
+ // Takes a rectangle in the screen space (i.e., -1 <= left <= right <= 1
// and -1 <= bottom <= top <= 1) of this Frustum, and returns a new
// Frustum whose near clipping-plane window is that rectangle in local
- // space.
+ // space.
//-----------------------------------------------------------------------
- Frustum<T> window(T left, T right, T top, T bottom) const;
+ Frustum<T> window(T left, T right, T top, T bottom) const;
//----------------------------------------------------------
// Projection is in screen space / Conversion from Z-Buffer
//----------------------------------------------------------
- Line3<T> projectScreenToRay( const Vec2<T> & ) const;
- Vec2<T> projectPointToScreen( const Vec3<T> & ) const;
+ Line3<T> projectScreenToRay( const Vec2<T> & ) const;
+ Vec2<T> projectPointToScreen( const Vec3<T> & ) const;
- T ZToDepth(long zval, long min, long max) const;
- T normalizedZToDepth(T zval) const;
- long DepthToZ(T depth, long zmin, long zmax) const;
+ T ZToDepth(long zval, long min, long max) const;
+ T normalizedZToDepth(T zval) const;
+ long DepthToZ(T depth, long zmin, long zmax) const;
- T worldRadius(const Vec3<T> &p, T radius) const;
- T screenRadius(const Vec3<T> &p, T radius) const;
+ T worldRadius(const Vec3<T> &p, T radius) const;
+ T screenRadius(const Vec3<T> &p, T radius) const;
protected:
- Vec2<T> screenToLocal( const Vec2<T> & ) const;
- Vec2<T> localToScreen( const Vec2<T> & ) const;
+ Vec2<T> screenToLocal( const Vec2<T> & ) const;
+ Vec2<T> localToScreen( const Vec2<T> & ) const;
protected:
- T _nearPlane;
- T _farPlane;
- T _left;
- T _right;
- T _top;
- T _bottom;
- bool _orthographic;
+ T _nearPlane;
+ T _farPlane;
+ T _left;
+ T _right;
+ T _top;
+ T _bottom;
+ bool _orthographic;
};
inline Frustum<T>::Frustum()
{
set(T (0.1),
- T (1000.0),
- T (-1.0),
- T (1.0),
- T (1.0),
- T (-1.0),
- false);
+ T (1000.0),
+ T (-1.0),
+ T (1.0),
+ T (1.0),
+ T (-1.0),
+ false);
}
template<class T>
void Frustum<T>::set(T n, T f, T l, T r, T t, T b, bool o)
{
_nearPlane = n;
- _farPlane = f;
- _left = l;
- _right = r;
- _bottom = b;
- _top = t;
+ _farPlane = f;
+ _left = l;
+ _right = r;
+ _bottom = b;
+ _top = t;
_orthographic = o;
}
{
if ( _orthographic )
{
- _nearPlane = n;
+ _nearPlane = n;
}
else
{
- Line3<T> lowerLeft( Vec3<T>(0,0,0), Vec3<T>(_left,_bottom,-_nearPlane) );
- Line3<T> upperRight( Vec3<T>(0,0,0), Vec3<T>(_right,_top,-_nearPlane) );
- Plane3<T> nearPlane( Vec3<T>(0,0,-1), n );
-
- Vec3<T> ll,ur;
- nearPlane.intersect(lowerLeft,ll);
- nearPlane.intersect(upperRight,ur);
-
- _left = ll.x;
- _right = ur.x;
- _top = ur.y;
- _bottom = ll.y;
- _nearPlane = n;
- _farPlane = f;
+ Line3<T> lowerLeft( Vec3<T>(0,0,0), Vec3<T>(_left,_bottom,-_nearPlane) );
+ Line3<T> upperRight( Vec3<T>(0,0,0), Vec3<T>(_right,_top,-_nearPlane) );
+ Plane3<T> nearPlane( Vec3<T>(0,0,-1), n );
+
+ Vec3<T> ll,ur;
+ nearPlane.intersect(lowerLeft,ll);
+ nearPlane.intersect(upperRight,ur);
+
+ _left = ll.x;
+ _right = ur.x;
+ _top = ur.y;
+ _bottom = ll.y;
+ _nearPlane = n;
+ _farPlane = f;
}
_farPlane = f;
void Frustum<T>::set(T nearPlane, T farPlane, T fovx, T fovy, T aspect)
{
if (fovx != 0 && fovy != 0)
- throw Iex::ArgExc ("fovx and fovy cannot both be non-zero.");
+ throw IEX_NAMESPACE::ArgExc ("fovx and fovy cannot both be non-zero.");
const T two = static_cast<T>(2);
if (fovx != 0)
{
- _right = nearPlane * Math<T>::tan(fovx / two);
- _left = -_right;
- _top = ((_right - _left) / aspect) / two;
- _bottom = -_top;
+ _right = nearPlane * Math<T>::tan(fovx / two);
+ _left = -_right;
+ _top = ((_right - _left) / aspect) / two;
+ _bottom = -_top;
}
else
{
- _top = nearPlane * Math<T>::tan(fovy / two);
- _bottom = -_top;
- _right = (_top - _bottom) * aspect / two;
- _left = -_right;
+ _top = nearPlane * Math<T>::tan(fovy / two);
+ _bottom = -_top;
+ _right = (_top - _bottom) * aspect / two;
+ _left = -_right;
}
- _nearPlane = nearPlane;
- _farPlane = farPlane;
- _orthographic = false;
+ _nearPlane = nearPlane;
+ _farPlane = farPlane;
+ _orthographic = false;
}
template<class T>
T topMinusBottom = _top-_bottom;
if (abs(topMinusBottom) < 1 &&
- abs(rightMinusLeft) > limits<T>::max() * abs(topMinusBottom))
+ abs(rightMinusLeft) > limits<T>::max() * abs(topMinusBottom))
{
- throw Iex::DivzeroExc ("Bad viewing frustum: "
- "aspect ratio cannot be computed.");
+ throw IEX_NAMESPACE::DivzeroExc ("Bad viewing frustum: "
+ "aspect ratio cannot be computed.");
}
return rightMinusLeft / topMinusBottom;
T farMinusNear = _farPlane-_nearPlane;
if ((abs(rightMinusLeft) < 1 &&
- abs(rightPlusLeft) > limits<T>::max() * abs(rightMinusLeft)) ||
- (abs(topMinusBottom) < 1 &&
- abs(topPlusBottom) > limits<T>::max() * abs(topMinusBottom)) ||
- (abs(farMinusNear) < 1 &&
- abs(farPlusNear) > limits<T>::max() * abs(farMinusNear)))
- {
- throw Iex::DivzeroExc ("Bad viewing frustum: "
- "projection matrix cannot be computed.");
- }
-
- if ( _orthographic )
- {
- T tx = -rightPlusLeft / rightMinusLeft;
- T ty = -topPlusBottom / topMinusBottom;
- T tz = -farPlusNear / farMinusNear;
-
- if ((abs(rightMinusLeft) < 1 &&
- 2 > limits<T>::max() * abs(rightMinusLeft)) ||
+ abs(rightPlusLeft) > limits<T>::max() * abs(rightMinusLeft)) ||
(abs(topMinusBottom) < 1 &&
- 2 > limits<T>::max() * abs(topMinusBottom)) ||
+ abs(topPlusBottom) > limits<T>::max() * abs(topMinusBottom)) ||
(abs(farMinusNear) < 1 &&
- 2 > limits<T>::max() * abs(farMinusNear)))
+ abs(farPlusNear) > limits<T>::max() * abs(farMinusNear)))
{
- throw Iex::DivzeroExc ("Bad viewing frustum: "
- "projection matrix cannot be computed.");
- }
-
- T A = 2 / rightMinusLeft;
- T B = 2 / topMinusBottom;
- T C = -2 / farMinusNear;
-
- return Matrix44<T>( A, 0, 0, 0,
- 0, B, 0, 0,
- 0, 0, C, 0,
- tx, ty, tz, 1.f );
+ throw IEX_NAMESPACE::DivzeroExc ("Bad viewing frustum: "
+ "projection matrix cannot be computed.");
}
- else
- {
- T A = rightPlusLeft / rightMinusLeft;
- T B = topPlusBottom / topMinusBottom;
- T C = -farPlusNear / farMinusNear;
- T farTimesNear = -2 * _farPlane * _nearPlane;
- if (abs(farMinusNear) < 1 &&
- abs(farTimesNear) > limits<T>::max() * abs(farMinusNear))
+ if ( _orthographic )
{
- throw Iex::DivzeroExc ("Bad viewing frustum: "
- "projection matrix cannot be computed.");
+ T tx = -rightPlusLeft / rightMinusLeft;
+ T ty = -topPlusBottom / topMinusBottom;
+ T tz = -farPlusNear / farMinusNear;
+
+ if ((abs(rightMinusLeft) < 1 &&
+ 2 > limits<T>::max() * abs(rightMinusLeft)) ||
+ (abs(topMinusBottom) < 1 &&
+ 2 > limits<T>::max() * abs(topMinusBottom)) ||
+ (abs(farMinusNear) < 1 &&
+ 2 > limits<T>::max() * abs(farMinusNear)))
+ {
+ throw IEX_NAMESPACE::DivzeroExc ("Bad viewing frustum: "
+ "projection matrix cannot be computed.");
+ }
+
+ T A = 2 / rightMinusLeft;
+ T B = 2 / topMinusBottom;
+ T C = -2 / farMinusNear;
+
+ return Matrix44<T>( A, 0, 0, 0,
+ 0, B, 0, 0,
+ 0, 0, C, 0,
+ tx, ty, tz, 1.f );
}
-
- T D = farTimesNear / farMinusNear;
-
- T twoTimesNear = 2 * _nearPlane;
-
- if ((abs(rightMinusLeft) < 1 &&
- abs(twoTimesNear) > limits<T>::max() * abs(rightMinusLeft)) ||
- (abs(topMinusBottom) < 1 &&
- abs(twoTimesNear) > limits<T>::max() * abs(topMinusBottom)))
+ else
{
- throw Iex::DivzeroExc ("Bad viewing frustum: "
- "projection matrix cannot be computed.");
- }
-
- T E = twoTimesNear / rightMinusLeft;
- T F = twoTimesNear / topMinusBottom;
-
- return Matrix44<T>( E, 0, 0, 0,
- 0, F, 0, 0,
- A, B, C, -1,
- 0, 0, D, 0 );
+ T A = rightPlusLeft / rightMinusLeft;
+ T B = topPlusBottom / topMinusBottom;
+ T C = -farPlusNear / farMinusNear;
+
+ T farTimesNear = -2 * _farPlane * _nearPlane;
+ if (abs(farMinusNear) < 1 &&
+ abs(farTimesNear) > limits<T>::max() * abs(farMinusNear))
+ {
+ throw IEX_NAMESPACE::DivzeroExc ("Bad viewing frustum: "
+ "projection matrix cannot be computed.");
+ }
+
+ T D = farTimesNear / farMinusNear;
+
+ T twoTimesNear = 2 * _nearPlane;
+
+ if ((abs(rightMinusLeft) < 1 &&
+ abs(twoTimesNear) > limits<T>::max() * abs(rightMinusLeft)) ||
+ (abs(topMinusBottom) < 1 &&
+ abs(twoTimesNear) > limits<T>::max() * abs(topMinusBottom)))
+ {
+ throw IEX_NAMESPACE::DivzeroExc ("Bad viewing frustum: "
+ "projection matrix cannot be computed.");
+ }
+
+ T E = twoTimesNear / rightMinusLeft;
+ T F = twoTimesNear / topMinusBottom;
+
+ return Matrix44<T>( E, 0, 0, 0,
+ 0, F, 0, 0,
+ A, B, C, -1,
+ 0, 0, D, 0 );
}
}
Vec2<T> Frustum<T>::screenToLocal(const Vec2<T> &s) const
{
return Vec2<T>( _left + (_right-_left) * (1.f+s.x) / 2.f,
- _bottom + (_top-_bottom) * (1.f+s.y) / 2.f );
+ _bottom + (_top-_bottom) * (1.f+s.y) / 2.f );
}
template<class T>
T bottomMinusTop = _bottom-_top;
if ((abs(leftMinusRight) < T (1) &&
- abs(leftPlusRight) > limits<T>::max() * abs(leftMinusRight)) ||
- (abs(bottomMinusTop) < T (1) &&
- abs(bottomPlusTop) > limits<T>::max() * abs(bottomMinusTop)))
+ abs(leftPlusRight) > limits<T>::max() * abs(leftMinusRight)) ||
+ (abs(bottomMinusTop) < T (1) &&
+ abs(bottomPlusTop) > limits<T>::max() * abs(bottomMinusTop)))
{
- throw Iex::DivzeroExc
- ("Bad viewing frustum: "
- "local-to-screen transformation cannot be computed");
+ throw IEX_NAMESPACE::DivzeroExc
+ ("Bad viewing frustum: "
+ "local-to-screen transformation cannot be computed");
}
return Vec2<T>( leftPlusRight / leftMinusRight,
- bottomPlusTop / bottomMinusTop );
+ bottomPlusTop / bottomMinusTop );
}
template<class T>
{
Vec2<T> point = screenToLocal(p);
if (orthographic())
- return Line3<T>( Vec3<T>(point.x,point.y, 0.0),
- Vec3<T>(point.x,point.y,-_nearPlane));
+ return Line3<T>( Vec3<T>(point.x,point.y, 0.0),
+ Vec3<T>(point.x,point.y,-1.0));
else
- return Line3<T>( Vec3<T>(0, 0, 0), Vec3<T>(point.x,point.y,-_nearPlane));
+ return Line3<T>( Vec3<T>(0, 0, 0), Vec3<T>(point.x,point.y,-_nearPlane));
}
template<class T>
Vec2<T> Frustum<T>::projectPointToScreen(const Vec3<T> &point) const
{
if (orthographic() || point.z == T (0))
- return localToScreen( Vec2<T>( point.x, point.y ) );
+ return localToScreen( Vec2<T>( point.x, point.y ) );
else
- return localToScreen( Vec2<T>( point.x * _nearPlane / -point.z,
- point.y * _nearPlane / -point.z ) );
+ return localToScreen( Vec2<T>( point.x * _nearPlane / -point.z,
+ point.y * _nearPlane / -point.z ) );
}
template<class T>
if (zdiff == 0)
{
- throw Iex::DivzeroExc
- ("Bad call to Frustum::ZToDepth: zmax == zmin");
+ throw IEX_NAMESPACE::DivzeroExc
+ ("Bad call to Frustum::ZToDepth: zmax == zmin");
}
if ( zval > zmax+1 ) zval -= zdiff;
{
return -(Zp*(_farPlane-_nearPlane) + (_farPlane+_nearPlane))/2;
}
- else
- {
- T farTimesNear = 2 * _farPlane * _nearPlane;
- T farMinusNear = Zp * (_farPlane - _nearPlane) - _farPlane - _nearPlane;
-
- if (abs(farMinusNear) < 1 &&
- abs(farTimesNear) > limits<T>::max() * abs(farMinusNear))
+ else
{
- throw Iex::DivzeroExc
- ("Frustum::normalizedZToDepth cannot be computed. The "
- "near and far clipping planes of the viewing frustum "
- "may be too close to each other");
- }
-
- return farTimesNear / farMinusNear;
+ T farTimesNear = 2 * _farPlane * _nearPlane;
+ T farMinusNear = Zp * (_farPlane - _nearPlane) - _farPlane - _nearPlane;
+
+ if (abs(farMinusNear) < 1 &&
+ abs(farTimesNear) > limits<T>::max() * abs(farMinusNear))
+ {
+ throw IEX_NAMESPACE::DivzeroExc
+ ("Frustum::normalizedZToDepth cannot be computed. The "
+ "near and far clipping planes of the viewing frustum "
+ "may be too close to each other");
+ }
+
+ return farTimesNear / farMinusNear;
}
}
if ( _orthographic )
{
- T farPlusNear = 2*depth + _farPlane + _nearPlane;
-
- if (abs(farMinusNear) < 1 &&
- abs(farPlusNear) > limits<T>::max() * abs(farMinusNear))
- {
- throw Iex::DivzeroExc
- ("Bad viewing frustum: near and far clipping planes "
- "are too close to each other");
- }
-
- T Zp = -farPlusNear/farMinusNear;
- return long(0.5*(Zp+1)*zdiff) + zmin;
- }
- else
- {
- // Perspective
-
- T farTimesNear = 2*_farPlane*_nearPlane;
- if (abs(depth) < 1 &&
- abs(farTimesNear) > limits<T>::max() * abs(depth))
- {
- throw Iex::DivzeroExc
- ("Bad call to DepthToZ function: value of `depth' "
- "is too small");
+ T farPlusNear = 2*depth + _farPlane + _nearPlane;
+
+ if (abs(farMinusNear) < 1 &&
+ abs(farPlusNear) > limits<T>::max() * abs(farMinusNear))
+ {
+ throw IEX_NAMESPACE::DivzeroExc
+ ("Bad viewing frustum: near and far clipping planes "
+ "are too close to each other");
+ }
+
+ T Zp = -farPlusNear/farMinusNear;
+ return long(0.5*(Zp+1)*zdiff) + zmin;
}
-
- T farPlusNear = farTimesNear/depth + _farPlane + _nearPlane;
- if (abs(farMinusNear) < 1 &&
- abs(farPlusNear) > limits<T>::max() * abs(farMinusNear))
- {
- throw Iex::DivzeroExc
- ("Bad viewing frustum: near and far clipping planes "
- "are too close to each other");
- }
-
- T Zp = farPlusNear/farMinusNear;
- return long(0.5*(Zp+1)*zdiff) + zmin;
+ else
+ {
+ // Perspective
+
+ T farTimesNear = 2*_farPlane*_nearPlane;
+ if (abs(depth) < 1 &&
+ abs(farTimesNear) > limits<T>::max() * abs(depth))
+ {
+ throw IEX_NAMESPACE::DivzeroExc
+ ("Bad call to DepthToZ function: value of `depth' "
+ "is too small");
+ }
+
+ T farPlusNear = farTimesNear/depth + _farPlane + _nearPlane;
+ if (abs(farMinusNear) < 1 &&
+ abs(farPlusNear) > limits<T>::max() * abs(farMinusNear))
+ {
+ throw IEX_NAMESPACE::DivzeroExc
+ ("Bad viewing frustum: near and far clipping planes "
+ "are too close to each other");
+ }
+
+ T Zp = farPlusNear/farMinusNear;
+ return long(0.5*(Zp+1)*zdiff) + zmin;
}
}
if (abs(p.z) > 1 || abs(-_nearPlane) < limits<T>::max() * abs(p.z))
{
- return radius * (-_nearPlane / p.z);
+ return radius * (-_nearPlane / p.z);
}
else
{
- throw Iex::DivzeroExc
- ("Bad call to Frustum::screenRadius: the magnitude of `p' "
- "is too small");
+ throw IEX_NAMESPACE::DivzeroExc
+ ("Bad call to Frustum::screenRadius: the magnitude of `p' "
+ "is too small");
}
return radius * (-_nearPlane / p.z);
{
if (abs(-_nearPlane) > 1 || abs(p.z) < limits<T>::max() * abs(-_nearPlane))
{
- return radius * (p.z / -_nearPlane);
+ return radius * (p.z / -_nearPlane);
}
else
{
- throw Iex::DivzeroExc
- ("Bad viewing frustum: the near clipping plane is too "
- "close to zero");
+ throw IEX_NAMESPACE::DivzeroExc
+ ("Bad viewing frustum: the near clipping plane is too "
+ "close to zero");
}
}
template<class T>
-void Frustum<T>::planes(Plane3<T> p[6])
+void Frustum<T>::planes(Plane3<T> p[6]) const
{
//
- // Plane order: Top, Right, Bottom, Left, Near, Far.
+ // Plane order: Top, Right, Bottom, Left, Near, Far.
// Normals point outwards.
//
template<class T>
-void Frustum<T>::planes(Plane3<T> p[6], const Matrix44<T> &M)
+void Frustum<T>::planes(Plane3<T> p[6], const Matrix44<T> &M) const
{
//
- // Plane order: Top, Right, Bottom, Left, Near, Far.
+ // Plane order: Top, Right, Bottom, Left, Near, Far.
// Normals point outwards.
//
}
}
-typedef Frustum<float> Frustumf;
+typedef Frustum<float> Frustumf;
typedef Frustum<double> Frustumd;
-} // namespace Imath
+IMATH_INTERNAL_NAMESPACE_HEADER_EXIT
#if defined _WIN32 || defined _WIN64
#endif
#endif
-#endif
+#endif // INCLUDED_IMATHFRUSTUM_H
///////////////////////////////////////////////////////////////////////////
//
-// Copyright (c) 2011, Industrial Light & Magic, a division of Lucas
+// Copyright (c) 2011-2012, Industrial Light & Magic, a division of Lucas
// Digital Ltd. LLC
-//
+//
// All rights reserved.
-//
+//
// Redistribution and use in source and binary forms, with or without
// modification, are permitted provided that the following conditions are
// met:
// distribution.
// * Neither the name of Industrial Light & Magic nor the names of
// its contributors may be used to endorse or promote products derived
-// from this software without specific prior written permission.
-//
+// from this software without specific prior written permission.
+//
// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
//-------------------------------------------------------------------------
//
-// This file contains algorithms applied to or in conjunction with
-// Frustum visibility testing (Imath::Frustum).
+// This file contains algorithms applied to or in conjunction with
+// Frustum visibility testing (Imath::Frustum).
//
-// Methods for frustum-based rejection of primitives are contained here.
+// Methods for frustum-based rejection of primitives are contained here.
//
//-------------------------------------------------------------------------
#include "ImathSphere.h"
#include "ImathMatrix.h"
#include "ImathVec.h"
+#include "ImathNamespace.h"
-namespace Imath {
+IMATH_INTERNAL_NAMESPACE_HEADER_ENTER
/////////////////////////////////////////////////////////////////
// FrustumTest
//
// Given that you already have:
// Imath::Frustum myFrustum
-// IMath::Matrix44 myCameraWorldMatrix
+// Imath::Matrix44 myCameraWorldMatrix
//
// First, make a frustum test object:
// FrustumTest myFrustumTest(myFrustum, myCameraWorldMatrix)
cameraMat.makeIdentity();
setFrustum(frust, cameraMat);
}
- FrustumTest(Frustum<T> &frustum, const Matrix44<T> &cameraMat)
+ FrustumTest(const Frustum<T> &frustum, const Matrix44<T> &cameraMat)
{
setFrustum(frustum, cameraMat);
}
// setFrustum()
// This updates the frustum test with a new frustum and matrix.
// This should usually be called just once per frame.
- void setFrustum(Frustum<T> &frustum, const Matrix44<T> &cameraMat);
+ void setFrustum(const Frustum<T> &frustum, const Matrix44<T> &cameraMat);
////////////////////////////////////////////////////////////////////
// isVisible()
bool isVisible(const Sphere3<T> &sphere) const;
bool isVisible(const Box<Vec3<T> > &box) const;
bool isVisible(const Vec3<T> &vec) const;
-
+
////////////////////////////////////////////////////////////////////
// completelyContains()
// Check to see if shapes are entirely contained.
bool completelyContains(const Sphere3<T> &sphere) const;
bool completelyContains(const Box<Vec3<T> > &box) const;
-
+
// These next items are kept primarily for debugging tools.
// It's useful for drawing the culling environment, and also
// for getting an "outside view" of the culling frustum.
- Imath::Matrix44<T> cameraMat() const {return cameraMatrix;}
- Imath::Frustum<T> currentFrustum() const {return currFrustum;}
+ IMATH_INTERNAL_NAMESPACE::Matrix44<T> cameraMat() const {return cameraMatrix;}
+ IMATH_INTERNAL_NAMESPACE::Frustum<T> currentFrustum() const {return currFrustum;}
protected:
// To understand why the planes are stored this way, see
// This should usually only be called once per frame, or however
// often the camera moves.
template<class T>
-void FrustumTest<T>::setFrustum(Frustum<T> &frustum,
+void FrustumTest<T>::setFrustum(const Frustum<T> &frustum,
const Matrix44<T> &cameraMat)
{
Plane3<T> frustumPlanes[6];
int index = i * 3;
planeNormX[i] = Vec3<T>(frustumPlanes[index + 0].normal.x,
- frustumPlanes[index + 1].normal.x,
+ frustumPlanes[index + 1].normal.x,
frustumPlanes[index + 2].normal.x);
planeNormY[i] = Vec3<T>(frustumPlanes[index + 0].normal.y,
frustumPlanes[index + 1].normal.y,
frustumPlanes[index + 1].normal.z,
frustumPlanes[index + 2].normal.z);
- planeNormAbsX[i] = Vec3<T>(Imath::abs(planeNormX[i].x),
- Imath::abs(planeNormX[i].y),
- Imath::abs(planeNormX[i].z));
- planeNormAbsY[i] = Vec3<T>(Imath::abs(planeNormY[i].x),
- Imath::abs(planeNormY[i].y),
- Imath::abs(planeNormY[i].z));
- planeNormAbsZ[i] = Vec3<T>(Imath::abs(planeNormZ[i].x),
- Imath::abs(planeNormZ[i].y),
- Imath::abs(planeNormZ[i].z));
+ planeNormAbsX[i] = Vec3<T>(IMATH_INTERNAL_NAMESPACE::abs(planeNormX[i].x),
+ IMATH_INTERNAL_NAMESPACE::abs(planeNormX[i].y),
+ IMATH_INTERNAL_NAMESPACE::abs(planeNormX[i].z));
+ planeNormAbsY[i] = Vec3<T>(IMATH_INTERNAL_NAMESPACE::abs(planeNormY[i].x),
+ IMATH_INTERNAL_NAMESPACE::abs(planeNormY[i].y),
+ IMATH_INTERNAL_NAMESPACE::abs(planeNormY[i].z));
+ planeNormAbsZ[i] = Vec3<T>(IMATH_INTERNAL_NAMESPACE::abs(planeNormZ[i].x),
+ IMATH_INTERNAL_NAMESPACE::abs(planeNormZ[i].y),
+ IMATH_INTERNAL_NAMESPACE::abs(planeNormZ[i].z));
planeOffsetVec[i] = Vec3<T>(frustumPlanes[index + 0].distance,
frustumPlanes[index + 1].distance,
Vec3<T> radiusVec = Vec3<T>(sphere.radius, sphere.radius, sphere.radius);
// This is a vertical dot-product on three vectors at once.
- Vec3<T> d0 = planeNormX[0] * center.x
- + planeNormY[0] * center.y
- + planeNormZ[0] * center.z
+ Vec3<T> d0 = planeNormX[0] * center.x
+ + planeNormY[0] * center.y
+ + planeNormZ[0] * center.z
- radiusVec
- planeOffsetVec[0];
if (d0.x >= 0 || d0.y >= 0 || d0.z >= 0)
return false;
- Vec3<T> d1 = planeNormX[1] * center.x
- + planeNormY[1] * center.y
- + planeNormZ[1] * center.z
+ Vec3<T> d1 = planeNormX[1] * center.x
+ + planeNormY[1] * center.y
+ + planeNormZ[1] * center.z
- radiusVec
- planeOffsetVec[1];
Vec3<T> radiusVec = Vec3<T>(sphere.radius, sphere.radius, sphere.radius);
// This is a vertical dot-product on three vectors at once.
- Vec3<T> d0 = planeNormX[0] * center.x
- + planeNormY[0] * center.y
- + planeNormZ[0] * center.z
+ Vec3<T> d0 = planeNormX[0] * center.x
+ + planeNormY[0] * center.y
+ + planeNormZ[0] * center.z
+ radiusVec
- planeOffsetVec[0];
if (d0.x >= 0 || d0.y >= 0 || d0.z >= 0)
return false;
- Vec3<T> d1 = planeNormX[1] * center.x
- + planeNormY[1] * center.y
- + planeNormZ[1] * center.z
+ Vec3<T> d1 = planeNormX[1] * center.x
+ + planeNormY[1] * center.y
+ + planeNormZ[1] * center.z
+ radiusVec
- planeOffsetVec[1];
template<typename T>
bool FrustumTest<T>::isVisible(const Box<Vec3<T> > &box) const
{
+ if (box.isEmpty())
+ return false;
+
Vec3<T> center = (box.min + box.max) / 2;
Vec3<T> extent = (box.max - center);
// This is a vertical dot-product on three vectors at once.
- Vec3<T> d0 = planeNormX[0] * center.x
- + planeNormY[0] * center.y
+ Vec3<T> d0 = planeNormX[0] * center.x
+ + planeNormY[0] * center.y
+ planeNormZ[0] * center.z
- - planeNormAbsX[0] * extent.x
- - planeNormAbsY[0] * extent.y
- - planeNormAbsZ[0] * extent.z
+ - planeNormAbsX[0] * extent.x
+ - planeNormAbsY[0] * extent.y
+ - planeNormAbsZ[0] * extent.z
- planeOffsetVec[0];
if (d0.x >= 0 || d0.y >= 0 || d0.z >= 0)
return false;
- Vec3<T> d1 = planeNormX[1] * center.x
- + planeNormY[1] * center.y
+ Vec3<T> d1 = planeNormX[1] * center.x
+ + planeNormY[1] * center.y
+ planeNormZ[1] * center.z
- - planeNormAbsX[1] * extent.x
- - planeNormAbsY[1] * extent.y
- - planeNormAbsZ[1] * extent.z
+ - planeNormAbsX[1] * extent.x
+ - planeNormAbsY[1] * extent.y
+ - planeNormAbsZ[1] * extent.z
- planeOffsetVec[1];
if (d1.x >= 0 || d1.y >= 0 || d1.z >= 0)
template<typename T>
bool FrustumTest<T>::completelyContains(const Box<Vec3<T> > &box) const
{
+ if (box.isEmpty())
+ return false;
+
Vec3<T> center = (box.min + box.max) / 2;
Vec3<T> extent = (box.max - center);
// This is a vertical dot-product on three vectors at once.
- Vec3<T> d0 = planeNormX[0] * center.x
- + planeNormY[0] * center.y
+ Vec3<T> d0 = planeNormX[0] * center.x
+ + planeNormY[0] * center.y
+ planeNormZ[0] * center.z
- + planeNormAbsX[0] * extent.x
- + planeNormAbsY[0] * extent.y
- + planeNormAbsZ[0] * extent.z
+ + planeNormAbsX[0] * extent.x
+ + planeNormAbsY[0] * extent.y
+ + planeNormAbsZ[0] * extent.z
- planeOffsetVec[0];
if (d0.x >= 0 || d0.y >= 0 || d0.z >= 0)
return false;
- Vec3<T> d1 = planeNormX[1] * center.x
- + planeNormY[1] * center.y
+ Vec3<T> d1 = planeNormX[1] * center.x
+ + planeNormY[1] * center.y
+ planeNormZ[1] * center.z
- + planeNormAbsX[1] * extent.x
- + planeNormAbsY[1] * extent.y
- + planeNormAbsZ[1] * extent.z
+ + planeNormAbsX[1] * extent.x
+ + planeNormAbsY[1] * extent.y
+ + planeNormAbsZ[1] * extent.z
- planeOffsetVec[1];
if (d1.x >= 0 || d1.y >= 0 || d1.z >= 0)
bool FrustumTest<T>::isVisible(const Vec3<T> &vec) const
{
// This is a vertical dot-product on three vectors at once.
- Vec3<T> d0 = (planeNormX[0] * vec.x)
- + (planeNormY[0] * vec.y)
- + (planeNormZ[0] * vec.z)
+ Vec3<T> d0 = (planeNormX[0] * vec.x)
+ + (planeNormY[0] * vec.y)
+ + (planeNormZ[0] * vec.z)
- planeOffsetVec[0];
if (d0.x >= 0 || d0.y >= 0 || d0.z >= 0)
return false;
- Vec3<T> d1 = (planeNormX[1] * vec.x)
- + (planeNormY[1] * vec.y)
- + (planeNormZ[1] * vec.z)
+ Vec3<T> d1 = (planeNormX[1] * vec.x)
+ + (planeNormY[1] * vec.y)
+ + (planeNormZ[1] * vec.z)
- planeOffsetVec[1];
if (d1.x >= 0 || d1.y >= 0 || d1.z >= 0)
typedef FrustumTest<float> FrustumTestf;
typedef FrustumTest<double> FrustumTestd;
-} //namespace Imath
+IMATH_INTERNAL_NAMESPACE_HEADER_EXIT
-#endif
+#endif // INCLUDED_IMATHFRUSTUMTEST_H
///////////////////////////////////////////////////////////////////////////
//
-// Copyright (c) 2002, Industrial Light & Magic, a division of Lucas
+// Copyright (c) 2002-2012, Industrial Light & Magic, a division of Lucas
// Digital Ltd. LLC
-//
+//
// All rights reserved.
-//
+//
// Redistribution and use in source and binary forms, with or without
// modification, are permitted provided that the following conditions are
// met:
// distribution.
// * Neither the name of Industrial Light & Magic nor the names of
// its contributors may be used to endorse or promote products derived
-// from this software without specific prior written permission.
-//
+// from this software without specific prior written permission.
+//
// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
#include "ImathFun.h"
-namespace Imath {
+IMATH_INTERNAL_NAMESPACE_SOURCE_ENTER
float
u.i = 0x0000000000000001LL;
}
- else if (u.i > 0)
+ else if (u.d > 0)
{
// Positive double, normalized or denormalized.
// Incrementing the largest positive double
u.i = 0x8000000000000001LL;
}
- else if (u.i > 0)
+ else if (u.d > 0)
{
// Positive double, normalized or denormalized.
}
-} // namespace Imath
+IMATH_INTERNAL_NAMESPACE_SOURCE_EXIT
///////////////////////////////////////////////////////////////////////////
//
-// Copyright (c) 2002, Industrial Light & Magic, a division of Lucas
+// Copyright (c) 2002-2012, Industrial Light & Magic, a division of Lucas
// Digital Ltd. LLC
-//
+//
// All rights reserved.
-//
+//
// Redistribution and use in source and binary forms, with or without
// modification, are permitted provided that the following conditions are
// met:
// distribution.
// * Neither the name of Industrial Light & Magic nor the names of
// its contributors may be used to endorse or promote products derived
-// from this software without specific prior written permission.
-//
+// from this software without specific prior written permission.
+//
// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
//
//-----------------------------------------------------------------------------
+#include "ImathExport.h"
#include "ImathLimits.h"
#include "ImathInt64.h"
+#include "ImathNamespace.h"
-namespace Imath {
+IMATH_INTERNAL_NAMESPACE_HEADER_ENTER
template <class T>
inline T
T n = m - a;
if (abs(d) > T(1) || abs(n) < limits<T>::max() * abs(d))
- return n / d;
+ return n / d;
return T(0);
}
inline int
cmp (T a, T b)
{
- return Imath::sign (a - b);
+ return IMATH_INTERNAL_NAMESPACE::sign (a - b);
}
inline int
cmpt (T a, T b, T t)
{
- return (Imath::abs (a - b) <= t)? 0 : cmp (a, b);
+ return (IMATH_INTERNAL_NAMESPACE::abs (a - b) <= t)? 0 : cmp (a, b);
}
inline bool
iszero (T a, T t)
{
- return (Imath::abs (a) <= t) ? 1 : 0;
+ return (IMATH_INTERNAL_NAMESPACE::abs (a) <= t) ? 1 : 0;
}
inline bool
equal (T1 a, T2 b, T3 t)
{
- return Imath::abs (a - b) <= t;
+ return IMATH_INTERNAL_NAMESPACE::abs (a - b) <= t;
}
template <class T>
divs (int x, int y)
{
return (x >= 0)? ((y >= 0)? ( x / y): -( x / -y)):
- ((y >= 0)? -(-x / y): (-x / -y));
+ ((y >= 0)? -(-x / y): (-x / -y));
}
mods (int x, int y)
{
return (x >= 0)? ((y >= 0)? ( x % y): ( x % -y)):
- ((y >= 0)? -(-x % y): -(-x % -y));
+ ((y >= 0)? -(-x % y): -(-x % -y));
}
//
// divp(x,y) == floor (double(x) / double (y))
// modp(x,y) == x - y * divp(x,y)
-//
+//
inline int
divp (int x, int y)
{
return (x >= 0)? ((y >= 0)? ( x / y): -( x / -y)):
- ((y >= 0)? -((y-1-x) / y): ((-y-1-x) / -y));
+ ((y >= 0)? -((y-1-x) / y): ((-y-1-x) / -y));
}
//
// predf(f) returns float(f-e), where e is the smallest
// positive number such that float(f-e) != f.
-//
+//
// succd(d) returns double(d+e), where e is the smallest
// positive number such that double(d+e) != d.
//
// Exceptions: If the input value is an infinity or a nan,
// succf(), predf(), succd(), and predd() all
// return the input value without changing it.
-//
+//
//----------------------------------------------------------
-float succf (float f);
-float predf (float f);
+IMATH_EXPORT float succf (float f);
+IMATH_EXPORT float predf (float f);
-double succd (double d);
-double predd (double d);
+IMATH_EXPORT double succd (double d);
+IMATH_EXPORT double predd (double d);
//
// Return true if the number is not a NaN or Infinity.
//
-inline bool
+inline bool
finitef (float f)
{
union {float f; int i;} u;
return (u.i & 0x7f800000) != 0x7f800000;
}
-inline bool
+inline bool
finited (double d)
{
union {double d; Int64 i;} u;
}
-} // namespace Imath
+IMATH_INTERNAL_NAMESPACE_HEADER_EXIT
-#endif
+#endif // INCLUDED_IMATHFUN_H
+++ /dev/null
-///////////////////////////////////////////////////////////////////////////
-//
-// Copyright (c) 2002, Industrial Light & Magic, a division of Lucas
-// Digital Ltd. LLC
-//
-// All rights reserved.
-//
-// Redistribution and use in source and binary forms, with or without
-// modification, are permitted provided that the following conditions are
-// met:
-// * Redistributions of source code must retain the above copyright
-// notice, this list of conditions and the following disclaimer.
-// * Redistributions in binary form must reproduce the above
-// copyright notice, this list of conditions and the following disclaimer
-// in the documentation and/or other materials provided with the
-// distribution.
-// * Neither the name of Industrial Light & Magic nor the names of
-// its contributors may be used to endorse or promote products derived
-// from this software without specific prior written permission.
-//
-// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
-// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
-// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
-// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
-// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
-// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
-// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
-// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
-// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
-// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
-// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
-//
-///////////////////////////////////////////////////////////////////////////
-
-
-#ifndef INCLUDED_IMATHGL_H
-#define INCLUDED_IMATHGL_H
-
-#include <GL/gl.h>
-
-#include "ImathVec.h"
-#include "ImathMatrix.h"
-#include "IexMathExc.h"
-#include "ImathFun.h"
-
-inline void glVertex ( const Imath::V3f &v ) { glVertex3f(v.x,v.y,v.z); }
-inline void glVertex ( const Imath::V2f &v ) { glVertex2f(v.x,v.y); }
-inline void glNormal ( const Imath::V3f &n ) { glNormal3f(n.x,n.y,n.z); }
-inline void glColor ( const Imath::V3f &c ) { glColor3f(c.x,c.y,c.z); }
-inline void glTranslate ( const Imath::V3f &t ) { glTranslatef(t.x,t.y,t.z); }
-
-inline void glTexCoord( const Imath::V2f &t )
-{
- glTexCoord2f(t.x,t.y);
-}
-
-inline void glDisableTexture()
-{
- glActiveTexture(GL_TEXTURE1);
- glBindTexture(GL_TEXTURE_2D, 0);
- glDisable(GL_TEXTURE_2D);
-
- glActiveTexture(GL_TEXTURE0);
-}
-
-namespace {
-
-const float GL_FLOAT_MAX = 1.8e+19; // sqrt (FLT_MAX)
-
-inline bool
-badFloat (float f)
-{
- return !Imath::finitef (f) || f < - GL_FLOAT_MAX || f > GL_FLOAT_MAX;
-}
-
-} // namespace
-
-inline void
-throwBadMatrix (const Imath::M44f& m)
-{
- if (badFloat (m[0][0]) ||
- badFloat (m[0][1]) ||
- badFloat (m[0][2]) ||
- badFloat (m[0][3]) ||
- badFloat (m[1][0]) ||
- badFloat (m[1][1]) ||
- badFloat (m[1][2]) ||
- badFloat (m[1][3]) ||
- badFloat (m[2][0]) ||
- badFloat (m[2][1]) ||
- badFloat (m[2][2]) ||
- badFloat (m[2][3]) ||
- badFloat (m[3][0]) ||
- badFloat (m[3][1]) ||
- badFloat (m[3][2]) ||
- badFloat (m[3][3]))
- throw Iex::OverflowExc ("GL matrix overflow");
-}
-
-inline void
-glMultMatrix( const Imath::M44f& m )
-{
- throwBadMatrix (m);
- glMultMatrixf( (GLfloat*)m[0] );
-}
-
-inline void
-glMultMatrix( const Imath::M44f* m )
-{
- throwBadMatrix (*m);
- glMultMatrixf( (GLfloat*)(*m)[0] );
-}
-
-inline void
-glLoadMatrix( const Imath::M44f& m )
-{
- throwBadMatrix (m);
- glLoadMatrixf( (GLfloat*)m[0] );
-}
-
-inline void
-glLoadMatrix( const Imath::M44f* m )
-{
- throwBadMatrix (*m);
- glLoadMatrixf( (GLfloat*)(*m)[0] );
-}
-
-
-namespace Imath {
-
-//
-// Class objects that push/pop the GL state. These objects assist with
-// proper cleanup of the state when exceptions are thrown.
-//
-
-class GLPushMatrix {
- public:
-
- GLPushMatrix () { glPushMatrix(); }
- ~GLPushMatrix() { glPopMatrix(); }
-};
-
-class GLPushAttrib {
- public:
-
- GLPushAttrib (GLbitfield mask) { glPushAttrib (mask); }
- ~GLPushAttrib() { glPopAttrib(); }
-};
-
-class GLBegin {
- public:
-
- GLBegin (GLenum mode) { glBegin (mode); }
- ~GLBegin() { glEnd(); }
-};
-
-} // namespace Imath
-
-#endif
///////////////////////////////////////////////////////////////////////////
//
-// Copyright (c) 2002, Industrial Light & Magic, a division of Lucas
+// Copyright (c) 2002-2012, Industrial Light & Magic, a division of Lucas
// Digital Ltd. LLC
-//
+//
// All rights reserved.
-//
+//
// Redistribution and use in source and binary forms, with or without
// modification, are permitted provided that the following conditions are
// met:
// distribution.
// * Neither the name of Industrial Light & Magic nor the names of
// its contributors may be used to endorse or promote products derived
-// from this software without specific prior written permission.
-//
+// from this software without specific prior written permission.
+//
// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
//--------------------------------------------------
#include "ImathLimits.h"
+#include "ImathNamespace.h"
+
#include "half.h"
-namespace Imath {
+IMATH_INTERNAL_NAMESPACE_HEADER_ENTER
template <>
};
-} // namespace Imath
+IMATH_INTERNAL_NAMESPACE_HEADER_EXIT
-#endif
+#endif // INCLUDED_IMATHHALFLIMITS_H
///////////////////////////////////////////////////////////////////////////
//
-// Copyright (c) 2006, Industrial Light & Magic, a division of Lucas
+// Copyright (c) 2006-2012, Industrial Light & Magic, a division of Lucas
// Digital Ltd. LLC
-//
+//
// All rights reserved.
-//
+//
// Redistribution and use in source and binary forms, with or without
// modification, are permitted provided that the following conditions are
// met:
// distribution.
// * Neither the name of Industrial Light & Magic nor the names of
// its contributors may be used to endorse or promote products derived
-// from this software without specific prior written permission.
-//
+// from this software without specific prior written permission.
+//
// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
//
//----------------------------------------------------------------------------
+#include "ImathNamespace.h"
#include <limits.h>
-namespace Imath {
+IMATH_INTERNAL_NAMESPACE_HEADER_ENTER
#if (defined _WIN32 || defined _WIN64) && _MSC_VER >= 1300
typedef unsigned __int64 Int64;
+ typedef __int64 SInt64;
#elif ULONG_MAX == 18446744073709551615LU
typedef long unsigned int Int64;
+ typedef long int SInt64;
#else
typedef long long unsigned int Int64;
+ typedef long long int SInt64;
#endif
-} // namespace Imath
+IMATH_INTERNAL_NAMESPACE_HEADER_EXIT
-#endif
+#endif // INCLUDED_IMATH_INT64_H
///////////////////////////////////////////////////////////////////////////
//
-// Copyright (c) 2002, Industrial Light & Magic, a division of Lucas
+// Copyright (c) 2002-2012, Industrial Light & Magic, a division of Lucas
// Digital Ltd. LLC
-//
+//
// All rights reserved.
-//
+//
// Redistribution and use in source and binary forms, with or without
// modification, are permitted provided that the following conditions are
// met:
// distribution.
// * Neither the name of Industrial Light & Magic nor the names of
// its contributors may be used to endorse or promote products derived
-// from this software without specific prior written permission.
-//
+// from this software without specific prior written permission.
+//
// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
//-------------------------------------------------------------------
#include "ImathVec.h"
+#include "ImathNamespace.h"
-namespace Imath {
+IMATH_INTERNAL_NAMESPACE_HEADER_ENTER
-template <class T>
+template <class T>
class Interval
{
public:
// Constructors - an "empty" Interval is created by default
//-----------------------------------------------------
- Interval();
+ Interval();
Interval(const T& point);
Interval(const T& minT, const T& maxT);
//--------------------------------
// Operators: we get != from STL
//--------------------------------
-
+
bool operator == (const Interval<T> &src) const;
//------------------
Interval<T>::extendBy(const T& point)
{
if ( point < min )
- min = point;
-
+ min = point;
+
if ( point > max )
- max = point;
+ max = point;
}
template <class T>
Interval<T>::extendBy(const Interval<T>& interval)
{
if ( interval.min < min )
- min = interval.min;
+ min = interval.min;
if ( interval.max > max )
- max = interval.max;
+ max = interval.max;
}
template <class T>
return interval.max >= min && interval.min <= max;
}
-template <class T>
+template <class T>
inline T
-Interval<T>::size() const
-{
+Interval<T>::size() const
+{
return max-min;
}
-template <class T>
+template <class T>
inline T
-Interval<T>::center() const
-{
+Interval<T>::center() const
+{
return (max+min)/2;
}
return max > min;
}
-} // namespace Imath
-#endif
+IMATH_INTERNAL_NAMESPACE_HEADER_EXIT
+
+#endif // INCLUDED_IMATHINTERVAL_H
///////////////////////////////////////////////////////////////////////////
//
-// Copyright (c) 2002, Industrial Light & Magic, a division of Lucas
+// Copyright (c) 2002-2012, Industrial Light & Magic, a division of Lucas
// Digital Ltd. LLC
-//
+//
// All rights reserved.
-//
+//
// Redistribution and use in source and binary forms, with or without
// modification, are permitted provided that the following conditions are
// met:
// distribution.
// * Neither the name of Industrial Light & Magic nor the names of
// its contributors may be used to endorse or promote products derived
-// from this software without specific prior written permission.
-//
+// from this software without specific prior written permission.
+//
// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
//
//----------------------------------------------------------------
+#include "ImathNamespace.h"
#include <float.h>
#include <limits.h>
#endif
#endif
-namespace Imath {
+IMATH_INTERNAL_NAMESPACE_HEADER_ENTER
//-----------------------------------------------------------------
};
-} // namespace Imath
+IMATH_INTERNAL_NAMESPACE_HEADER_EXIT
-#endif
+#endif // INCLUDED_IMATHLIMITS_H
///////////////////////////////////////////////////////////////////////////
//
-// Copyright (c) 2002, Industrial Light & Magic, a division of Lucas
+// Copyright (c) 2002-2012, Industrial Light & Magic, a division of Lucas
// Digital Ltd. LLC
-//
+//
// All rights reserved.
-//
+//
// Redistribution and use in source and binary forms, with or without
// modification, are permitted provided that the following conditions are
// met:
// distribution.
// * Neither the name of Industrial Light & Magic nor the names of
// its contributors may be used to endorse or promote products derived
-// from this software without specific prior written permission.
-//
+// from this software without specific prior written permission.
+//
// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
#include "ImathVec.h"
#include "ImathLimits.h"
#include "ImathMatrix.h"
+#include "ImathNamespace.h"
-namespace Imath {
+IMATH_INTERNAL_NAMESPACE_HEADER_ENTER
template <class T>
Vec3<T> pos;
Vec3<T> dir;
-
+
//-------------------------------------------------------------
// Constructors - default is normalized units along direction
//-------------------------------------------------------------
// State Query/Set
//------------------
- void set(const Vec3<T>& point1,
- const Vec3<T>& point2);
+ void set(const Vec3<T>& point1,
+ const Vec3<T>& point2);
//-------
// F(t)
}
template <class T>
-inline Vec3<T>
+inline Vec3<T>
Line3<T>::closestPointTo(const Line3<T>& line) const
{
// Assumes the lines are normalized
if (absDenom < 1)
{
- T absNum = ((num >= 0)? num: -num);
+ T absNum = ((num >= 0)? num: -num);
- if (absNum >= absDenom * limits<T>::max())
- return pos;
+ if (absNum >= absDenom * limits<T>::max())
+ return pos;
}
return pos + dir * (num / denom);
}
-} // namespace Imath
+IMATH_INTERNAL_NAMESPACE_HEADER_EXIT
-#endif
+#endif // INCLUDED_IMATHLINE_H
///////////////////////////////////////////////////////////////////////////
//
-// Copyright (c) 2002, Industrial Light & Magic, a division of Lucas
+// Copyright (c) 2002-2012, Industrial Light & Magic, a division of Lucas
// Digital Ltd. LLC
-//
+//
// All rights reserved.
-//
+//
// Redistribution and use in source and binary forms, with or without
// modification, are permitted provided that the following conditions are
// met:
// distribution.
// * Neither the name of Industrial Light & Magic nor the names of
// its contributors may be used to endorse or promote products derived
-// from this software without specific prior written permission.
-//
+// from this software without specific prior written permission.
+//
// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
#include "ImathLine.h"
#include "ImathVecAlgo.h"
#include "ImathFun.h"
+#include "ImathNamespace.h"
-namespace Imath {
+IMATH_INTERNAL_NAMESPACE_HEADER_ENTER
template <class T>
T absD = abs (d);
if ((absD > 1) ||
- (abs (n1) < limits<T>::max() * absD &&
- abs (n2) < limits<T>::max() * absD))
+ (abs (n1) < limits<T>::max() * absD &&
+ abs (n2) < limits<T>::max() * absD))
{
- point1 = line1 (n1 / d);
- point2 = line2 (n2 / d);
- return true;
+ point1 = line1 (n1 / d);
+ point2 = line2 (n2 / d);
+ return true;
}
else
{
- return false;
+ return false;
}
}
T l = normal.length();
if (l != 0)
- normal /= l;
+ normal /= l;
else
- return false; // zero-area triangle
+ return false; // zero-area triangle
//
// d is the distance of line.pos from the plane that contains the triangle.
T nd = normal ^ line.dir;
if (abs (nd) > 1 || abs (d) < limits<T>::max() * abs (nd))
- pt = line (d / nd);
+ pt = line (d / nd);
else
- return false; // line and plane are nearly parallel
+ return false; // line and plane are nearly parallel
//
// Compute the barycentric coordinates of the intersection point.
//
{
- Vec3<T> en = edge0.normalized();
- Vec3<T> a = pt - v0;
- Vec3<T> b = v2 - v0;
- Vec3<T> c = (a - en * (en ^ a));
- Vec3<T> d = (b - en * (en ^ b));
- T e = c ^ d;
- T f = d ^ d;
-
- if (e >= 0 && e <= f)
- barycentric.z = e / f;
- else
- return false; // outside
+ Vec3<T> en = edge0.normalized();
+ Vec3<T> a = pt - v0;
+ Vec3<T> b = v2 - v0;
+ Vec3<T> c = (a - en * (en ^ a));
+ Vec3<T> d = (b - en * (en ^ b));
+ T e = c ^ d;
+ T f = d ^ d;
+
+ if (e >= 0 && e <= f)
+ barycentric.z = e / f;
+ else
+ return false; // outside
}
{
- Vec3<T> en = edge1.normalized();
- Vec3<T> a = pt - v1;
- Vec3<T> b = v0 - v1;
- Vec3<T> c = (a - en * (en ^ a));
- Vec3<T> d = (b - en * (en ^ b));
- T e = c ^ d;
- T f = d ^ d;
-
- if (e >= 0 && e <= f)
- barycentric.x = e / f;
- else
- return false; // outside
+ Vec3<T> en = edge1.normalized();
+ Vec3<T> a = pt - v1;
+ Vec3<T> b = v0 - v1;
+ Vec3<T> c = (a - en * (en ^ a));
+ Vec3<T> d = (b - en * (en ^ b));
+ T e = c ^ d;
+ T f = d ^ d;
+
+ if (e >= 0 && e <= f)
+ barycentric.x = e / f;
+ else
+ return false; // outside
}
barycentric.y = 1 - barycentric.x - barycentric.z;
if (barycentric.y < 0)
- return false; // outside
+ return false; // outside
front = ((line.dir ^ normal) < 0);
return true;
{
Vec3<T> nearest = v0;
T neardot = (v0 - l.closestPointTo(v0)).length2();
-
+
T tmp = (v1 - l.closestPointTo(v1)).length2();
if (tmp < neardot)
T cosangle = Math<T>::cos(angle);
T sinangle = Math<T>::sin(angle);
- Vec3<T> r = q + x * radius * cosangle + y * radius * sinangle;
+ Vec3<T> r = q + x * radius * cosangle + y * radius * sinangle;
return r;
}
-} // namespace Imath
+IMATH_INTERNAL_NAMESPACE_HEADER_EXIT
-#endif
+#endif // INCLUDED_IMATHLINEALGO_H
///////////////////////////////////////////////////////////////////////////
//
-// Copyright (c) 2002, Industrial Light & Magic, a division of Lucas
+// Copyright (c) 2002-2012, Industrial Light & Magic, a division of Lucas
// Digital Ltd. LLC
-//
+//
// All rights reserved.
-//
+//
// Redistribution and use in source and binary forms, with or without
// modification, are permitted provided that the following conditions are
// met:
// distribution.
// * Neither the name of Industrial Light & Magic nor the names of
// its contributors may be used to endorse or promote products derived
-// from this software without specific prior written permission.
-//
+// from this software without specific prior written permission.
+//
// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
#include "ImathPlatform.h"
#include "ImathLimits.h"
+#include "ImathNamespace.h"
#include <math.h>
-namespace Imath {
+IMATH_INTERNAL_NAMESPACE_HEADER_ENTER
template <class T>
struct Math
{
- static T acos (T x) {return ::acos (double(x));}
+ static T acos (T x) {return ::acos (double(x));}
static T asin (T x) {return ::asin (double(x));}
static T atan (T x) {return ::atan (double(x));}
static T atan2 (T x, T y) {return ::atan2 (double(x), double(y));}
{
double ival;
T rval( ::modf (double(x),&ival));
- *iptr = ival;
- return rval;
+ *iptr = ival;
+ return rval;
}
static T pow (T x, T y) {return ::pow (double(x), double(y));}
static T sqrt (T x) {return ::sqrt (double(x));}
template <>
struct Math<float>
{
- static float acos (float x) {return ::acosf (x);}
+ static float acos (float x) {return ::acosf (x);}
static float asin (float x) {return ::asinf (x);}
static float atan (float x) {return ::atanf (x);}
static float atan2 (float x, float y) {return ::atan2f (x, y);}
sinx_over_x (T x)
{
if (x * x < limits<T>::epsilon())
- return T (1);
+ return T (1);
else
- return Math<T>::sin (x) / x;
+ return Math<T>::sin (x) / x;
}
//
// Returns true if x1 is the same as x2 with an absolute error of
// no more than e,
-//
+//
// abs (x1 - x2) <= e
//
// equalWithRelError (x1, x2, e)
//
// Returns true if x1 is the same as x2 with an relative error of
// no more than e,
-//
+//
// abs (x1 - x2) <= e * x1
//
//--------------------------------------------------------------------------
}
+IMATH_INTERNAL_NAMESPACE_HEADER_EXIT
-} // namespace Imath
-
-#endif
+#endif // INCLUDED_IMATHMATH_H
///////////////////////////////////////////////////////////////////////////
//
-// Copyright (c) 2002, Industrial Light & Magic, a division of Lucas
+// Copyright (c) 2002-2012, Industrial Light & Magic, a division of Lucas
// Digital Ltd. LLC
-//
+//
// All rights reserved.
-//
+//
// Redistribution and use in source and binary forms, with or without
// modification, are permitted provided that the following conditions are
// met:
// distribution.
// * Neither the name of Industrial Light & Magic nor the names of
// its contributors may be used to endorse or promote products derived
-// from this software without specific prior written permission.
-//
+// from this software without specific prior written permission.
+//
// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
#include "ImathExc.h"
#include "ImathVec.h"
#include "ImathShear.h"
+#include "ImathNamespace.h"
#include <cstring>
#include <iostream>
#endif
-namespace Imath {
+IMATH_INTERNAL_NAMESPACE_HEADER_ENTER
enum Uninitialized {UNINITIALIZED};
//----------------------
// Compatibility with Sb
//----------------------
-
+
T * getValue ();
const T * getValue () const;
// inverse() and invert() are significantly faster than
// gjInverse() and gjInvert(), but the results may be slightly
// less accurate.
- //
+ //
//------------------------------------------------------------
- const Matrix33 & invert (bool singExc = false)
- throw (Iex::MathExc);
+ const Matrix33 & invert (bool singExc = false);
- Matrix33<T> inverse (bool singExc = false) const
- throw (Iex::MathExc);
+ Matrix33<T> inverse (bool singExc = false) const;
- const Matrix33 & gjInvert (bool singExc = false)
- throw (Iex::MathExc);
+ const Matrix33 & gjInvert (bool singExc = false);
- Matrix33<T> gjInverse (bool singExc = false) const
- throw (Iex::MathExc);
+ Matrix33<T> gjInverse (bool singExc = false) const;
//------------------------------------------------
// Build a minor using the specified rows and columns
//---------------------------------------------------
- T fastMinor (const int r0, const int r1,
+ T fastMinor (const int r0, const int r1,
const int c0, const int c1) const;
//------------
//----------------------
// Compatibility with Sb
//----------------------
-
+
T * getValue ();
const T * getValue () const;
// inverse() and invert() are significantly faster than
// gjInverse() and gjInvert(), but the results may be slightly
// less accurate.
- //
+ //
//------------------------------------------------------------
- const Matrix44 & invert (bool singExc = false)
- throw (Iex::MathExc);
+ const Matrix44 & invert (bool singExc = false);
- Matrix44<T> inverse (bool singExc = false) const
- throw (Iex::MathExc);
+ Matrix44<T> inverse (bool singExc = false) const;
- const Matrix44 & gjInvert (bool singExc = false)
- throw (Iex::MathExc);
+ const Matrix44 & gjInvert (bool singExc = false);
- Matrix44<T> gjInverse (bool singExc = false) const
- throw (Iex::MathExc);
+ Matrix44<T> gjInverse (bool singExc = false) const;
//------------------------------------------------
// Set matrix to shear by given factors. The resulting matrix
// will shear x for each y coord. by a factor of h.xy ;
// will shear x for each z coord. by a factor of h.xz ;
- // will shear y for each z coord. by a factor of h.yz ;
+ // will shear y for each z coord. by a factor of h.yz ;
// will shear y for each x coord. by a factor of h.yx ;
// will shear z for each x coord. by a factor of h.zx ;
// will shear z for each y coord. by a factor of h.zy .
//--------------------------------------------------------
- // Shear the matrix by given vector. The composed matrix
+ // Shear the matrix by given vector. The composed matrix
// will be <shear> * <this>, where the shear matrix ...
// will shear x for each y coord. by a factor of h[0] ;
// will shear x for each z coord. by a factor of h[1] ;
//------------------------------------------------------------
- // Shear the matrix by the given factors. The composed matrix
+ // Shear the matrix by the given factors. The composed matrix
// will be <shear> * <this>, where the shear matrix ...
// will shear x for each y coord. by a factor of h.xy ;
// will shear x for each z coord. by a factor of h.xz ;
//--------------
template <class T>
-std::ostream & operator << (std::ostream & s, const Matrix33<T> &m);
+std::ostream & operator << (std::ostream & s, const Matrix33<T> &m);
template <class T>
-std::ostream & operator << (std::ostream & s, const Matrix44<T> &m);
+std::ostream & operator << (std::ostream & s, const Matrix44<T> &m);
//---------------------------------------------
template <class T>
inline
-Matrix33<T>::Matrix33 (const T a[3][3])
+Matrix33<T>::Matrix33 (const T a[3][3])
{
memcpy (x, a, sizeof (x));
}
{
for (int i = 0; i < 3; i++)
for (int j = 0; j < 3; j++)
- if (!Imath::equalWithAbsError ((*this)[i][j], m[i][j], e))
+ if (!IMATH_INTERNAL_NAMESPACE::equalWithAbsError ((*this)[i][j], m[i][j], e))
return false;
return true;
{
for (int i = 0; i < 3; i++)
for (int j = 0; j < 3; j++)
- if (!Imath::equalWithRelError ((*this)[i][j], m[i][j], e))
+ if (!IMATH_INTERNAL_NAMESPACE::equalWithRelError ((*this)[i][j], m[i][j], e))
return false;
return true;
x[2][0] += a;
x[2][1] += a;
x[2][2] += a;
-
+
return *this;
}
x[2][0] -= v.x[2][0];
x[2][1] -= v.x[2][1];
x[2][2] -= v.x[2][2];
-
+
return *this;
}
x[2][0] -= a;
x[2][1] -= a;
x[2][2] -= a;
-
+
return *this;
}
x[2][0] *= a;
x[2][1] *= a;
x[2][2] *= a;
-
+
return *this;
}
x[2][0] /= a;
x[2][1] /= a;
x[2][2] /= a;
-
+
return *this;
}
template <class T>
const Matrix33<T> &
-Matrix33<T>::gjInvert (bool singExc) throw (Iex::MathExc)
+Matrix33<T>::gjInvert (bool singExc)
{
*this = gjInverse (singExc);
return *this;
template <class T>
Matrix33<T>
-Matrix33<T>::gjInverse (bool singExc) const throw (Iex::MathExc)
+Matrix33<T>::gjInverse (bool singExc) const
{
int i, j, k;
Matrix33 s;
if (pivotsize == 0)
{
if (singExc)
- throw ::Imath::SingMatrixExc ("Cannot invert singular matrix.");
+ throw ::IMATH_INTERNAL_NAMESPACE::SingMatrixExc ("Cannot invert singular matrix.");
return Matrix33();
}
if ((f = t[i][i]) == 0)
{
if (singExc)
- throw ::Imath::SingMatrixExc ("Cannot invert singular matrix.");
+ throw ::IMATH_INTERNAL_NAMESPACE::SingMatrixExc ("Cannot invert singular matrix.");
return Matrix33();
}
template <class T>
const Matrix33<T> &
-Matrix33<T>::invert (bool singExc) throw (Iex::MathExc)
+Matrix33<T>::invert (bool singExc)
{
*this = inverse (singExc);
return *this;
template <class T>
Matrix33<T>
-Matrix33<T>::inverse (bool singExc) const throw (Iex::MathExc)
+Matrix33<T>::inverse (bool singExc) const
{
if (x[0][2] != 0 || x[1][2] != 0 || x[2][2] != 1)
{
T r = x[0][0] * s[0][0] + x[0][1] * s[1][0] + x[0][2] * s[2][0];
- if (Imath::abs (r) >= 1)
+ if (IMATH_INTERNAL_NAMESPACE::abs (r) >= 1)
{
for (int i = 0; i < 3; ++i)
{
}
else
{
- T mr = Imath::abs (r) / limits<T>::smallest();
+ T mr = IMATH_INTERNAL_NAMESPACE::abs (r) / limits<T>::smallest();
for (int i = 0; i < 3; ++i)
{
for (int j = 0; j < 3; ++j)
{
- if (mr > Imath::abs (s[i][j]))
+ if (mr > IMATH_INTERNAL_NAMESPACE::abs (s[i][j]))
{
s[i][j] /= r;
}
{
Matrix33 s ( x[1][1],
-x[0][1],
- 0,
+ 0,
-x[1][0],
x[0][0],
T r = x[0][0] * x[1][1] - x[1][0] * x[0][1];
- if (Imath::abs (r) >= 1)
+ if (IMATH_INTERNAL_NAMESPACE::abs (r) >= 1)
{
for (int i = 0; i < 2; ++i)
{
}
else
{
- T mr = Imath::abs (r) / limits<T>::smallest();
+ T mr = IMATH_INTERNAL_NAMESPACE::abs (r) / limits<T>::smallest();
for (int i = 0; i < 2; ++i)
{
for (int j = 0; j < 2; ++j)
{
- if (mr > Imath::abs (s[i][j]))
+ if (mr > IMATH_INTERNAL_NAMESPACE::abs (s[i][j]))
{
s[i][j] /= r;
}
}
template <class T>
-inline Vec2<T>
+inline Vec2<T>
Matrix33<T>::translation () const
{
return Vec2<T> (x[2][0], x[2][1]);
Matrix33<T>::shear (const S &xy)
{
//
- // In this case, we don't need a temp. copy of the matrix
- // because we never use a value on the RHS after we've
+ // In this case, we don't need a temp. copy of the matrix
+ // because we never use a value on the RHS after we've
// changed it on the LHS.
- //
+ //
x[1][0] += xy * x[0][0];
x[1][1] += xy * x[0][1];
Matrix33<T>::shear (const Vec2<S> &h)
{
Matrix33<T> P (*this);
-
+
x[0][0] = P[0][0] + h[1] * P[1][0];
x[0][1] = P[0][1] + h[1] * P[1][1];
x[0][2] = P[0][2] + h[1] * P[1][2];
-
+
x[1][0] = P[1][0] + h[0] * P[0][0];
x[1][1] = P[1][1] + h[0] * P[0][1];
x[1][2] = P[1][2] + h[0] * P[0][2];
template <class T>
inline
-Matrix44<T>::Matrix44 (const T a[4][4])
+Matrix44<T>::Matrix44 (const T a[4][4])
{
memcpy (x, a, sizeof (x));
}
{
for (int i = 0; i < 4; i++)
for (int j = 0; j < 4; j++)
- if (!Imath::equalWithAbsError ((*this)[i][j], m[i][j], e))
+ if (!IMATH_INTERNAL_NAMESPACE::equalWithAbsError ((*this)[i][j], m[i][j], e))
return false;
return true;
{
for (int i = 0; i < 4; i++)
for (int j = 0; j < 4; j++)
- if (!Imath::equalWithRelError ((*this)[i][j], m[i][j], e))
+ if (!IMATH_INTERNAL_NAMESPACE::equalWithRelError ((*this)[i][j], m[i][j], e))
return false;
return true;
const Matrix44<T> &b,
Matrix44<T> &c)
{
- register const T * IMATH_RESTRICT ap = &a.x[0][0];
- register const T * IMATH_RESTRICT bp = &b.x[0][0];
- register T * IMATH_RESTRICT cp = &c.x[0][0];
+ const T * IMATH_RESTRICT ap = &a.x[0][0];
+ const T * IMATH_RESTRICT bp = &b.x[0][0];
+ T * IMATH_RESTRICT cp = &c.x[0][0];
- register T a0, a1, a2, a3;
+ T a0, a1, a2, a3;
a0 = ap[0];
a1 = ap[1];
template <class T>
const Matrix44<T> &
-Matrix44<T>::gjInvert (bool singExc) throw (Iex::MathExc)
+Matrix44<T>::gjInvert (bool singExc)
{
*this = gjInverse (singExc);
return *this;
template <class T>
Matrix44<T>
-Matrix44<T>::gjInverse (bool singExc) const throw (Iex::MathExc)
+Matrix44<T>::gjInverse (bool singExc) const
{
int i, j, k;
Matrix44 s;
if (pivotsize == 0)
{
if (singExc)
- throw ::Imath::SingMatrixExc ("Cannot invert singular matrix.");
+ throw ::IMATH_INTERNAL_NAMESPACE::SingMatrixExc ("Cannot invert singular matrix.");
return Matrix44();
}
if ((f = t[i][i]) == 0)
{
if (singExc)
- throw ::Imath::SingMatrixExc ("Cannot invert singular matrix.");
+ throw ::IMATH_INTERNAL_NAMESPACE::SingMatrixExc ("Cannot invert singular matrix.");
return Matrix44();
}
template <class T>
const Matrix44<T> &
-Matrix44<T>::invert (bool singExc) throw (Iex::MathExc)
+Matrix44<T>::invert (bool singExc)
{
*this = inverse (singExc);
return *this;
template <class T>
Matrix44<T>
-Matrix44<T>::inverse (bool singExc) const throw (Iex::MathExc)
+Matrix44<T>::inverse (bool singExc) const
{
if (x[0][3] != 0 || x[1][3] != 0 || x[2][3] != 0 || x[3][3] != 1)
return gjInverse(singExc);
T r = x[0][0] * s[0][0] + x[0][1] * s[1][0] + x[0][2] * s[2][0];
- if (Imath::abs (r) >= 1)
+ if (IMATH_INTERNAL_NAMESPACE::abs (r) >= 1)
{
for (int i = 0; i < 3; ++i)
{
}
else
{
- T mr = Imath::abs (r) / limits<T>::smallest();
+ T mr = IMATH_INTERNAL_NAMESPACE::abs (r) / limits<T>::smallest();
for (int i = 0; i < 3; ++i)
{
for (int j = 0; j < 3; ++j)
{
- if (mr > Imath::abs (s[i][j]))
+ if (mr > IMATH_INTERNAL_NAMESPACE::abs (s[i][j]))
{
s[i][j] /= r;
}
Matrix44<T>::setEulerAngles (const Vec3<S>& r)
{
S cos_rz, sin_rz, cos_ry, sin_ry, cos_rx, sin_rx;
-
+
cos_rz = Math<T>::cos (r[2]);
cos_ry = Math<T>::cos (r[1]);
cos_rx = Math<T>::cos (r[0]);
-
+
sin_rz = Math<T>::sin (r[2]);
sin_ry = Math<T>::sin (r[1]);
sin_rx = Math<T>::sin (r[0]);
-
+
x[0][0] = cos_rz * cos_ry;
x[0][1] = sin_rz * cos_ry;
x[0][2] = -sin_ry;
x[0][3] = 0;
-
+
x[1][0] = -sin_rz * cos_rx + cos_rz * sin_ry * sin_rx;
x[1][1] = cos_rz * cos_rx + sin_rz * sin_ry * sin_rx;
x[1][2] = cos_ry * sin_rx;
x[1][3] = 0;
-
+
x[2][0] = sin_rz * sin_rx + cos_rz * sin_ry * cos_rx;
x[2][1] = -cos_rz * sin_rx + sin_rz * sin_ry * cos_rx;
x[2][2] = cos_ry * cos_rx;
cos_rz = Math<S>::cos (r[2]);
cos_ry = Math<S>::cos (r[1]);
cos_rx = Math<S>::cos (r[0]);
-
+
sin_rz = Math<S>::sin (r[2]);
sin_ry = Math<S>::sin (r[1]);
sin_rx = Math<S>::sin (r[0]);
Matrix44<T>::shear (const Vec3<S> &h)
{
//
- // In this case, we don't need a temp. copy of the matrix
- // because we never use a value on the RHS after we've
+ // In this case, we don't need a temp. copy of the matrix
+ // because we never use a value on the RHS after we've
// changed it on the LHS.
- //
+ //
for (int i=0; i < 4; i++)
{
if (s.flags() & std::ios_base::fixed)
{
s.setf (std::ios_base::showpoint);
- width = s.precision() + 5;
+ width = static_cast<int>(s.precision()) + 5;
}
else
{
s.setf (std::ios_base::scientific);
s.setf (std::ios_base::showpoint);
- width = s.precision() + 8;
+ width = static_cast<int>(s.precision()) + 8;
}
s << "(" << std::setw (width) << m[0][0] <<
if (s.flags() & std::ios_base::fixed)
{
s.setf (std::ios_base::showpoint);
- width = s.precision() + 5;
+ width = static_cast<int>(s.precision()) + 5;
}
else
{
s.setf (std::ios_base::scientific);
s.setf (std::ios_base::showpoint);
- width = s.precision() + 8;
+ width = static_cast<int>(s.precision()) + 8;
}
s << "(" << std::setw (width) << m[0][0] <<
return Vec4<S> (x, y, z, w);
}
-} // namespace Imath
+IMATH_INTERNAL_NAMESPACE_HEADER_EXIT
-
-
-#endif
+#endif // INCLUDED_IMATHMATRIX_H
///////////////////////////////////////////////////////////////////////////
//
-// Copyright (c) 2002, Industrial Light & Magic, a division of Lucas
+// Copyright (c) 2002-2012, Industrial Light & Magic, a division of Lucas
// Digital Ltd. LLC
-//
+//
// All rights reserved.
-//
+//
// Redistribution and use in source and binary forms, with or without
// modification, are permitted provided that the following conditions are
// met:
// distribution.
// * Neither the name of Industrial Light & Magic nor the names of
// its contributors may be used to endorse or promote products derived
-// from this software without specific prior written permission.
-//
+// from this software without specific prior written permission.
+//
// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
#include "ImathMatrixAlgo.h"
#include <cmath>
-#include <algorithm> // for std::max()
+#include <algorithm>
#if defined(OPENEXR_DLL)
#define EXPORT_CONST __declspec(dllexport)
#define EXPORT_CONST const
#endif
-namespace Imath {
+IMATH_INTERNAL_NAMESPACE_SOURCE_ENTER
EXPORT_CONST M33f identity33f ( 1, 0, 0,
- 0, 1, 0,
- 0, 0, 1);
+ 0, 1, 0,
+ 0, 0, 1);
EXPORT_CONST M33d identity33d ( 1, 0, 0,
- 0, 1, 0,
- 0, 0, 1);
+ 0, 1, 0,
+ 0, 0, 1);
EXPORT_CONST M44f identity44f ( 1, 0, 0, 0,
- 0, 1, 0, 0,
- 0, 0, 1, 0,
- 0, 0, 0, 1);
+ 0, 1, 0, 0,
+ 0, 0, 1, 0,
+ 0, 0, 0, 1);
EXPORT_CONST M44d identity44d ( 1, 0, 0, 0,
- 0, 1, 0, 0,
- 0, 0, 1, 0,
- 0, 0, 0, 1);
+ 0, 1, 0, 0,
+ 0, 0, 1, 0,
+ 0, 0, 0, 1);
namespace
{
M33d U, V;
V3d S;
- jacobiSVD (C, U, S, V, Imath::limits<double>::epsilon(), true);
+ jacobiSVD (C, U, S, V, IMATH_INTERNAL_NAMESPACE::limits<double>::epsilon(), true);
// We want Q.transposed() here since we are going to be using it in the
// Imath style (multiplying vectors on the right, v' = v*A^T):
if (doScale && numPoints > 1)
{
// Finding a uniform scale: let us assume the Q is completely fixed
- // at this point (solving for both simultaneously seems much harder).
+ // at this point (solving for both simultaneously seems much harder).
// We are trying to compute (again, per Golub and van Loan)
// min || s*A*Q - B ||_F
- // Notice that we've jammed a uniform scale in front of the Q.
+ // Notice that we've jammed a uniform scale in front of the Q.
// Now, the Frobenius norm (the least squares norm over matrices)
// has the neat property that it is equivalent to minimizing the trace
// of M^T*M (see your friendly neighborhood linear algebra text for a
// [ 0 1 0 tb ] [ s*Q 0 ] [ 0 1 0 -ta ] = [ 0 1 0 tb ] [ s*Q -s*Q*ta ] = [ Q tb-s*Q*ta ]
// [ 0 0 1 | ] [ 0 ] [ 0 0 1 | ] [ 0 0 1 | ] [ | ] [ ]
// [ 0 0 0 1 ] [ 0 0 0 1 ] [ 0 0 0 1 ] [ 0 0 0 1 ] [ 0 0 0 1 ] [ 0 0 0 1 ]
- // (ofc the whole thing is transposed for Imath).
+ // (ofc the whole thing is transposed for Imath).
const V3d translate = Bcenter - s*Acenter*Qt;
return M44d (s*Qt.x[0][0], s*Qt.x[0][1], s*Qt.x[0][2], T(0),
} // procrustesRotationAndTranslation
-template M44d procrustesRotationAndTranslation (const V3d* from, const V3d* to, const size_t numPoints, const bool doScale);
-template M44d procrustesRotationAndTranslation (const V3f* from, const V3f* to, const size_t numPoints, const bool doScale);
-template M44d procrustesRotationAndTranslation (const V3d* from, const V3d* to, const double* weights, const size_t numPoints, const bool doScale);
-template M44d procrustesRotationAndTranslation (const V3f* from, const V3f* to, const float* weights, const size_t numPoints, const bool doScale);
+template IMATH_EXPORT M44d procrustesRotationAndTranslation (const V3d* from, const V3d* to, const size_t numPoints, const bool doScale);
+template IMATH_EXPORT M44d procrustesRotationAndTranslation (const V3f* from, const V3f* to, const size_t numPoints, const bool doScale);
+template IMATH_EXPORT M44d procrustesRotationAndTranslation (const V3d* from, const V3d* to, const double* weights, const size_t numPoints, const bool doScale);
+template IMATH_EXPORT M44d procrustesRotationAndTranslation (const V3f* from, const V3f* to, const float* weights, const size_t numPoints, const bool doScale);
namespace
// J * A
// for the Jacobi rotation J and the matrix A. This is efficient because we
// only need to touch exactly the 2 columns that are affected, so we never
-// need to explicitly construct the J matrix.
+// need to explicitly construct the J matrix.
template <typename T, int j, int k>
void
-jacobiRotateRight (Imath::Matrix33<T>& A,
+jacobiRotateRight (IMATH_INTERNAL_NAMESPACE::Matrix33<T>& A,
const T c,
const T s)
{
template <typename T>
void
-jacobiRotateRight (Imath::Matrix44<T>& A,
+jacobiRotateRight (IMATH_INTERNAL_NAMESPACE::Matrix44<T>& A,
const int j,
const int k,
const T c,
// 'Computation of the Singular Value Decomposition using Mesh-Connected Processors'
// by Richard P. Brent, Franklin T. Luk, and Charles Van Loan
// It breaks the computation into two steps: the first symmetrizes the matrix,
-// and the second diagonalizes the symmetric matrix.
+// and the second diagonalizes the symmetric matrix.
template <typename T, int j, int k, int l>
bool
-twoSidedJacobiRotation (Imath::Matrix33<T>& A,
- Imath::Matrix33<T>& U,
- Imath::Matrix33<T>& V,
+twoSidedJacobiRotation (IMATH_INTERNAL_NAMESPACE::Matrix33<T>& A,
+ IMATH_INTERNAL_NAMESPACE::Matrix33<T>& U,
+ IMATH_INTERNAL_NAMESPACE::Matrix33<T>& V,
const T tol)
{
// Load everything into local variables to make things easier on the
const T d_2 = s_1*(w*s_2 + x*c_2) + c_1*(y*s_2 + z*c_2);
// For the entries we just zeroed out, we'll just set them to 0, since
- // they should be 0 up to machine precision.
+ // they should be 0 up to machine precision.
A[j][j] = d_1;
A[k][k] = d_2;
A[k][j] = 0;
// [ -s1 c1 0 ] or [ 0 1 0 ] or [ 0 c1 s1 ]
// [ 0 0 1 ] [ -s1 0 c1 ] [ 0 -s1 c1 ]
// This has the effect of adding the (weighted) ith and jth _rows_ to
- // each other.
+ // each other.
const T tau1 = A[j][l];
const T tau2 = A[k][l];
A[j][l] = c_1 * tau1 - s_1 * tau2;
// [ -s2 c2 0 ] or [ 0 1 0 ] or [ 0 c2 s2 ]
// [ 0 0 1 ] [ -s2 0 c2 ] [ 0 -s2 c2 ]
// This has the effect of adding the (weighted) ith and jth _columns_ to
- // each other.
+ // each other.
const T tau1 = A[l][j];
const T tau2 = A[l][k];
A[l][j] = c_2 * tau1 - s_2 * tau2;
}
// Now apply the rotations to U and V:
- // Remember that we have
+ // Remember that we have
// R1^T * A * R2 = D
// This is in the 2x2 case, but after doing a bunch of these
// we will get something like this for the 3x3 case:
template <typename T>
bool
-twoSidedJacobiRotation (Imath::Matrix44<T>& A,
+twoSidedJacobiRotation (IMATH_INTERNAL_NAMESPACE::Matrix44<T>& A,
int j,
int k,
- Imath::Matrix44<T>& U,
- Imath::Matrix44<T>& V,
+ IMATH_INTERNAL_NAMESPACE::Matrix44<T>& U,
+ IMATH_INTERNAL_NAMESPACE::Matrix44<T>& V,
const T tol)
{
// Load everything into local variables to make things easier on the
const T d_2 = s_1*(w*s_2 + x*c_2) + c_1*(y*s_2 + z*c_2);
// For the entries we just zeroed out, we'll just set them to 0, since
- // they should be 0 up to machine precision.
+ // they should be 0 up to machine precision.
A[j][j] = d_1;
A[k][k] = d_2;
A[k][j] = 0;
// j k
//
// This has the effect of adding the (weighted) ith and jth _rows_ to
- // each other.
+ // each other.
const T tau1 = A[j][l];
const T tau2 = A[k][l];
A[j][l] = c_1 * tau1 - s_1 * tau2;
// j k
//
// This has the effect of adding the (weighted) ith and jth _columns_ to
- // each other.
+ // each other.
const T tau1 = A[l][j];
const T tau2 = A[l][k];
A[l][j] = c_2 * tau1 - s_2 * tau2;
}
// Now apply the rotations to U and V:
- // Remember that we have
+ // Remember that we have
// R1^T * A * R2 = D
// This is in the 2x2 case, but after doing a bunch of these
// we will get something like this for the 3x3 case:
template <typename T>
void
-swapColumns (Imath::Matrix33<T>& A, int j, int k)
+swapColumns (IMATH_INTERNAL_NAMESPACE::Matrix33<T>& A, int j, int k)
{
for (int i = 0; i < 3; ++i)
std::swap (A[i][j], A[i][k]);
template <typename T>
T
-maxOffDiag (const Imath::Matrix33<T>& A)
+maxOffDiag (const IMATH_INTERNAL_NAMESPACE::Matrix33<T>& A)
{
T result = 0;
result = std::max (result, std::abs (A[0][1]));
template <typename T>
T
-maxOffDiag (const Imath::Matrix44<T>& A)
+maxOffDiag (const IMATH_INTERNAL_NAMESPACE::Matrix44<T>& A)
{
T result = 0;
for (int i = 0; i < 4; ++i)
template <typename T>
void
-twoSidedJacobiSVD (Imath::Matrix33<T> A,
- Imath::Matrix33<T>& U,
- Imath::Vec3<T>& S,
- Imath::Matrix33<T>& V,
+twoSidedJacobiSVD (IMATH_INTERNAL_NAMESPACE::Matrix33<T> A,
+ IMATH_INTERNAL_NAMESPACE::Matrix33<T>& U,
+ IMATH_INTERNAL_NAMESPACE::Vec3<T>& S,
+ IMATH_INTERNAL_NAMESPACE::Matrix33<T>& V,
const T tol,
const bool forcePositiveDeterminant)
{
// [-s1 c1 ] [ * *] [-s2 c2 ] = [* * *]
// [ 1] [* * *] [ 1] [ * *]
// However, if we keep doing this, we'll find that the off-diagonal entries
- // converge to 0 fairly quickly (convergence should be roughly cubic). The
+ // converge to 0 fairly quickly (convergence should be roughly cubic). The
// result is a diagonal A matrix and a bunch of orthogonal transforms:
// [* * *] [* ]
// L1 L2 ... Ln [* * *] Rn ... R2 R1 = [ * ]
// are extremely stable to compute and apply (this is why QR factorization
// works so well, FWIW) and because (2) by applying everything to the original
// matrix A instead of computing (A^T * A) we avoid any precision loss that
- // would result from that.
+ // would result from that.
U.makeIdentity();
V.makeIdentity();
U[i][2] = -U[i][2];
S.z = -S.z;
}
-
+
if (V.determinant() < 0)
{
for (int i = 0; i < 3; ++i)
template <typename T>
void
-twoSidedJacobiSVD (Imath::Matrix44<T> A,
- Imath::Matrix44<T>& U,
- Imath::Vec4<T>& S,
- Imath::Matrix44<T>& V,
+twoSidedJacobiSVD (IMATH_INTERNAL_NAMESPACE::Matrix44<T> A,
+ IMATH_INTERNAL_NAMESPACE::Matrix44<T>& U,
+ IMATH_INTERNAL_NAMESPACE::Vec4<T>& S,
+ IMATH_INTERNAL_NAMESPACE::Matrix44<T>& V,
const T tol,
const bool forcePositiveDeterminant)
{
// Order the singular values from largest to smallest using insertion sort:
for (int i = 1; i < 4; ++i)
{
- const Imath::Vec4<T> uCol (U[0][i], U[1][i], U[2][i], U[3][i]);
- const Imath::Vec4<T> vCol (V[0][i], V[1][i], V[2][i], V[3][i]);
+ const IMATH_INTERNAL_NAMESPACE::Vec4<T> uCol (U[0][i], U[1][i], U[2][i], U[3][i]);
+ const IMATH_INTERNAL_NAMESPACE::Vec4<T> vCol (V[0][i], V[1][i], V[2][i], V[3][i]);
const T sVal = S[i];
int j = i - 1;
U[i][3] = -U[i][3];
S[3] = -S[3];
}
-
+
if (V.determinant() < 0)
{
for (int i = 0; i < 4; ++i)
template <typename T>
void
-jacobiSVD (const Imath::Matrix33<T>& A,
- Imath::Matrix33<T>& U,
- Imath::Vec3<T>& S,
- Imath::Matrix33<T>& V,
+jacobiSVD (const IMATH_INTERNAL_NAMESPACE::Matrix33<T>& A,
+ IMATH_INTERNAL_NAMESPACE::Matrix33<T>& U,
+ IMATH_INTERNAL_NAMESPACE::Vec3<T>& S,
+ IMATH_INTERNAL_NAMESPACE::Matrix33<T>& V,
const T tol,
const bool forcePositiveDeterminant)
{
template <typename T>
void
-jacobiSVD (const Imath::Matrix44<T>& A,
- Imath::Matrix44<T>& U,
- Imath::Vec4<T>& S,
- Imath::Matrix44<T>& V,
+jacobiSVD (const IMATH_INTERNAL_NAMESPACE::Matrix44<T>& A,
+ IMATH_INTERNAL_NAMESPACE::Matrix44<T>& U,
+ IMATH_INTERNAL_NAMESPACE::Vec4<T>& S,
+ IMATH_INTERNAL_NAMESPACE::Matrix44<T>& V,
const T tol,
const bool forcePositiveDeterminant)
{
twoSidedJacobiSVD (A, U, S, V, tol, forcePositiveDeterminant);
}
-template void jacobiSVD (const Imath::Matrix33<float>& A,
- Imath::Matrix33<float>& U,
- Imath::Vec3<float>& S,
- Imath::Matrix33<float>& V,
- const float tol,
- const bool forcePositiveDeterminant);
-template void jacobiSVD (const Imath::Matrix33<double>& A,
- Imath::Matrix33<double>& U,
- Imath::Vec3<double>& S,
- Imath::Matrix33<double>& V,
- const double tol,
- const bool forcePositiveDeterminant);
-template void jacobiSVD (const Imath::Matrix44<float>& A,
- Imath::Matrix44<float>& U,
- Imath::Vec4<float>& S,
- Imath::Matrix44<float>& V,
- const float tol,
- const bool forcePositiveDeterminant);
-template void jacobiSVD (const Imath::Matrix44<double>& A,
- Imath::Matrix44<double>& U,
- Imath::Vec4<double>& S,
- Imath::Matrix44<double>& V,
- const double tol,
- const bool forcePositiveDeterminant);
+template IMATH_EXPORT void jacobiSVD (const IMATH_INTERNAL_NAMESPACE::Matrix33<float>& A,
+ IMATH_INTERNAL_NAMESPACE::Matrix33<float>& U,
+ IMATH_INTERNAL_NAMESPACE::Vec3<float>& S,
+ IMATH_INTERNAL_NAMESPACE::Matrix33<float>& V,
+ const float tol,
+ const bool forcePositiveDeterminant);
+template IMATH_EXPORT void jacobiSVD (const IMATH_INTERNAL_NAMESPACE::Matrix33<double>& A,
+ IMATH_INTERNAL_NAMESPACE::Matrix33<double>& U,
+ IMATH_INTERNAL_NAMESPACE::Vec3<double>& S,
+ IMATH_INTERNAL_NAMESPACE::Matrix33<double>& V,
+ const double tol,
+ const bool forcePositiveDeterminant);
+template IMATH_EXPORT void jacobiSVD (const IMATH_INTERNAL_NAMESPACE::Matrix44<float>& A,
+ IMATH_INTERNAL_NAMESPACE::Matrix44<float>& U,
+ IMATH_INTERNAL_NAMESPACE::Vec4<float>& S,
+ IMATH_INTERNAL_NAMESPACE::Matrix44<float>& V,
+ const float tol,
+ const bool forcePositiveDeterminant);
+template IMATH_EXPORT void jacobiSVD (const IMATH_INTERNAL_NAMESPACE::Matrix44<double>& A,
+ IMATH_INTERNAL_NAMESPACE::Matrix44<double>& U,
+ IMATH_INTERNAL_NAMESPACE::Vec4<double>& S,
+ IMATH_INTERNAL_NAMESPACE::Matrix44<double>& V,
+ const double tol,
+ const bool forcePositiveDeterminant);
namespace
{
template <int j, int k, typename TM>
-inline
+inline
void
jacobiRotateRight (TM& A,
const typename TM::BaseType s,
A[k][k] += h;
// For the entries we just zeroed out, we'll just set them to 0, since
- // they should be 0 up to machine precision.
+ // they should be 0 up to machine precision.
A[j][k] = 0;
// We only update upper triagnular elements of A, since
const T nu1 = offd1;
const T nu2 = offd2;
offd1 = nu1 - s * (nu2 + tau * nu1);
- offd2 = nu2 + s * (nu1 - tau * nu2);
+ offd2 = nu2 + s * (nu1 - tau * nu2);
// Apply rotation to V
jacobiRotateRight<j, k> (V, s, tau);
const T mu2 = T(2) * y;
// Let's see if rho^(-1) = mu2 / mu1 is less than tol
- // This test also checks if rho^2 will overflow
+ // This test also checks if rho^2 will overflow
// when tol^(-1) < sqrt(limits<T>::max()).
if (std::abs(mu2) <= tol*std::abs(mu1))
{
const T nu1 = offd1;
const T nu2 = offd2;
offd1 -= s * (nu2 + tau * nu1);
- offd2 += s * (nu1 - tau * nu2);
+ offd2 += s * (nu1 - tau * nu2);
}
{
const T nu1 = offd1;
const T nu2 = offd2;
offd1 -= s * (nu2 + tau * nu1);
- offd2 += s * (nu1 - tau * nu2);
+ offd2 += s * (nu1 - tau * nu2);
}
jacobiRotateRight<j, k> (V, s, tau);
{
// Z is for accumulating small changes (h) to diagonal entries
// of A for one sweep. Adding h's directly to A might cause
- // a cancellation effect when h is relatively very small to
- // the corresponding diagonal entry of A and
+ // a cancellation effect when h is relatively very small to
+ // the corresponding diagonal entry of A and
// this will increase numerical errors
Vec3<T> Z(0, 0, 0);
++numIter;
V[i] = MV[i][minIdx];
}
-template void jacobiEigenSolver (Matrix33<float>& A,
- Vec3<float>& S,
- Matrix33<float>& V,
- const float tol);
-template void jacobiEigenSolver (Matrix33<double>& A,
- Vec3<double>& S,
- Matrix33<double>& V,
- const double tol);
-template void jacobiEigenSolver (Matrix44<float>& A,
- Vec4<float>& S,
- Matrix44<float>& V,
- const float tol);
-template void jacobiEigenSolver (Matrix44<double>& A,
- Vec4<double>& S,
- Matrix44<double>& V,
- const double tol);
-
-template void maxEigenVector (Matrix33<float>& A,
- Vec3<float>& S);
-template void maxEigenVector (Matrix44<float>& A,
- Vec4<float>& S);
-template void maxEigenVector (Matrix33<double>& A,
- Vec3<double>& S);
-template void maxEigenVector (Matrix44<double>& A,
- Vec4<double>& S);
-
-template void minEigenVector (Matrix33<float>& A,
- Vec3<float>& S);
-template void minEigenVector (Matrix44<float>& A,
- Vec4<float>& S);
-template void minEigenVector (Matrix33<double>& A,
- Vec3<double>& S);
-template void minEigenVector (Matrix44<double>& A,
- Vec4<double>& S);
-
-} // namespace Imath
+template IMATH_EXPORT void jacobiEigenSolver (Matrix33<float>& A,
+ Vec3<float>& S,
+ Matrix33<float>& V,
+ const float tol);
+template IMATH_EXPORT void jacobiEigenSolver (Matrix33<double>& A,
+ Vec3<double>& S,
+ Matrix33<double>& V,
+ const double tol);
+template IMATH_EXPORT void jacobiEigenSolver (Matrix44<float>& A,
+ Vec4<float>& S,
+ Matrix44<float>& V,
+ const float tol);
+template IMATH_EXPORT void jacobiEigenSolver (Matrix44<double>& A,
+ Vec4<double>& S,
+ Matrix44<double>& V,
+ const double tol);
+
+template IMATH_EXPORT void maxEigenVector (Matrix33<float>& A,
+ Vec3<float>& S);
+template IMATH_EXPORT void maxEigenVector (Matrix44<float>& A,
+ Vec4<float>& S);
+template IMATH_EXPORT void maxEigenVector (Matrix33<double>& A,
+ Vec3<double>& S);
+template IMATH_EXPORT void maxEigenVector (Matrix44<double>& A,
+ Vec4<double>& S);
+
+template IMATH_EXPORT void minEigenVector (Matrix33<float>& A,
+ Vec3<float>& S);
+template IMATH_EXPORT void minEigenVector (Matrix44<float>& A,
+ Vec4<float>& S);
+template IMATH_EXPORT void minEigenVector (Matrix33<double>& A,
+ Vec3<double>& S);
+template IMATH_EXPORT void minEigenVector (Matrix44<double>& A,
+ Vec4<double>& S);
+
+IMATH_INTERNAL_NAMESPACE_SOURCE_EXIT
///////////////////////////////////////////////////////////////////////////
//
-// Copyright (c) 2002, Industrial Light & Magic, a division of Lucas
+// Copyright (c) 2002-2012, Industrial Light & Magic, a division of Lucas
// Digital Ltd. LLC
-//
+//
// All rights reserved.
-//
+//
// Redistribution and use in source and binary forms, with or without
// modification, are permitted provided that the following conditions are
// met:
// distribution.
// * Neither the name of Industrial Light & Magic nor the names of
// its contributors may be used to endorse or promote products derived
-// from this software without specific prior written permission.
-//
+// from this software without specific prior written permission.
+//
// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
//-------------------------------------------------------------------------
//
-// This file contains algorithms applied to or in conjunction with
-// transformation matrices (Imath::Matrix33 and Imath::Matrix44).
-// The assumption made is that these functions are called much less
-// often than the basic point functions or these functions require
-// more support classes.
+// This file contains algorithms applied to or in conjunction with
+// transformation matrices (Imath::Matrix33 and Imath::Matrix44).
+// The assumption made is that these functions are called much less
+// often than the basic point functions or these functions require
+// more support classes.
//
-// This file also defines a few predefined constant matrices.
+// This file also defines a few predefined constant matrices.
//
//-------------------------------------------------------------------------
+#include "ImathExport.h"
#include "ImathMatrix.h"
#include "ImathQuat.h"
#include "ImathEuler.h"
#include "ImathExc.h"
#include "ImathVec.h"
#include "ImathLimits.h"
+#include "ImathNamespace.h"
#include <math.h>
-
-#ifdef OPENEXR_DLL
- #ifdef IMATH_EXPORTS
- #define IMATH_EXPORT_CONST extern __declspec(dllexport)
- #else
- #define IMATH_EXPORT_CONST extern __declspec(dllimport)
- #endif
-#else
- #define IMATH_EXPORT_CONST extern const
-#endif
-
-
-namespace Imath {
+IMATH_INTERNAL_NAMESPACE_HEADER_ENTER
//------------------
// Identity matrices
//----------------------------------------------------------------------
// Extract scale, shear, rotation, and translation values from a matrix:
-//
+//
// Notes:
//
// This implementation follows the technique described in the paper by
-// Spencer W. Thomas in the Graphics Gems II article: "Decomposing a
+// Spencer W. Thomas in the Graphics Gems II article: "Decomposing a
// Matrix into Simple Transformations", p. 320.
//
// - Some of the functions below have an optional exc parameter
// removeScaling (m) returns false, m is unchanged
// sansScalingAndShear (m) returns m
// removeScalingAndShear (m) returns false, m is unchanged
-// extractAndRemoveScalingAndShear (m, s, h)
-// returns false, m is unchanged,
+// extractAndRemoveScalingAndShear (m, s, h)
+// returns false, m is unchanged,
// (sh) are invalid
// checkForZeroScaleInRow () returns false
// extractSHRT (m, s, h, r, t) returns false, (shrt) are invalid
//
-// - Functions extractEuler(), extractEulerXYZ() and extractEulerZYX()
-// assume that the matrix does not include shear or non-uniform scaling,
-// but they do not examine the matrix to verify this assumption.
-// Matrices with shear or non-uniform scaling are likely to produce
-// meaningless results. Therefore, you should use the
+// - Functions extractEuler(), extractEulerXYZ() and extractEulerZYX()
+// assume that the matrix does not include shear or non-uniform scaling,
+// but they do not examine the matrix to verify this assumption.
+// Matrices with shear or non-uniform scaling are likely to produce
+// meaningless results. Therefore, you should use the
// removeScalingAndShear() routine, if necessary, prior to calling
// extractEuler...() .
//
// - All functions assume that the matrix does not include perspective
-// transformation(s), but they do not examine the matrix to verify
-// this assumption. Matrices with perspective transformations are
+// transformation(s), but they do not examine the matrix to verify
+// this assumption. Matrices with perspective transformations are
// likely to produce meaningless results.
//
//----------------------------------------------------------------------
// Declarations for 4x4 matrix.
//
-template <class T> bool extractScaling
+template <class T> bool extractScaling
(const Matrix44<T> &mat,
- Vec3<T> &scl,
- bool exc = true);
+ Vec3<T> &scl,
+ bool exc = true);
+
+template <class T> Matrix44<T> sansScaling (const Matrix44<T> &mat,
+ bool exc = true);
-template <class T> Matrix44<T> sansScaling (const Matrix44<T> &mat,
- bool exc = true);
-
-template <class T> bool removeScaling
- (Matrix44<T> &mat,
- bool exc = true);
+template <class T> bool removeScaling
+ (Matrix44<T> &mat,
+ bool exc = true);
-template <class T> bool extractScalingAndShear
+template <class T> bool extractScalingAndShear
(const Matrix44<T> &mat,
- Vec3<T> &scl,
- Vec3<T> &shr,
- bool exc = true);
-
-template <class T> Matrix44<T> sansScalingAndShear
- (const Matrix44<T> &mat,
- bool exc = true);
-
-template <class T> void sansScalingAndShear
+ Vec3<T> &scl,
+ Vec3<T> &shr,
+ bool exc = true);
+
+template <class T> Matrix44<T> sansScalingAndShear
+ (const Matrix44<T> &mat,
+ bool exc = true);
+
+template <class T> void sansScalingAndShear
(Matrix44<T> &result,
- const Matrix44<T> &mat,
- bool exc = true);
+ const Matrix44<T> &mat,
+ bool exc = true);
-template <class T> bool removeScalingAndShear
+template <class T> bool removeScalingAndShear
(Matrix44<T> &mat,
- bool exc = true);
+ bool exc = true);
template <class T> bool extractAndRemoveScalingAndShear
(Matrix44<T> &mat,
- Vec3<T> &scl,
- Vec3<T> &shr,
- bool exc = true);
+ Vec3<T> &scl,
+ Vec3<T> &shr,
+ bool exc = true);
-template <class T> void extractEulerXYZ
+template <class T> void extractEulerXYZ
(const Matrix44<T> &mat,
- Vec3<T> &rot);
+ Vec3<T> &rot);
-template <class T> void extractEulerZYX
+template <class T> void extractEulerZYX
(const Matrix44<T> &mat,
- Vec3<T> &rot);
+ Vec3<T> &rot);
template <class T> Quat<T> extractQuat (const Matrix44<T> &mat);
-template <class T> bool extractSHRT
+template <class T> bool extractSHRT
(const Matrix44<T> &mat,
- Vec3<T> &s,
- Vec3<T> &h,
- Vec3<T> &r,
- Vec3<T> &t,
- bool exc /*= true*/,
- typename Euler<T>::Order rOrder);
-
-template <class T> bool extractSHRT
+ Vec3<T> &s,
+ Vec3<T> &h,
+ Vec3<T> &r,
+ Vec3<T> &t,
+ bool exc /*= true*/,
+ typename Euler<T>::Order rOrder);
+
+template <class T> bool extractSHRT
(const Matrix44<T> &mat,
- Vec3<T> &s,
- Vec3<T> &h,
- Vec3<T> &r,
- Vec3<T> &t,
- bool exc = true);
+ Vec3<T> &s,
+ Vec3<T> &h,
+ Vec3<T> &r,
+ Vec3<T> &t,
+ bool exc = true);
-template <class T> bool extractSHRT
+template <class T> bool extractSHRT
(const Matrix44<T> &mat,
- Vec3<T> &s,
- Vec3<T> &h,
- Euler<T> &r,
- Vec3<T> &t,
- bool exc = true);
+ Vec3<T> &s,
+ Vec3<T> &h,
+ Euler<T> &r,
+ Vec3<T> &t,
+ bool exc = true);
//
// Internal utility function.
//
template <class T> bool checkForZeroScaleInRow
- (const T &scl,
- const Vec3<T> &row,
- bool exc = true);
+ (const T &scl,
+ const Vec3<T> &row,
+ bool exc = true);
template <class T> Matrix44<T> outerProduct
( const Vec4<T> &a,
//
template <class T> Matrix44<T> rotationMatrix (const Vec3<T> &fromDirection,
- const Vec3<T> &toDirection);
+ const Vec3<T> &toDirection);
//
-// Returns a matrix that rotates the "fromDir" vector
-// so that it points towards "toDir". You may also
-// specify that you want the up vector to be pointing
+// Returns a matrix that rotates the "fromDir" vector
+// so that it points towards "toDir". You may also
+// specify that you want the up vector to be pointing
// in a certain direction "upDir".
//
-template <class T> Matrix44<T> rotationMatrixWithUpDir
+template <class T> Matrix44<T> rotationMatrixWithUpDir
(const Vec3<T> &fromDir,
- const Vec3<T> &toDir,
- const Vec3<T> &upDir);
+ const Vec3<T> &toDir,
+ const Vec3<T> &upDir);
//
-// Constructs a matrix that rotates the z-axis so that it
-// points towards "targetDir". You must also specify
-// that you want the up vector to be pointing in a
+// Constructs a matrix that rotates the z-axis so that it
+// points towards "targetDir". You must also specify
+// that you want the up vector to be pointing in a
// certain direction "upDir".
//
// Notes: The following degenerate cases are handled:
-// (a) when the directions given by "toDir" and "upDir"
+// (a) when the directions given by "toDir" and "upDir"
// are parallel or opposite;
// (the direction vectors must have a non-zero cross product)
// (b) when any of the given direction vectors have zero length
//
-template <class T> void alignZAxisWithTargetDir
+template <class T> void alignZAxisWithTargetDir
(Matrix44<T> &result,
- Vec3<T> targetDir,
- Vec3<T> upDir);
+ Vec3<T> targetDir,
+ Vec3<T> upDir);
// Compute an orthonormal direct frame from : a position, an x axis direction and a normal to the y axis
// If the x axis and normal are perpendicular, then the normal will have the same direction as the z axis.
-// Inputs are :
+// Inputs are :
// -the position of the frame
// -the x axis direction of the frame
// -a normal to the y axis of the frame
// -Matrix B
// Return Matrix A with tweaked rotation/scale
template <class T> Matrix44<T> computeRSMatrix( bool keepRotateA,
- bool keepScaleA,
+ bool keepScaleA,
const Matrix44<T>& A,
const Matrix44<T>& B);
//----------------------------------------------------------------------
-//
+//
// Declarations for 3x3 matrix.
//
-
-template <class T> bool extractScaling
+
+template <class T> bool extractScaling
(const Matrix33<T> &mat,
- Vec2<T> &scl,
- bool exc = true);
-
-template <class T> Matrix33<T> sansScaling (const Matrix33<T> &mat,
- bool exc = true);
-
-template <class T> bool removeScaling
- (Matrix33<T> &mat,
- bool exc = true);
+ Vec2<T> &scl,
+ bool exc = true);
+
+template <class T> Matrix33<T> sansScaling (const Matrix33<T> &mat,
+ bool exc = true);
-template <class T> bool extractScalingAndShear
- (const Matrix33<T> &mat,
- Vec2<T> &scl,
- T &h,
- bool exc = true);
+template <class T> bool removeScaling
+ (Matrix33<T> &mat,
+ bool exc = true);
-template <class T> Matrix33<T> sansScalingAndShear
+template <class T> bool extractScalingAndShear
(const Matrix33<T> &mat,
- bool exc = true);
-
-template <class T> bool removeScalingAndShear
+ Vec2<T> &scl,
+ T &h,
+ bool exc = true);
+
+template <class T> Matrix33<T> sansScalingAndShear
+ (const Matrix33<T> &mat,
+ bool exc = true);
+
+template <class T> bool removeScalingAndShear
(Matrix33<T> &mat,
- bool exc = true);
+ bool exc = true);
template <class T> bool extractAndRemoveScalingAndShear
(Matrix33<T> &mat,
- Vec2<T> &scl,
- T &shr,
- bool exc = true);
+ Vec2<T> &scl,
+ T &shr,
+ bool exc = true);
template <class T> void extractEuler
(const Matrix33<T> &mat,
- T &rot);
+ T &rot);
template <class T> bool extractSHRT (const Matrix33<T> &mat,
- Vec2<T> &s,
- T &h,
- T &r,
- Vec2<T> &t,
- bool exc = true);
+ Vec2<T> &s,
+ T &h,
+ T &r,
+ Vec2<T> &t,
+ bool exc = true);
template <class T> bool checkForZeroScaleInRow
- (const T &scl,
- const Vec2<T> &row,
- bool exc = true);
+ (const T &scl,
+ const Vec2<T> &row,
+ bool exc = true);
template <class T> Matrix33<T> outerProduct
( const Vec3<T> &a,
Matrix44<T> M (mat);
if (! extractAndRemoveScalingAndShear (M, scl, shr, exc))
- return false;
-
+ return false;
+
return true;
}
Vec3<T> tran;
if (! extractSHRT (mat, scl, shr, rot, tran, exc))
- return mat;
+ return mat;
Matrix44<T> M;
-
+
M.translate (tran);
M.rotate (rot);
M.shear (shr);
Vec3<T> tran;
if (! extractSHRT (mat, scl, shr, rot, tran, exc))
- return false;
+ return false;
mat.makeIdentity ();
mat.translate (tran);
template <class T>
bool
-extractScalingAndShear (const Matrix44<T> &mat,
- Vec3<T> &scl, Vec3<T> &shr, bool exc)
+extractScalingAndShear (const Matrix44<T> &mat,
+ Vec3<T> &scl, Vec3<T> &shr, bool exc)
{
Matrix44<T> M (mat);
if (! extractAndRemoveScalingAndShear (M, scl, shr, exc))
- return false;
-
+ return false;
+
return true;
}
Matrix44<T> M (mat);
if (! extractAndRemoveScalingAndShear (M, scl, shr, exc))
- return mat;
-
+ return mat;
+
return M;
}
Vec3<T> shr;
if (! extractAndRemoveScalingAndShear (result, scl, shr, exc))
- result = mat;
+ result = mat;
}
Vec3<T> shr;
if (! extractAndRemoveScalingAndShear (mat, scl, shr, exc))
- return false;
-
+ return false;
+
return true;
}
template <class T>
bool
-extractAndRemoveScalingAndShear (Matrix44<T> &mat,
- Vec3<T> &scl, Vec3<T> &shr, bool exc)
+extractAndRemoveScalingAndShear (Matrix44<T> &mat,
+ Vec3<T> &scl, Vec3<T> &shr, bool exc)
{
//
// This implementation follows the technique described in the paper by
- // Spencer W. Thomas in the Graphics Gems II article: "Decomposing a
+ // Spencer W. Thomas in the Graphics Gems II article: "Decomposing a
// Matrix into Simple Transformations", p. 320.
//
row[0] = Vec3<T> (mat[0][0], mat[0][1], mat[0][2]);
row[1] = Vec3<T> (mat[1][0], mat[1][1], mat[1][2]);
row[2] = Vec3<T> (mat[2][0], mat[2][1], mat[2][2]);
-
+
T maxVal = 0;
for (int i=0; i < 3; i++)
- for (int j=0; j < 3; j++)
- if (Imath::abs (row[i][j]) > maxVal)
- maxVal = Imath::abs (row[i][j]);
+ for (int j=0; j < 3; j++)
+ if (IMATH_INTERNAL_NAMESPACE::abs (row[i][j]) > maxVal)
+ maxVal = IMATH_INTERNAL_NAMESPACE::abs (row[i][j]);
//
// We normalize the 3x3 matrix here.
// It was noticed that this can improve numerical stability significantly,
// especially when many of the upper 3x3 matrix's coefficients are very
- // close to zero; we correct for this step at the end by multiplying the
- // scaling factors by maxVal at the end (shear and rotation are not
+ // close to zero; we correct for this step at the end by multiplying the
+ // scaling factors by maxVal at the end (shear and rotation are not
// affected by the normalization).
if (maxVal != 0)
{
- for (int i=0; i < 3; i++)
- if (! checkForZeroScaleInRow (maxVal, row[i], exc))
- return false;
- else
- row[i] /= maxVal;
+ for (int i=0; i < 3; i++)
+ if (! checkForZeroScaleInRow (maxVal, row[i], exc))
+ return false;
+ else
+ row[i] /= maxVal;
}
- // Compute X scale factor.
+ // Compute X scale factor.
scl.x = row[0].length ();
if (! checkForZeroScaleInRow (scl.x, row[0], exc))
- return false;
+ return false;
// Normalize first row.
row[0] /= scl.x;
// Now, compute Y scale.
scl.y = row[1].length ();
if (! checkForZeroScaleInRow (scl.y, row[1], exc))
- return false;
+ return false;
// Normalize 2nd row and correct the XY shear factor for Y scaling.
- row[1] /= scl.y;
+ row[1] /= scl.y;
shr[0] /= scl.y;
// Compute XZ and YZ shears, orthogonalize 3rd row.
// Next, get Z scale.
scl.z = row[2].length ();
if (! checkForZeroScaleInRow (scl.z, row[2], exc))
- return false;
+ return false;
// Normalize 3rd row and correct the XZ and YZ shear factors for Z scaling.
row[2] /= scl.z;
// Check for a coordinate system flip. If the determinant
// is less than zero, then negate the matrix and the scaling factors.
if (row[0].dot (row[1].cross (row[2])) < 0)
- for (int i=0; i < 3; i++)
- {
- scl[i] *= -1;
- row[i] *= -1;
- }
+ for (int i=0; i < 3; i++)
+ {
+ scl[i] *= -1;
+ row[i] *= -1;
+ }
// Copy over the orthonormal rows into the returned matrix.
// The upper 3x3 matrix in mat is now a rotation matrix.
for (int i=0; i < 3; i++)
{
- mat[i][0] = row[i][0];
- mat[i][1] = row[i][1];
- mat[i][2] = row[i][2];
+ mat[i][0] = row[i][0];
+ mat[i][1] = row[i][1];
+ mat[i][2] = row[i][2];
}
- // Correct the scaling factors for the normalization step that we
- // performed above; shear and rotation are not affected by the
+ // Correct the scaling factors for the normalization step that we
+ // performed above; shear and rotation are not affected by the
// normalization.
scl *= maxVal;
j.normalize();
k.normalize();
- Matrix44<T> M (i[0], i[1], i[2], 0,
- j[0], j[1], j[2], 0,
- k[0], k[1], k[2], 0,
- 0, 0, 0, 1);
+ Matrix44<T> M (i[0], i[1], i[2], 0,
+ j[0], j[1], j[2], 0,
+ k[0], k[1], k[2], 0,
+ 0, 0, 0, 1);
//
// Extract the first angle, rot.x.
- //
+ //
rot.x = Math<T>::atan2 (M[1][2], M[2][2]);
j.normalize();
k.normalize();
- Matrix44<T> M (i[0], i[1], i[2], 0,
- j[0], j[1], j[2], 0,
- k[0], k[1], k[2], 0,
- 0, 0, 0, 1);
+ Matrix44<T> M (i[0], i[1], i[2], 0,
+ j[0], j[1], j[2], 0,
+ k[0], k[1], k[2], 0,
+ 0, 0, 0, 1);
//
// Extract the first angle, rot.x.
- //
+ //
rot.x = -Math<T>::atan2 (M[1][0], M[0][0]);
quat.v.x = (mat[1][2] - mat[2][1]) * s;
quat.v.y = (mat[2][0] - mat[0][2]) * s;
quat.v.z = (mat[0][1] - mat[1][0]) * s;
- }
- else {
+ }
+ else {
// diagonal is negative
i = 0;
- if (mat[1][1] > mat[0][0])
+ if (mat[1][1] > mat[0][0])
i=1;
- if (mat[2][2] > mat[i][i])
+ if (mat[2][2] > mat[i][i])
i=2;
-
+
j = nxt[i];
k = nxt[j];
s = Math<T>::sqrt ((mat[i][i] - (mat[j][j] + mat[k][k])) + T(1.0));
-
+
q[i] = s * T(0.5);
- if (s != T(0.0))
+ if (s != T(0.0))
s = T(0.5) / s;
q[3] = (mat[j][k] - mat[k][j]) * s;
}
template <class T>
-bool
+bool
extractSHRT (const Matrix44<T> &mat,
- Vec3<T> &s,
- Vec3<T> &h,
- Vec3<T> &r,
- Vec3<T> &t,
- bool exc /* = true */ ,
- typename Euler<T>::Order rOrder /* = Euler<T>::XYZ */ )
+ Vec3<T> &s,
+ Vec3<T> &h,
+ Vec3<T> &r,
+ Vec3<T> &t,
+ bool exc /* = true */ ,
+ typename Euler<T>::Order rOrder /* = Euler<T>::XYZ */ )
{
Matrix44<T> rot;
rot = mat;
if (! extractAndRemoveScalingAndShear (rot, s, h, exc))
- return false;
+ return false;
extractEulerXYZ (rot, r);
if (rOrder != Euler<T>::XYZ)
{
- Imath::Euler<T> eXYZ (r, Imath::Euler<T>::XYZ);
- Imath::Euler<T> e (eXYZ, rOrder);
- r = e.toXYZVector ();
+ IMATH_INTERNAL_NAMESPACE::Euler<T> eXYZ (r, IMATH_INTERNAL_NAMESPACE::Euler<T>::XYZ);
+ IMATH_INTERNAL_NAMESPACE::Euler<T> e (eXYZ, rOrder);
+ r = e.toXYZVector ();
}
return true;
}
template <class T>
-bool
+bool
extractSHRT (const Matrix44<T> &mat,
- Vec3<T> &s,
- Vec3<T> &h,
- Vec3<T> &r,
- Vec3<T> &t,
- bool exc)
+ Vec3<T> &s,
+ Vec3<T> &h,
+ Vec3<T> &r,
+ Vec3<T> &t,
+ bool exc)
{
- return extractSHRT(mat, s, h, r, t, exc, Imath::Euler<T>::XYZ);
+ return extractSHRT(mat, s, h, r, t, exc, IMATH_INTERNAL_NAMESPACE::Euler<T>::XYZ);
}
template <class T>
-bool
+bool
extractSHRT (const Matrix44<T> &mat,
- Vec3<T> &s,
- Vec3<T> &h,
- Euler<T> &r,
- Vec3<T> &t,
- bool exc /* = true */)
+ Vec3<T> &s,
+ Vec3<T> &h,
+ Euler<T> &r,
+ Vec3<T> &t,
+ bool exc /* = true */)
{
return extractSHRT (mat, s, h, r, t, exc, r.order ());
}
-template <class T>
-bool
-checkForZeroScaleInRow (const T& scl,
- const Vec3<T> &row,
- bool exc /* = true */ )
+template <class T>
+bool
+checkForZeroScaleInRow (const T& scl,
+ const Vec3<T> &row,
+ bool exc /* = true */ )
{
for (int i = 0; i < 3; i++)
{
- if ((abs (scl) < 1 && abs (row[i]) >= limits<T>::max() * abs (scl)))
- {
- if (exc)
- throw Imath::ZeroScaleExc ("Cannot remove zero scaling "
- "from matrix.");
- else
- return false;
- }
+ if ((abs (scl) < 1 && abs (row[i]) >= limits<T>::max() * abs (scl)))
+ {
+ if (exc)
+ throw IMATH_INTERNAL_NAMESPACE::ZeroScaleExc ("Cannot remove zero scaling "
+ "from matrix.");
+ else
+ return false;
+ }
}
return true;
template <class T>
-Matrix44<T>
+Matrix44<T>
rotationMatrixWithUpDir (const Vec3<T> &fromDir,
- const Vec3<T> &toDir,
- const Vec3<T> &upDir)
+ const Vec3<T> &toDir,
+ const Vec3<T> &upDir)
{
//
- // The goal is to obtain a rotation matrix that takes
- // "fromDir" to "toDir". We do this in two steps and
- // compose the resulting rotation matrices;
+ // The goal is to obtain a rotation matrix that takes
+ // "fromDir" to "toDir". We do this in two steps and
+ // compose the resulting rotation matrices;
// (a) rotate "fromDir" into the z-axis
// (b) rotate the z-axis into "toDir"
//
// The from direction must be non-zero; but we allow zero to and up dirs.
if (fromDir.length () == 0)
- return Matrix44<T> ();
+ return Matrix44<T> ();
else
{
- Matrix44<T> zAxis2FromDir( Imath::UNINITIALIZED );
- alignZAxisWithTargetDir (zAxis2FromDir, fromDir, Vec3<T> (0, 1, 0));
+ Matrix44<T> zAxis2FromDir( IMATH_INTERNAL_NAMESPACE::UNINITIALIZED );
+ alignZAxisWithTargetDir (zAxis2FromDir, fromDir, Vec3<T> (0, 1, 0));
- Matrix44<T> fromDir2zAxis = zAxis2FromDir.transposed ();
+ Matrix44<T> fromDir2zAxis = zAxis2FromDir.transposed ();
+
+ Matrix44<T> zAxis2ToDir( IMATH_INTERNAL_NAMESPACE::UNINITIALIZED );
+ alignZAxisWithTargetDir (zAxis2ToDir, toDir, upDir);
- Matrix44<T> zAxis2ToDir( Imath::UNINITIALIZED );
- alignZAxisWithTargetDir (zAxis2ToDir, toDir, upDir);
-
- return fromDir2zAxis * zAxis2ToDir;
+ return fromDir2zAxis * zAxis2ToDir;
}
}
//
if ( targetDir.length () == 0 )
- targetDir = Vec3<T> (0, 0, 1);
+ targetDir = Vec3<T> (0, 0, 1);
//
// Ensure that the up direction is non-zero.
//
if ( upDir.length () == 0 )
- upDir = Vec3<T> (0, 1, 0);
+ upDir = Vec3<T> (0, 1, 0);
//
- // Check for degeneracies. If the upDir and targetDir are parallel
+ // Check for degeneracies. If the upDir and targetDir are parallel
// or opposite, then compute a new, arbitrary up direction that is
// not parallel or opposite to the targetDir.
//
if (upDir.cross (targetDir).length () == 0)
{
- upDir = targetDir.cross (Vec3<T> (1, 0, 0));
- if (upDir.length() == 0)
- upDir = targetDir.cross(Vec3<T> (0, 0, 1));
+ upDir = targetDir.cross (Vec3<T> (1, 0, 0));
+ if (upDir.length() == 0)
+ upDir = targetDir.cross(Vec3<T> (0, 0, 1));
}
//
// Compute the x-, y-, and z-axis vectors of the new coordinate system.
//
- Vec3<T> targetPerpDir = upDir.cross (targetDir);
+ Vec3<T> targetPerpDir = upDir.cross (targetDir);
Vec3<T> targetUpDir = targetDir.cross (targetPerpDir);
-
+
//
// Rotate the x-axis into targetPerpDir (row 0),
// rotate the y-axis into targetUpDir (row 1),
// rotate the z-axis into targetDir (row 2).
//
-
+
Vec3<T> row[3];
row[0] = targetPerpDir.normalized ();
row[1] = targetUpDir .normalized ();
row[2] = targetDir .normalized ();
-
+
result.x[0][0] = row[0][0];
result.x[0][1] = row[0][1];
result.x[0][2] = row[0][2];
result.x[0][3] = (T)0;
-
+
result.x[1][0] = row[1][0];
result.x[1][1] = row[1][1];
result.x[1][2] = row[1][2];
result.x[1][3] = (T)0;
-
+
result.x[2][0] = row[2][0];
result.x[2][1] = row[2][1];
result.x[2][2] = row[2][2];
result.x[2][3] = (T)0;
-
+
result.x[3][0] = (T)0;
result.x[3][1] = (T)0;
result.x[3][2] = (T)0;
// Compute an orthonormal direct frame from : a position, an x axis direction and a normal to the y axis
// If the x axis and normal are perpendicular, then the normal will have the same direction as the z axis.
-// Inputs are :
+// Inputs are :
// -the position of the frame
// -the x axis direction of the frame
// -a normal to the y axis of the frame
L[3][1] = p[1];
L[3][2] = p[2];
L[3][3] = 1.0;
-
+
return L;
}
template <class T>
Matrix44<T>
computeRSMatrix( bool keepRotateA,
- bool keepScaleA,
- const Matrix44<T>& A,
+ bool keepScaleA,
+ const Matrix44<T>& A,
const Matrix44<T>& B)
{
Vec3<T> as, ah, ar, at;
extractSHRT (A, as, ah, ar, at);
-
+
Vec3<T> bs, bh, br, bt;
extractSHRT (B, bs, bh, br, bt);
mat.translate (at);
mat.rotate (ar);
mat.scale (as);
-
+
return mat;
}
Matrix33<T> M (mat);
if (! extractAndRemoveScalingAndShear (M, scl, shr, exc))
- return false;
+ return false;
return true;
}
Vec2<T> tran;
if (! extractSHRT (mat, scl, shr, rot, tran, exc))
- return mat;
+ return mat;
Matrix33<T> M;
-
+
M.translate (tran);
M.rotate (rot);
M.shear (shr);
Vec2<T> tran;
if (! extractSHRT (mat, scl, shr, rot, tran, exc))
- return false;
+ return false;
mat.makeIdentity ();
mat.translate (tran);
Matrix33<T> M (mat);
if (! extractAndRemoveScalingAndShear (M, scl, shr, exc))
- return false;
+ return false;
return true;
}
Matrix33<T> M (mat);
if (! extractAndRemoveScalingAndShear (M, scl, shr, exc))
- return mat;
-
+ return mat;
+
return M;
}
T shr;
if (! extractAndRemoveScalingAndShear (mat, scl, shr, exc))
- return false;
-
+ return false;
+
return true;
}
template <class T>
bool
-extractAndRemoveScalingAndShear (Matrix33<T> &mat,
- Vec2<T> &scl, T &shr, bool exc)
+extractAndRemoveScalingAndShear (Matrix33<T> &mat,
+ Vec2<T> &scl, T &shr, bool exc)
{
Vec2<T> row[2];
row[0] = Vec2<T> (mat[0][0], mat[0][1]);
row[1] = Vec2<T> (mat[1][0], mat[1][1]);
-
+
T maxVal = 0;
for (int i=0; i < 2; i++)
- for (int j=0; j < 2; j++)
- if (Imath::abs (row[i][j]) > maxVal)
- maxVal = Imath::abs (row[i][j]);
+ for (int j=0; j < 2; j++)
+ if (IMATH_INTERNAL_NAMESPACE::abs (row[i][j]) > maxVal)
+ maxVal = IMATH_INTERNAL_NAMESPACE::abs (row[i][j]);
//
// We normalize the 2x2 matrix here.
// It was noticed that this can improve numerical stability significantly,
// especially when many of the upper 2x2 matrix's coefficients are very
- // close to zero; we correct for this step at the end by multiplying the
- // scaling factors by maxVal at the end (shear and rotation are not
+ // close to zero; we correct for this step at the end by multiplying the
+ // scaling factors by maxVal at the end (shear and rotation are not
// affected by the normalization).
if (maxVal != 0)
{
- for (int i=0; i < 2; i++)
- if (! checkForZeroScaleInRow (maxVal, row[i], exc))
- return false;
- else
- row[i] /= maxVal;
+ for (int i=0; i < 2; i++)
+ if (! checkForZeroScaleInRow (maxVal, row[i], exc))
+ return false;
+ else
+ row[i] /= maxVal;
}
- // Compute X scale factor.
+ // Compute X scale factor.
scl.x = row[0].length ();
if (! checkForZeroScaleInRow (scl.x, row[0], exc))
- return false;
+ return false;
// Normalize first row.
row[0] /= scl.x;
// An XY shear factor will shear the X coord. as the Y coord. changes.
- // There are 2 combinations (XY, YX), although we only extract the XY
- // shear factor because we can effect the an YX shear factor by
+ // There are 2 combinations (XY, YX), although we only extract the XY
+ // shear factor because we can effect the an YX shear factor by
// shearing in XY combined with rotations and scales.
//
// shear matrix < 1, YX, 0,
// Now, compute Y scale.
scl.y = row[1].length ();
if (! checkForZeroScaleInRow (scl.y, row[1], exc))
- return false;
+ return false;
// Normalize 2nd row and correct the XY shear factor for Y scaling.
- row[1] /= scl.y;
+ row[1] /= scl.y;
shr /= scl.y;
// At this point, the upper 2x2 matrix in mat is orthonormal.
// Check for a coordinate system flip. If the determinant
- // is -1, then flip the rotation matrix and adjust the scale(Y)
+ // is -1, then flip the rotation matrix and adjust the scale(Y)
// and shear(XY) factors to compensate.
if (row[0][0] * row[1][1] - row[0][1] * row[1][0] < 0)
{
- row[1][0] *= -1;
- row[1][1] *= -1;
- scl[1] *= -1;
- shr *= -1;
+ row[1][0] *= -1;
+ row[1][1] *= -1;
+ scl[1] *= -1;
+ shr *= -1;
}
// Copy over the orthonormal rows into the returned matrix.
// The upper 2x2 matrix in mat is now a rotation matrix.
for (int i=0; i < 2; i++)
{
- mat[i][0] = row[i][0];
- mat[i][1] = row[i][1];
+ mat[i][0] = row[i][0];
+ mat[i][1] = row[i][1];
}
scl *= maxVal;
//
// Extract the angle, rot.
- //
+ //
rot = - Math<T>::atan2 (j[0], i[0]);
}
template <class T>
-bool
+bool
extractSHRT (const Matrix33<T> &mat,
- Vec2<T> &s,
- T &h,
- T &r,
- Vec2<T> &t,
- bool exc)
+ Vec2<T> &s,
+ T &h,
+ T &r,
+ Vec2<T> &t,
+ bool exc)
{
Matrix33<T> rot;
rot = mat;
if (! extractAndRemoveScalingAndShear (rot, s, h, exc))
- return false;
+ return false;
extractEuler (rot, r);
}
-template <class T>
-bool
-checkForZeroScaleInRow (const T& scl,
- const Vec2<T> &row,
- bool exc /* = true */ )
+template <class T>
+bool
+checkForZeroScaleInRow (const T& scl,
+ const Vec2<T> &row,
+ bool exc /* = true */ )
{
for (int i = 0; i < 2; i++)
{
- if ((abs (scl) < 1 && abs (row[i]) >= limits<T>::max() * abs (scl)))
- {
- if (exc)
- throw Imath::ZeroScaleExc ("Cannot remove zero scaling "
- "from matrix.");
- else
- return false;
- }
+ if ((abs (scl) < 1 && abs (row[i]) >= limits<T>::max() * abs (scl)))
+ {
+ if (exc)
+ throw IMATH_INTERNAL_NAMESPACE::ZeroScaleExc (
+ "Cannot remove zero scaling from matrix.");
+ else
+ return false;
+ }
}
return true;
// Computes the translation and rotation that brings the 'from' points
-// as close as possible to the 'to' points under the Frobenius norm.
+// as close as possible to the 'to' points under the Frobenius norm.
// To be more specific, let x be the matrix of 'from' points and y be
// the matrix of 'to' points, we want to find the matrix A of the form
// [ R t ]
// || (A*x - y)^T * W * (A*x - y) ||_F
// If doScaling is true, then a uniform scale is allowed also.
template <typename T>
-Imath::M44d
-procrustesRotationAndTranslation (const Imath::Vec3<T>* A, // From these
- const Imath::Vec3<T>* B, // To these
- const T* weights,
+IMATH_INTERNAL_NAMESPACE::M44d
+procrustesRotationAndTranslation (const IMATH_INTERNAL_NAMESPACE::Vec3<T>* A, // From these
+ const IMATH_INTERNAL_NAMESPACE::Vec3<T>* B, // To these
+ const T* weights,
const size_t numPoints,
const bool doScaling = false);
// Unweighted:
template <typename T>
-Imath::M44d
-procrustesRotationAndTranslation (const Imath::Vec3<T>* A,
- const Imath::Vec3<T>* B,
+IMATH_INTERNAL_NAMESPACE::M44d
+procrustesRotationAndTranslation (const IMATH_INTERNAL_NAMESPACE::Vec3<T>* A,
+ const IMATH_INTERNAL_NAMESPACE::Vec3<T>* B,
const size_t numPoints,
const bool doScaling = false);
// Compute the SVD of a 3x3 matrix using Jacobi transformations. This method
// should be quite accurate (competitive with LAPACK) even for poorly
// conditioned matrices, and because it has been written specifically for the
-// 3x3/4x4 case it is much faster than calling out to LAPACK.
+// 3x3/4x4 case it is much faster than calling out to LAPACK.
//
// The SVD of a 3x3/4x4 matrix A is defined as follows:
// A = U * S * V^T
// the largest to the smallest. However, some uses of this function may
// require that the matrix U*V^T have positive determinant; in this case, we
// may make the smallest singular value negative to ensure that this is
-// satisfied.
+// satisfied.
//
// Currently only available for single- and double-precision matrices.
template <typename T>
void
-jacobiSVD (const Imath::Matrix33<T>& A,
- Imath::Matrix33<T>& U,
- Imath::Vec3<T>& S,
- Imath::Matrix33<T>& V,
- const T tol = Imath::limits<T>::epsilon(),
+jacobiSVD (const IMATH_INTERNAL_NAMESPACE::Matrix33<T>& A,
+ IMATH_INTERNAL_NAMESPACE::Matrix33<T>& U,
+ IMATH_INTERNAL_NAMESPACE::Vec3<T>& S,
+ IMATH_INTERNAL_NAMESPACE::Matrix33<T>& V,
+ const T tol = IMATH_INTERNAL_NAMESPACE::limits<T>::epsilon(),
const bool forcePositiveDeterminant = false);
template <typename T>
void
-jacobiSVD (const Imath::Matrix44<T>& A,
- Imath::Matrix44<T>& U,
- Imath::Vec4<T>& S,
- Imath::Matrix44<T>& V,
- const T tol = Imath::limits<T>::epsilon(),
+jacobiSVD (const IMATH_INTERNAL_NAMESPACE::Matrix44<T>& A,
+ IMATH_INTERNAL_NAMESPACE::Matrix44<T>& U,
+ IMATH_INTERNAL_NAMESPACE::Vec4<T>& S,
+ IMATH_INTERNAL_NAMESPACE::Matrix44<T>& V,
+ const T tol = IMATH_INTERNAL_NAMESPACE::limits<T>::epsilon(),
const bool forcePositiveDeterminant = false);
// Compute the eigenvalues (S) and the eigenvectors (V) of
// A = V * S * V^T
// where V is orthonormal and S is the diagonal matrix of eigenvalues.
// Input matrix A must be symmetric. A is also modified during
-// the computation so that upper diagonal entries of A become zero.
+// the computation so that upper diagonal entries of A become zero.
//
template <typename T>
void
void
minEigenVector (TM& A, TV& S);
-} // namespace Imath
+IMATH_INTERNAL_NAMESPACE_HEADER_EXIT
-#endif
+#endif // INCLUDED_IMATHMATRIXALGO_H
--- /dev/null
+///////////////////////////////////////////////////////////////////////////
+//
+// Copyright (c) 2012, Industrial Light & Magic, a division of Lucas
+// Digital Ltd. LLC
+//
+// All rights reserved.
+//
+// Redistribution and use in source and binary forms, with or without
+// modification, are permitted provided that the following conditions are
+// met:
+// * Redistributions of source code must retain the above copyright
+// notice, this list of conditions and the following disclaimer.
+// * Redistributions in binary form must reproduce the above
+// copyright notice, this list of conditions and the following disclaimer
+// in the documentation and/or other materials provided with the
+// distribution.
+// * Neither the name of Industrial Light & Magic nor the names of
+// its contributors may be used to endorse or promote products derived
+// from this software without specific prior written permission.
+//
+// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+//
+///////////////////////////////////////////////////////////////////////////
+
+#ifndef INCLUDED_IMATHNAMESPACE_H
+#define INCLUDED_IMATHNAMESPACE_H
+
+//
+// The purpose of this file is to make it possible to specify an
+// IMATH_INTERNAL_NAMESPACE as a preprocessor definition and have all of the
+// Imath symbols defined within that namespace rather than the standard
+// Imath namespace. Those symbols are made available to client code through
+// the IMATH_NAMESPACE in addition to the IMATH_INTERNAL_NAMESPACE.
+//
+// To ensure source code compatibility, the IMATH_NAMESPACE defaults to Imath
+// and then "using namespace IMATH_INTERNAL_NAMESPACE;" brings all of the
+// declarations from the IMATH_INTERNAL_NAMESPACE into the IMATH_NAMESPACE.
+// This means that client code can continue to use syntax like Imath::V3f,
+// but at link time it will resolve to a mangled symbol based on the
+// IMATH_INTERNAL_NAMESPACE.
+//
+// As an example, if one needed to build against a newer version of Imath and
+// have it run alongside an older version in the same application, it is now
+// possible to use an internal namespace to prevent collisions between the
+// older versions of Imath symbols and the newer ones. To do this, the
+// following could be defined at build time:
+//
+// IMATH_INTERNAL_NAMESPACE = Imath_v2
+//
+// This means that declarations inside Imath headers look like this (after
+// the preprocessor has done its work):
+//
+// namespace Imath_v2 {
+// ...
+// class declarations
+// ...
+// }
+//
+// namespace Imath {
+// using namespace Imath_v2;
+// }
+//
+
+//
+// Open Source version of this file pulls in the IlmBaseConfig.h file
+// for the configure time options.
+//
+#include "IlmBaseConfig.h"
+
+
+#ifndef IMATH_NAMESPACE
+#define IMATH_NAMESPACE Imath
+#endif
+
+#ifndef IMATH_INTERNAL_NAMESPACE
+#define IMATH_INTERNAL_NAMESPACE IMATH_NAMESPACE
+#endif
+
+//
+// We need to be sure that we import the internal namespace into the public one.
+// To do this, we use the small bit of code below which initially defines
+// IMATH_INTERNAL_NAMESPACE (so it can be referenced) and then defines
+// IMATH_NAMESPACE and pulls the internal symbols into the public
+// namespace.
+//
+
+namespace IMATH_INTERNAL_NAMESPACE {}
+namespace IMATH_NAMESPACE {
+ using namespace IMATH_INTERNAL_NAMESPACE;
+}
+
+//
+// There are identical pairs of HEADER/SOURCE ENTER/EXIT macros so that
+// future extension to the namespace mechanism is possible without changing
+// project source code.
+//
+
+#define IMATH_INTERNAL_NAMESPACE_HEADER_ENTER namespace IMATH_INTERNAL_NAMESPACE {
+#define IMATH_INTERNAL_NAMESPACE_HEADER_EXIT }
+
+#define IMATH_INTERNAL_NAMESPACE_SOURCE_ENTER namespace IMATH_INTERNAL_NAMESPACE {
+#define IMATH_INTERNAL_NAMESPACE_SOURCE_EXIT }
+
+
+#endif /* INCLUDED_IMATHNAMESPACE_H */
///////////////////////////////////////////////////////////////////////////
//
-// Copyright (c) 2002, Industrial Light & Magic, a division of Lucas
+// Copyright (c) 2002-2012, Industrial Light & Magic, a division of Lucas
// Digital Ltd. LLC
-//
+//
// All rights reserved.
-//
+//
// Redistribution and use in source and binary forms, with or without
// modification, are permitted provided that the following conditions are
// met:
// distribution.
// * Neither the name of Industrial Light & Magic nor the names of
// its contributors may be used to endorse or promote products derived
-// from this software without specific prior written permission.
-//
+// from this software without specific prior written permission.
+//
// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
#include "ImathVec.h"
#include "ImathLine.h"
+#include "ImathNamespace.h"
-namespace Imath {
+IMATH_INTERNAL_NAMESPACE_HEADER_ENTER
template <class T>
Plane3(const Vec3<T> &normal, T distance);
Plane3(const Vec3<T> &point, const Vec3<T> &normal);
Plane3(const Vec3<T> &point1,
- const Vec3<T> &point2,
- const Vec3<T> &point3);
+ const Vec3<T> &point2,
+ const Vec3<T> &point3);
//----------------------
// Various set methods
//----------------------
void set(const Vec3<T> &normal,
- T distance);
+ T distance);
void set(const Vec3<T> &point,
- const Vec3<T> &normal);
+ const Vec3<T> &normal);
void set(const Vec3<T> &point1,
- const Vec3<T> &point2,
- const Vec3<T> &point3 );
+ const Vec3<T> &point2,
+ const Vec3<T> &point3 );
//----------------------
// Utilities
Vec3<T> &intersection) const;
bool intersectT(const Line3<T> &line,
- T ¶meter) const;
+ T ¶meter) const;
T distanceTo(const Vec3<T> &) const;
template <class T>
inline Plane3<T>::Plane3(const Vec3<T> &p0,
- const Vec3<T> &p1,
- const Vec3<T> &p2)
+ const Vec3<T> &p1,
+ const Vec3<T> &p2)
{
set(p0,p1,p2);
}
template <class T>
inline void Plane3<T>::set(const Vec3<T>& point1,
- const Vec3<T>& point2,
- const Vec3<T>& point3)
+ const Vec3<T>& point2,
+ const Vec3<T>& point3)
{
normal = (point2 - point1) % (point3 - point1);
normal.normalize();
std::ostream &operator<< (std::ostream &o, const Plane3<T> &plane)
{
return o << "(" << plane.normal << ", " << plane.distance
- << ")";
+ << ")";
}
template<class T>
if (tmpLen > dir1Len)
{
- dir1 = tmp;
- dir1Len = tmpLen;
+ dir1 = tmp;
+ dir1Len = tmpLen;
}
tmp = Vec3<T> (0, 0, 1) % plane.normal;
if (tmpLen > dir1Len)
{
- dir1 = tmp;
+ dir1 = tmp;
}
Vec3<T> dir2 = dir1 % plane.normal;
Vec3<T> point = plane.distance * plane.normal;
return Plane3<T> ( point * M,
- (point + dir2) * M,
- (point + dir1) * M );
+ (point + dir2) * M,
+ (point + dir1) * M );
}
template<class T>
}
-} // namespace Imath
+IMATH_INTERNAL_NAMESPACE_HEADER_EXIT
-#endif
+#endif // INCLUDED_IMATHPLANE_H
//
// Copyright (c) 2002, Industrial Light & Magic, a division of Lucas
// Digital Ltd. LLC
-//
+//
// All rights reserved.
-//
+//
// Redistribution and use in source and binary forms, with or without
// modification, are permitted provided that the following conditions are
// met:
// distribution.
// * Neither the name of Industrial Light & Magic nor the names of
// its contributors may be used to endorse or promote products derived
-// from this software without specific prior written permission.
-//
+// from this software without specific prior written permission.
+//
// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
//
// ImathPlatform.h
//
-// This file contains functions and constants which aren't
-// provided by the system libraries, compilers, or includes on
+// This file contains functions and constants which aren't
+// provided by the system libraries, compilers, or includes on
// certain platforms.
//
//----------------------------------------------------------------------------
///////////////////////////////////////////////////////////////////////////
//
-// Copyright (c) 2002, Industrial Light & Magic, a division of Lucas
+// Copyright (c) 2002-2012, Industrial Light & Magic, a division of Lucas
// Digital Ltd. LLC
-//
+//
// All rights reserved.
-//
+//
// Redistribution and use in source and binary forms, with or without
// modification, are permitted provided that the following conditions are
// met:
// distribution.
// * Neither the name of Industrial Light & Magic nor the names of
// its contributors may be used to endorse or promote products derived
-// from this software without specific prior written permission.
-//
+// from this software without specific prior written permission.
+//
// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
#include "ImathExc.h"
#include "ImathMatrix.h"
+#include "ImathNamespace.h"
#include <iostream>
-namespace Imath {
+IMATH_INTERNAL_NAMESPACE_HEADER_ENTER
#if (defined _WIN32 || defined _WIN64) && defined _MSC_VER
// Disable MS VC++ warnings about conversion from double to float
Quat<T> & setAxisAngle (const Vec3<T> &axis, T radians);
Quat<T> & setRotation (const Vec3<T> &fromDirection,
- const Vec3<T> &toDirection);
+ const Vec3<T> &toDirection);
T angle () const;
Vec3<T> axis () const;
private:
void setRotationInternal (const Vec3<T> &f0,
- const Vec3<T> &t0,
- Quat<T> &q);
+ const Vec3<T> &t0,
+ Quat<T> &q);
};
template<class T>
-Quat<T> squad (const Quat<T> &q1, const Quat<T> &q2,
- const Quat<T> &qa, const Quat<T> &qb, T t);
+Quat<T> squad (const Quat<T> &q1, const Quat<T> &q2,
+ const Quat<T> &qa, const Quat<T> &qb, T t);
template<class T>
-void intermediate (const Quat<T> &q0, const Quat<T> &q1,
- const Quat<T> &q2, const Quat<T> &q3,
- Quat<T> &qa, Quat<T> &qb);
+void intermediate (const Quat<T> &q0, const Quat<T> &q1,
+ const Quat<T> &q2, const Quat<T> &q3,
+ Quat<T> &qa, Quat<T> &qb);
template<class T>
Matrix33<T> operator * (const Matrix33<T> &M, const Quat<T> &q);
{
if (T l = length())
{
- r /= l;
- v /= l;
+ r /= l;
+ v /= l;
}
else
{
- r = 1;
- v = Vec3<T> (0);
+ r = 1;
+ v = Vec3<T> (0);
}
return *this;
Quat<T>::normalized () const
{
if (T l = length())
- return Quat (r / l, v / l);
+ return Quat (r / l, v / l);
return Quat();
}
template<class T>
-inline T
+inline T
Quat<T>::euclideanInnerProduct (const Quat<T> &q) const
{
return r * q.r + v.x * q.v.x + v.y * q.v.y + v.z * q.v.z;
T s = 1 - t;
Quat<T> q = sinx_over_x (s * a) / sinx_over_x (a) * s * q1 +
- sinx_over_x (t * a) / sinx_over_x (a) * t * q2;
+ sinx_over_x (t * a) / sinx_over_x (a) * t * q2;
return q.normalized();
}
Quat<T>
spline (const Quat<T> &q0, const Quat<T> &q1,
const Quat<T> &q2, const Quat<T> &q3,
- T t)
+ T t)
{
//
// Spherical Cubic Spline Interpolation -
// Given a set of quaternion keys: q0, q1, q2, q3,
// this routine does the interpolation between
// q1 and q2 by constructing two intermediate
- // quaternions: qa and qb. The qa and qb are
- // computed by the intermediate function to
+ // quaternions: qa and qb. The qa and qb are
+ // computed by the intermediate function to
// guarantee the continuity of tangents across
// adjacent cubic segments. The qa represents in-tangent
// for q1 and the qb represents the out-tangent for q2.
- //
- // The q1 q2 is the cubic segment being interpolated.
- // The q0 is from the previous adjacent segment and q3 is
+ //
+ // The q1 q2 is the cubic segment being interpolated.
+ // The q0 is from the previous adjacent segment and q3 is
// from the next adjacent segment. The q0 and q3 are used
// in computing qa and qb.
- //
+ //
Quat<T> qa = intermediate (q0, q1, q2);
Quat<T> qb = intermediate (q1, q2, q3);
// Spherical Quadrangle Interpolation -
// from Advanced Animation and Rendering
// Techniques by Watt and Watt, Page 366:
- // It constructs a spherical cubic interpolation as
- // a series of three spherical linear interpolations
- // of a quadrangle of unit quaternions.
- //
-
+ // It constructs a spherical cubic interpolation as
+ // a series of three spherical linear interpolations
+ // of a quadrangle of unit quaternions.
+ //
+
Quat<T> r1 = slerp (q1, q2, t);
Quat<T> r2 = slerp (qa, qb, t);
Quat<T> result = slerp (r1, r2, 2 * t * (1 - t));
//
// From advanced Animation and Rendering
// Techniques by Watt and Watt, Page 366:
- // computing the inner quadrangle
+ // computing the inner quadrangle
// points (qa and qb) to guarantee tangent
// continuity.
- //
+ //
Quat<T> q1inv = q1.inverse();
Quat<T> c1 = q1inv * q2;
Quat<T>::log () const
{
//
- // For unit quaternion, from Advanced Animation and
+ // For unit quaternion, from Advanced Animation and
// Rendering Techniques by Watt and Watt, Page 366:
//
T theta = Math<T>::acos (std::min (r, (T) 1.0));
if (theta == 0)
- return Quat<T> (0, v);
-
+ return Quat<T> (0, v);
+
T sintheta = Math<T>::sin (theta);
-
+
T k;
if (abs (sintheta) < 1 && abs (theta) >= limits<T>::max() * abs (sintheta))
- k = 1;
+ k = 1;
else
- k = theta / sintheta;
+ k = theta / sintheta;
return Quat<T> ((T) 0, v.x * k, v.y * k, v.z * k);
}
T theta = v.length();
T sintheta = Math<T>::sin (theta);
-
+
T k;
if (abs (theta) < 1 && abs (sintheta) >= limits<T>::max() * abs (theta))
- k = 1;
+ k = 1;
else
- k = sintheta / theta;
+ k = sintheta / theta;
T costheta = Math<T>::cos (theta);
if ((f0 ^ t0) >= 0)
{
- //
- // The rotation angle is less than or equal to pi/2.
- //
+ //
+ // The rotation angle is less than or equal to pi/2.
+ //
- setRotationInternal (f0, t0, *this);
+ setRotationInternal (f0, t0, *this);
}
else
{
- //
- // The angle is greater than pi/2. After computing h0,
- // which is halfway between f0 and t0, we rotate first
- // from f0 to h0, then from h0 to t0.
- //
-
- Vec3<T> h0 = (f0 + t0).normalized();
-
- if ((h0 ^ h0) != 0)
- {
- setRotationInternal (f0, h0, *this);
-
- Quat<T> q;
- setRotationInternal (h0, t0, q);
-
- *this *= q;
- }
- else
- {
- //
- // f0 and t0 point in exactly opposite directions.
- // Pick an arbitrary axis that is orthogonal to f0,
- // and rotate by pi.
- //
-
- r = T (0);
-
- Vec3<T> f02 = f0 * f0;
-
- if (f02.x <= f02.y && f02.x <= f02.z)
- v = (f0 % Vec3<T> (1, 0, 0)).normalized();
- else if (f02.y <= f02.z)
- v = (f0 % Vec3<T> (0, 1, 0)).normalized();
- else
- v = (f0 % Vec3<T> (0, 0, 1)).normalized();
- }
+ //
+ // The angle is greater than pi/2. After computing h0,
+ // which is halfway between f0 and t0, we rotate first
+ // from f0 to h0, then from h0 to t0.
+ //
+
+ Vec3<T> h0 = (f0 + t0).normalized();
+
+ if ((h0 ^ h0) != 0)
+ {
+ setRotationInternal (f0, h0, *this);
+
+ Quat<T> q;
+ setRotationInternal (h0, t0, q);
+
+ *this *= q;
+ }
+ else
+ {
+ //
+ // f0 and t0 point in exactly opposite directions.
+ // Pick an arbitrary axis that is orthogonal to f0,
+ // and rotate by pi.
+ //
+
+ r = T (0);
+
+ Vec3<T> f02 = f0 * f0;
+
+ if (f02.x <= f02.y && f02.x <= f02.z)
+ v = (f0 % Vec3<T> (1, 0, 0)).normalized();
+ else if (f02.y <= f02.z)
+ v = (f0 % Vec3<T> (0, 1, 0)).normalized();
+ else
+ v = (f0 % Vec3<T> (0, 0, 1)).normalized();
+ }
}
return *this;
Quat<T>::toMatrix33() const
{
return Matrix33<T> (1 - 2 * (v.y * v.y + v.z * v.z),
- 2 * (v.x * v.y + v.z * r),
- 2 * (v.z * v.x - v.y * r),
+ 2 * (v.x * v.y + v.z * r),
+ 2 * (v.z * v.x - v.y * r),
- 2 * (v.x * v.y - v.z * r),
- 1 - 2 * (v.z * v.z + v.x * v.x),
- 2 * (v.y * v.z + v.x * r),
+ 2 * (v.x * v.y - v.z * r),
+ 1 - 2 * (v.z * v.z + v.x * v.x),
+ 2 * (v.y * v.z + v.x * r),
- 2 * (v.z * v.x + v.y * r),
- 2 * (v.y * v.z - v.x * r),
- 1 - 2 * (v.y * v.y + v.x * v.x));
+ 2 * (v.z * v.x + v.y * r),
+ 2 * (v.y * v.z - v.x * r),
+ 1 - 2 * (v.y * v.y + v.x * v.x));
}
template<class T>
Quat<T>::toMatrix44() const
{
return Matrix44<T> (1 - 2 * (v.y * v.y + v.z * v.z),
- 2 * (v.x * v.y + v.z * r),
- 2 * (v.z * v.x - v.y * r),
- 0,
- 2 * (v.x * v.y - v.z * r),
- 1 - 2 * (v.z * v.z + v.x * v.x),
- 2 * (v.y * v.z + v.x * r),
- 0,
- 2 * (v.z * v.x + v.y * r),
- 2 * (v.y * v.z - v.x * r),
- 1 - 2 * (v.y * v.y + v.x * v.x),
- 0,
- 0,
- 0,
- 0,
- 1);
+ 2 * (v.x * v.y + v.z * r),
+ 2 * (v.z * v.x - v.y * r),
+ 0,
+ 2 * (v.x * v.y - v.z * r),
+ 1 - 2 * (v.z * v.z + v.x * v.x),
+ 2 * (v.y * v.z + v.x * r),
+ 0,
+ 2 * (v.z * v.x + v.y * r),
+ 2 * (v.y * v.z - v.x * r),
+ 1 - 2 * (v.y * v.y + v.x * v.x),
+ 0,
+ 0,
+ 0,
+ 0,
+ 1);
}
operator << (std::ostream &o, const Quat<T> &q)
{
return o << "(" << q.r
- << " " << q.v.x
- << " " << q.v.y
- << " " << q.v.z
- << ")";
+ << " " << q.v.x
+ << " " << q.v.y
+ << " " << q.v.z
+ << ")";
}
operator * (const Quat<T> &q1, const Quat<T> &q2)
{
return Quat<T> (q1.r * q2.r - (q1.v ^ q2.v),
- q1.r * q2.v + q1.v * q2.r + q1.v % q2.v);
+ q1.r * q2.v + q1.v * q2.r + q1.v % q2.v);
}
#pragma warning(default:4244)
#endif
-} // namespace Imath
+IMATH_INTERNAL_NAMESPACE_HEADER_EXIT
-#endif
+#endif // INCLUDED_IMATHQUAT_H
-
///////////////////////////////////////////////////////////////////////////
//
-// Copyright (c) 2002, Industrial Light & Magic, a division of Lucas
+// Copyright (c) 2002-2012, Industrial Light & Magic, a division of Lucas
// Digital Ltd. LLC
-//
+//
// All rights reserved.
-//
+//
// Redistribution and use in source and binary forms, with or without
// modification, are permitted provided that the following conditions are
// met:
// distribution.
// * Neither the name of Industrial Light & Magic nor the names of
// its contributors may be used to endorse or promote products derived
-// from this software without specific prior written permission.
-//
+// from this software without specific prior written permission.
+//
// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
#include "ImathRandom.h"
#include "ImathInt64.h"
-namespace Imath {
+IMATH_INTERNAL_NAMESPACE_SOURCE_ENTER
namespace {
//
// sequence,
//
// x[n+1] = (a * x[n] + c) % m,
- //
+ //
// where a and c are as specified below, and m == (1 << 48)
//
//
Int64 x = (Int64 (state[2]) << 32) |
- (Int64 (state[1]) << 16) |
- Int64 (state[0]);
+ (Int64 (state[1]) << 16) |
+ Int64 (state[0]);
//
// Compute x[n+1], except for the "modulo m" part.
{
//
// Generate double-precision floating-point values between 0.0 and 1.0:
- //
+ //
// The exponent is set to 0x3ff, which indicates a value greater
// than or equal to 1.0, and less than 2.0. The 48 most significant
// bits of the significand (mantissa) are filled with pseudo-random
// between 1.0 and 1.99999999999999978. Subtracting 1.0 from those
// values produces numbers between 0.0 and 0.99999999999999978, that
// is, between 0.0 and 1.0-DBL_EPSILON.
- //
+ //
rand48Next (state);
union {double d; Int64 i;} u;
u.i = (Int64 (0x3ff) << 52) | // sign and exponent
- (Int64 (state[2]) << 36) | // significand
- (Int64 (state[1]) << 20) |
- (Int64 (state[0]) << 4) |
- (Int64 (state[2]) >> 12);
+ (Int64 (state[2]) << 36) | // significand
+ (Int64 (state[1]) << 20) |
+ (Int64 (state[0]) << 4) |
+ (Int64 (state[2]) >> 12);
return u.d - 1;
}
double
drand48 ()
{
- return Imath::erand48 (staticState);
+ return IMATH_INTERNAL_NAMESPACE::erand48 (staticState);
}
{
//
// Generate uniformly distributed integers between 0 and 0x7fffffff.
- //
+ //
rand48Next (state);
return ((long int) (state[2]) << 15) |
- ((long int) (state[1]) >> 1);
+ ((long int) (state[1]) >> 1);
}
long int
lrand48 ()
{
- return Imath::nrand48 (staticState);
+ return IMATH_INTERNAL_NAMESPACE::nrand48 (staticState);
}
{
//
// Generate single-precision floating-point values between 0.0 and 1.0:
- //
+ //
// The exponent is set to 0x7f, which indicates a value greater than
// or equal to 1.0, and less than 2.0. The 23 bits of the significand
// (mantissa) are filled with pseudo-random bits generated by
// point values between 1.0 and 1.99999988. Subtracting 1.0 from
// those values produces numbers between 0.0 and 0.99999988, that is,
// between 0.0 and 1.0-FLT_EPSILON.
- //
+ //
next ();
return u.f - 1;
}
-} // namespace Imath
+IMATH_INTERNAL_NAMESPACE_SOURCE_EXIT
///////////////////////////////////////////////////////////////////////////
//
-// Copyright (c) 2002, Industrial Light & Magic, a division of Lucas
+// Copyright (c) 2002-2012, Industrial Light & Magic, a division of Lucas
// Digital Ltd. LLC
-//
+//
// All rights reserved.
-//
+//
// Redistribution and use in source and binary forms, with or without
// modification, are permitted provided that the following conditions are
// met:
// distribution.
// * Neither the name of Industrial Light & Magic nor the names of
// its contributors may be used to endorse or promote products derived
-// from this software without specific prior written permission.
-//
+// from this software without specific prior written permission.
+//
// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
//
//-----------------------------------------------------------------------------
+#include "ImathNamespace.h"
+#include "ImathExport.h"
+
#include <stdlib.h>
#include <math.h>
-namespace Imath {
+IMATH_INTERNAL_NAMESPACE_HEADER_ENTER
//-----------------------------------------------
// Fast random-number generator that generates
// length of 2^32.
//-----------------------------------------------
-class Rand32
+class IMATH_EXPORT Rand32
{
public:
//------------
Rand32 (unsigned long int seed = 0);
-
+
//--------------------------------
// Re-initialize with a given seed
//------------
Rand48 (unsigned long int seed = 0);
-
+
//--------------------------------
// Re-initialize with a given seed
//------------------------------------------------------------
template <class Vec, class Rand>
-Vec
+Vec
solidSphereRand (Rand &rand);
//-------------------------------------------------------------
template <class Vec, class Rand>
-Vec
+Vec
hollowSphereRand (Rand &rand);
// erand48(), nrand48() and friends
//---------------------------------
-double erand48 (unsigned short state[3]);
-double drand48 ();
-long int nrand48 (unsigned short state[3]);
-long int lrand48 ();
-void srand48 (long int seed);
+IMATH_EXPORT double erand48 (unsigned short state[3]);
+IMATH_EXPORT double drand48 ();
+IMATH_EXPORT long int nrand48 (unsigned short state[3]);
+IMATH_EXPORT long int lrand48 ();
+IMATH_EXPORT void srand48 (long int seed);
//---------------
_state[0] = (unsigned short int) (seed & 0xFFFF);
_state[1] = (unsigned short int) ((seed >> 16) & 0xFFFF);
- _state[2] = (unsigned short int) (seed & 0xFFFF);
+ _state[2] = (unsigned short int) (seed & 0xFFFF);
}
-inline
+inline
Rand48::Rand48 (unsigned long int seed)
{
init (seed);
inline bool
Rand48::nextb ()
{
- return Imath::nrand48 (_state) & 1;
+ return nrand48 (_state) & 1;
}
inline long int
Rand48::nexti ()
{
- return Imath::nrand48 (_state);
+ return nrand48 (_state);
}
inline double
Rand48::nextf ()
{
- return Imath::erand48 (_state);
+ return erand48 (_state);
}
do
{
- for (unsigned int i = 0; i < Vec::dimensions(); i++)
- v[i] = (typename Vec::BaseType) rand.nextf (-1, 1);
+ for (unsigned int i = 0; i < Vec::dimensions(); i++)
+ v[i] = (typename Vec::BaseType) rand.nextf (-1, 1);
}
while (v.length2() > 1);
do
{
- for (unsigned int i = 0; i < Vec::dimensions(); i++)
- v[i] = (typename Vec::BaseType) rand.nextf (-1, 1);
+ for (unsigned int i = 0; i < Vec::dimensions(); i++)
+ v[i] = (typename Vec::BaseType) rand.nextf (-1, 1);
- length = v.length();
+ length = v.length();
}
while (length > 1 || length == 0);
float x; // Note: to avoid numerical problems with very small
float y; // numbers, we make these variables singe-precision
float length2; // floats, but later we call the double-precision log()
- // and sqrt() functions instead of logf() and sqrtf().
+ // and sqrt() functions instead of logf() and sqrtf().
do
{
- x = float (rand.nextf (-1, 1));
- y = float (rand.nextf (-1, 1));
- length2 = x * x + y * y;
+ x = float (rand.nextf (-1, 1));
+ y = float (rand.nextf (-1, 1));
+ length2 = x * x + y * y;
}
while (length2 >= 1 || length2 == 0);
return hollowSphereRand <Vec> (rand) * gaussRand (rand);
}
-} // namespace Imath
+IMATH_INTERNAL_NAMESPACE_HEADER_EXIT
-#endif
+#endif // INCLUDED_IMATHRANDOM_H
///////////////////////////////////////////////////////////////////////////
//
-// Copyright (c) 2002, Industrial Light & Magic, a division of Lucas
+// Copyright (c) 2002-2012, Industrial Light & Magic, a division of Lucas
// Digital Ltd. LLC
-//
+//
// All rights reserved.
-//
+//
// Redistribution and use in source and binary forms, with or without
// modification, are permitted provided that the following conditions are
// met:
// distribution.
// * Neither the name of Industrial Light & Magic nor the names of
// its contributors may be used to endorse or promote products derived
-// from this software without specific prior written permission.
-//
+// from this software without specific prior written permission.
+//
// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
//
//---------------------------------------------------------------------
-#include <ImathMath.h>
+#include "ImathMath.h"
+#include "ImathNamespace.h"
#include <complex>
-namespace Imath {
+IMATH_INTERNAL_NAMESPACE_HEADER_ENTER
//--------------------------------------------------------------------------
// Find the real solutions of a linear, quadratic or cubic equation:
{
if (a != 0)
{
- x = -b / a;
- return 1;
+ x = -b / a;
+ return 1;
}
else if (b != 0)
{
- return 0;
+ return 0;
}
else
{
- return -1;
+ return -1;
}
}
{
if (a == 0)
{
- return solveLinear (b, c, x[0]);
- }
- else
- {
- T D = b * b - 4 * a * c;
-
- if (D > 0)
- {
- T s = Math<T>::sqrt (D);
- T q = -(b + (b > 0 ? 1 : -1) * s) / T(2);
-
- x[0] = q / a;
- x[1] = c / q;
- return 2;
- }
- if (D == 0)
- {
- x[0] = -b / (2 * a);
- return 1;
+ return solveLinear (b, c, x[0]);
}
else
{
- return 0;
- }
+ T D = b * b - 4 * a * c;
+
+ if (D > 0)
+ {
+ T s = Math<T>::sqrt (D);
+ T q = -(b + (b > 0 ? 1 : -1) * s) / T(2);
+
+ x[0] = q / a;
+ x[1] = c / q;
+ return 2;
+ }
+ if (D == 0)
+ {
+ x[0] = -b / (2 * a);
+ return 1;
+ }
+ else
+ {
+ return 0;
+ }
}
}
if (D == 0 && p3 == 0)
{
- x[0] = -r / 3;
- x[1] = -r / 3;
- x[2] = -r / 3;
- return 1;
+ x[0] = -r / 3;
+ x[1] = -r / 3;
+ x[2] = -r / 3;
+ return 1;
}
std::complex<T> u = std::pow (-q / 2 + std::sqrt (std::complex<T> (D)),
- T (1) / T (3));
+ T (1) / T (3));
std::complex<T> v = -p / (T (3) * u);
const T sqrt3 = T (1.73205080756887729352744634150587); // enough digits
- // for long double
+ // for long double
std::complex<T> y0 (u + v);
std::complex<T> y1 (-(u + v) / T (2) +
- (u - v) / T (2) * std::complex<T> (0, sqrt3));
+ (u - v) / T (2) * std::complex<T> (0, sqrt3));
std::complex<T> y2 (-(u + v) / T (2) -
- (u - v) / T (2) * std::complex<T> (0, sqrt3));
+ (u - v) / T (2) * std::complex<T> (0, sqrt3));
if (D > 0)
{
- x[0] = y0.real() - r / 3;
- return 1;
+ x[0] = y0.real() - r / 3;
+ return 1;
}
else if (D == 0)
{
- x[0] = y0.real() - r / 3;
- x[1] = y1.real() - r / 3;
- return 2;
+ x[0] = y0.real() - r / 3;
+ x[1] = y1.real() - r / 3;
+ return 2;
}
else
{
- x[0] = y0.real() - r / 3;
- x[1] = y1.real() - r / 3;
- x[2] = y2.real() - r / 3;
- return 3;
+ x[0] = y0.real() - r / 3;
+ x[1] = y1.real() - r / 3;
+ x[2] = y2.real() - r / 3;
+ return 3;
}
}
{
if (a == 0)
{
- return solveQuadratic (b, c, d, x);
+ return solveQuadratic (b, c, d, x);
}
else
{
- return solveNormalizedCubic (b / a, c / a, d / a, x);
+ return solveNormalizedCubic (b / a, c / a, d / a, x);
}
}
+IMATH_INTERNAL_NAMESPACE_HEADER_EXIT
-} // namespace Imath
-
-#endif
+#endif // INCLUDED_IMATHROOTS_H
--- /dev/null
+///////////////////////////////////////////////////////////////////////////
+//
+// Copyright (c) 2002-2012, Industrial Light & Magic, a division of Lucas
+// Digital Ltd. LLC
+//
+// All rights reserved.
+//
+// Redistribution and use in source and binary forms, with or without
+// modification, are permitted provided that the following conditions are
+// met:
+// * Redistributions of source code must retain the above copyright
+// notice, this list of conditions and the following disclaimer.
+// * Redistributions in binary form must reproduce the above
+// copyright notice, this list of conditions and the following disclaimer
+// in the documentation and/or other materials provided with the
+// distribution.
+// * Neither the name of Industrial Light & Magic nor the names of
+// its contributors may be used to endorse or promote products derived
+// from this software without specific prior written permission.
+//
+// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+//
+///////////////////////////////////////////////////////////////////////////
+
+
+
+
+//----------------------------------------------------------------------------
+//
+// Specializations of the Shear6<T> template.
+//
+//----------------------------------------------------------------------------
+
+#include "ImathShear.h"
+
+IMATH_INTERNAL_NAMESPACE_SOURCE_ENTER
+
+
+
+// empty
+
+
+
+IMATH_INTERNAL_NAMESPACE_SOURCE_EXIT
///////////////////////////////////////////////////////////////////////////
//
-// Copyright (c) 2004, Industrial Light & Magic, a division of Lucas
+// Copyright (c) 2004-2012, Industrial Light & Magic, a division of Lucas
// Digital Ltd. LLC
-//
+//
// All rights reserved.
-//
+//
// Redistribution and use in source and binary forms, with or without
// modification, are permitted provided that the following conditions are
// met:
// distribution.
// * Neither the name of Industrial Light & Magic nor the names of
// its contributors may be used to endorse or promote products derived
-// from this software without specific prior written permission.
-//
+// from this software without specific prior written permission.
+//
// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
#include "ImathLimits.h"
#include "ImathMath.h"
#include "ImathVec.h"
-
+#include "ImathNamespace.h"
#include <iostream>
-namespace Imath {
-
-
-
+IMATH_INTERNAL_NAMESPACE_HEADER_ENTER
template <class T> class Shear6
{
Shear6 (T XY, T XZ, T YZ); // (XY XZ YZ 0 0 0)
Shear6 (const Vec3<T> &v); // (v.x v.y v.z 0 0 0)
template <class S> // (v.x v.y v.z 0 0 0)
- Shear6 (const Vec3<S> &v);
+ Shear6 (const Vec3<S> &v);
Shear6 (T XY, T XZ, T YZ, // (XY XZ YZ YX ZX ZY)
- T YX, T ZX, T ZY);
+ T YX, T ZX, T ZY);
//---------------------------------
template <class S> Shear6 (const Shear6<S> &h);
const Shear6 & operator = (const Shear6 &h);
- template <class S>
- const Shear6 & operator = (const Vec3<S> &v);
+ template <class S>
+ const Shear6 & operator = (const Vec3<S> &v);
//----------------------
void setValue (const Shear6<S> &h);
template <class S>
- void getValue (S &XY, S &XZ, S &YZ,
- S &YX, S &ZX, S &ZY) const;
+ void getValue (S &XY, S &XZ, S &YZ,
+ S &YX, S &ZX, S &ZY) const;
template <class S>
void getValue (Shear6<S> &h) const;
inline bool
Shear6<T>::operator == (const Shear6<S> &h) const
{
- return xy == h.xy && xz == h.xz && yz == h.yz &&
- yx == h.yx && zx == h.zx && zy == h.zy;
+ return xy == h.xy && xz == h.xz && yz == h.yz &&
+ yx == h.yx && zx == h.zx && zy == h.zy;
}
template <class T>
Shear6<T>::operator != (const Shear6<S> &h) const
{
return xy != h.xy || xz != h.xz || yz != h.yz ||
- yx != h.yx || zx != h.zx || zy != h.zy;
+ yx != h.yx || zx != h.zx || zy != h.zy;
}
template <class T>
Shear6<T>::equalWithAbsError (const Shear6<T> &h, T e) const
{
for (int i = 0; i < 6; i++)
- if (!Imath::equalWithAbsError ((*this)[i], h[i], e))
- return false;
+ if (!IMATH_INTERNAL_NAMESPACE::equalWithAbsError ((*this)[i], h[i], e))
+ return false;
return true;
}
Shear6<T>::equalWithRelError (const Shear6<T> &h, T e) const
{
for (int i = 0; i < 6; i++)
- if (!Imath::equalWithRelError ((*this)[i], h[i], e))
- return false;
+ if (!IMATH_INTERNAL_NAMESPACE::equalWithRelError ((*this)[i], h[i], e))
+ return false;
return true;
}
Shear6<T>::operator + (const Shear6 &h) const
{
return Shear6 (xy + h.xy, xz + h.xz, yz + h.yz,
- yx + h.yx, zx + h.zx, zy + h.zy);
+ yx + h.yx, zx + h.zx, zy + h.zy);
}
template <class T>
Shear6<T>::operator - (const Shear6 &h) const
{
return Shear6 (xy - h.xy, xz - h.xz, yz - h.yz,
- yx - h.yx, zx - h.zx, zy - h.zy);
+ yx - h.yx, zx - h.zx, zy - h.zy);
}
template <class T>
inline Shear6<T>
Shear6<T>::operator * (const Shear6 &h) const
{
- return Shear6 (xy * h.xy, xz * h.xz, yz * h.yz,
- yx * h.yx, zx * h.zx, zy * h.zy);
+ return Shear6 (xy * h.xy, xz * h.xz, yz * h.yz,
+ yx * h.yx, zx * h.zx, zy * h.zy);
}
template <class T>
Shear6<T>::operator * (T a) const
{
return Shear6 (xy * a, xz * a, yz * a,
- yx * a, zx * a, zy * a);
+ yx * a, zx * a, zy * a);
}
template <class T>
Shear6<T>::operator / (const Shear6 &h) const
{
return Shear6 (xy / h.xy, xz / h.xz, yz / h.yz,
- yx / h.yx, zx / h.zx, zy / h.zy);
+ yx / h.yx, zx / h.zx, zy / h.zy);
}
template <class T>
Shear6<T>::operator / (T a) const
{
return Shear6 (xy / a, xz / a, yz / a,
- yx / a, zx / a, zy / a);
+ yx / a, zx / a, zy / a);
}
std::ostream &
operator << (std::ostream &s, const Shear6<T> &h)
{
- return s << '('
- << h.xy << ' ' << h.xz << ' ' << h.yz
- << h.yx << ' ' << h.zx << ' ' << h.zy
- << ')';
+ return s << '('
+ << h.xy << ' ' << h.xz << ' ' << h.yz
+ << h.yx << ' ' << h.zx << ' ' << h.zy
+ << ')';
}
operator * (S a, const Shear6<T> &h)
{
return Shear6<T> (a * h.xy, a * h.xz, a * h.yz,
- a * h.yx, a * h.zx, a * h.zy);
+ a * h.yx, a * h.zx, a * h.zy);
}
-} // namespace Imath
+IMATH_INTERNAL_NAMESPACE_HEADER_EXIT
-#endif
+#endif // INCLUDED_IMATHSHEAR_H
///////////////////////////////////////////////////////////////////////////
//
-// Copyright (c) 2002, Industrial Light & Magic, a division of Lucas
+// Copyright (c) 2002-2012, Industrial Light & Magic, a division of Lucas
// Digital Ltd. LLC
-//
+//
// All rights reserved.
-//
+//
// Redistribution and use in source and binary forms, with or without
// modification, are permitted provided that the following conditions are
// met:
// distribution.
// * Neither the name of Industrial Light & Magic nor the names of
// its contributors may be used to endorse or promote products derived
-// from this software without specific prior written permission.
-//
+// from this software without specific prior written permission.
+//
// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
#include "ImathVec.h"
#include "ImathBox.h"
#include "ImathLine.h"
+#include "ImathNamespace.h"
-namespace Imath {
+IMATH_INTERNAL_NAMESPACE_HEADER_ENTER
template <class T>
class Sphere3
if (discr < 0.0)
{
- // line and Sphere3 do not intersect
+ // line and Sphere3 do not intersect
- doesIntersect = false;
+ doesIntersect = false;
}
else
{
- // t0: (-B - sqrt(B^2 - 4AC)) / 2A (A = 1)
+ // t0: (-B - sqrt(B^2 - 4AC)) / 2A (A = 1)
- T sqroot = Math<T>::sqrt(discr);
- t = (-B - sqroot) * T(0.5);
+ T sqroot = Math<T>::sqrt(discr);
+ t = (-B - sqroot) * T(0.5);
- if (t < 0.0)
- {
- // no intersection, try t1: (-B + sqrt(B^2 - 4AC)) / 2A (A = 1)
+ if (t < 0.0)
+ {
+ // no intersection, try t1: (-B + sqrt(B^2 - 4AC)) / 2A (A = 1)
- t = (-B + sqroot) * T(0.5);
- }
+ t = (-B + sqroot) * T(0.5);
+ }
- if (t < 0.0)
- doesIntersect = false;
+ if (t < 0.0)
+ doesIntersect = false;
}
return doesIntersect;
if (intersectT (line, t))
{
- intersection = line(t);
- return true;
+ intersection = line(t);
+ return true;
}
else
{
- return false;
+ return false;
}
}
+IMATH_INTERNAL_NAMESPACE_HEADER_EXIT
-} //namespace Imath
-
-#endif
+#endif // INCLUDED_IMATHSPHERE_H
///////////////////////////////////////////////////////////////////////////
//
-// Copyright (c) 2002, Industrial Light & Magic, a division of Lucas
+// Copyright (c) 2002-2012, Industrial Light & Magic, a division of Lucas
// Digital Ltd. LLC
-//
+//
// All rights reserved.
-//
+//
// Redistribution and use in source and binary forms, with or without
// modification, are permitted provided that the following conditions are
// met:
// distribution.
// * Neither the name of Industrial Light & Magic nor the names of
// its contributors may be used to endorse or promote products derived
-// from this software without specific prior written permission.
-//
+// from this software without specific prior written permission.
+//
// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
//----------------------------------------------------------------------------
#include "ImathVec.h"
+#include "ImathExport.h"
#if (defined _WIN32 || defined _WIN64) && defined _MSC_VER
// suppress exception specification warnings
#endif
-namespace Imath {
+IMATH_INTERNAL_NAMESPACE_SOURCE_ENTER
namespace
{
// Vec2<short>
-template <>
+template <>
+IMATH_EXPORT
short
Vec2<short>::length () const
{
}
template <>
+IMATH_EXPORT
const Vec2<short> &
Vec2<short>::normalize ()
{
}
template <>
+IMATH_EXPORT
const Vec2<short> &
-Vec2<short>::normalizeExc () throw (Iex::MathExc)
+Vec2<short>::normalizeExc ()
{
if ((x == 0) && (y == 0))
throw NullVecExc ("Cannot normalize null vector.");
}
template <>
+IMATH_EXPORT
const Vec2<short> &
Vec2<short>::normalizeNonNull ()
{
}
template <>
+IMATH_EXPORT
Vec2<short>
Vec2<short>::normalized () const
{
}
template <>
+IMATH_EXPORT
Vec2<short>
-Vec2<short>::normalizedExc () const throw (Iex::MathExc)
+Vec2<short>::normalizedExc () const
{
if ((x == 0) && (y == 0))
throw NullVecExc ("Cannot normalize null vector.");
}
template <>
+IMATH_EXPORT
Vec2<short>
Vec2<short>::normalizedNonNull () const
{
// Vec2<int>
-template <>
+template <>
+IMATH_EXPORT
int
Vec2<int>::length () const
{
}
template <>
+IMATH_EXPORT
const Vec2<int> &
Vec2<int>::normalize ()
{
}
template <>
+IMATH_EXPORT
const Vec2<int> &
-Vec2<int>::normalizeExc () throw (Iex::MathExc)
+Vec2<int>::normalizeExc ()
{
if ((x == 0) && (y == 0))
throw NullVecExc ("Cannot normalize null vector.");
}
template <>
+IMATH_EXPORT
const Vec2<int> &
Vec2<int>::normalizeNonNull ()
{
}
template <>
+IMATH_EXPORT
Vec2<int>
Vec2<int>::normalized () const
{
}
template <>
+IMATH_EXPORT
Vec2<int>
-Vec2<int>::normalizedExc () const throw (Iex::MathExc)
+Vec2<int>::normalizedExc () const
{
if ((x == 0) && (y == 0))
throw NullVecExc ("Cannot normalize null vector.");
}
template <>
+IMATH_EXPORT
Vec2<int>
Vec2<int>::normalizedNonNull () const
{
// Vec3<short>
-template <>
+template <>
+IMATH_EXPORT
short
Vec3<short>::length () const
{
}
template <>
+IMATH_EXPORT
const Vec3<short> &
Vec3<short>::normalize ()
{
}
template <>
+IMATH_EXPORT
const Vec3<short> &
-Vec3<short>::normalizeExc () throw (Iex::MathExc)
+Vec3<short>::normalizeExc ()
{
if ((x == 0) && (y == 0) && (z == 0))
throw NullVecExc ("Cannot normalize null vector.");
}
template <>
+IMATH_EXPORT
const Vec3<short> &
Vec3<short>::normalizeNonNull ()
{
}
template <>
+IMATH_EXPORT
Vec3<short>
Vec3<short>::normalized () const
{
}
template <>
+IMATH_EXPORT
Vec3<short>
-Vec3<short>::normalizedExc () const throw (Iex::MathExc)
+Vec3<short>::normalizedExc () const
{
if ((x == 0) && (y == 0) && (z == 0))
throw NullVecExc ("Cannot normalize null vector.");
}
template <>
+IMATH_EXPORT
Vec3<short>
Vec3<short>::normalizedNonNull () const
{
// Vec3<int>
-template <>
+template <>
+IMATH_EXPORT
int
Vec3<int>::length () const
{
}
template <>
+IMATH_EXPORT
const Vec3<int> &
Vec3<int>::normalize ()
{
}
template <>
+IMATH_EXPORT
const Vec3<int> &
-Vec3<int>::normalizeExc () throw (Iex::MathExc)
+Vec3<int>::normalizeExc ()
{
if ((x == 0) && (y == 0) && (z == 0))
throw NullVecExc ("Cannot normalize null vector.");
}
template <>
+IMATH_EXPORT
const Vec3<int> &
Vec3<int>::normalizeNonNull ()
{
}
template <>
+IMATH_EXPORT
Vec3<int>
Vec3<int>::normalized () const
{
}
template <>
+IMATH_EXPORT
Vec3<int>
-Vec3<int>::normalizedExc () const throw (Iex::MathExc)
+Vec3<int>::normalizedExc () const
{
if ((x == 0) && (y == 0) && (z == 0))
throw NullVecExc ("Cannot normalize null vector.");
}
template <>
+IMATH_EXPORT
Vec3<int>
Vec3<int>::normalizedNonNull () const
{
// Vec4<short>
-template <>
+template <>
+IMATH_EXPORT
short
Vec4<short>::length () const
{
}
template <>
+IMATH_EXPORT
const Vec4<short> &
Vec4<short>::normalize ()
{
}
template <>
+IMATH_EXPORT
const Vec4<short> &
-Vec4<short>::normalizeExc () throw (Iex::MathExc)
+Vec4<short>::normalizeExc ()
{
if ((x == 0) && (y == 0) && (z == 0) && (w == 0))
throw NullVecExc ("Cannot normalize null vector.");
}
template <>
+IMATH_EXPORT
const Vec4<short> &
Vec4<short>::normalizeNonNull ()
{
}
template <>
+IMATH_EXPORT
Vec4<short>
Vec4<short>::normalized () const
{
}
template <>
+IMATH_EXPORT
Vec4<short>
-Vec4<short>::normalizedExc () const throw (Iex::MathExc)
+Vec4<short>::normalizedExc () const
{
if ((x == 0) && (y == 0) && (z == 0) && (w == 0))
throw NullVecExc ("Cannot normalize null vector.");
}
template <>
+IMATH_EXPORT
Vec4<short>
Vec4<short>::normalizedNonNull () const
{
// Vec4<int>
-template <>
+template <>
+IMATH_EXPORT
int
Vec4<int>::length () const
{
}
template <>
+IMATH_EXPORT
const Vec4<int> &
Vec4<int>::normalize ()
{
}
template <>
+IMATH_EXPORT
const Vec4<int> &
-Vec4<int>::normalizeExc () throw (Iex::MathExc)
+Vec4<int>::normalizeExc ()
{
if ((x == 0) && (y == 0) && (z == 0) && (w == 0))
throw NullVecExc ("Cannot normalize null vector.");
}
template <>
+IMATH_EXPORT
const Vec4<int> &
Vec4<int>::normalizeNonNull ()
{
}
template <>
+IMATH_EXPORT
Vec4<int>
Vec4<int>::normalized () const
{
}
template <>
+IMATH_EXPORT
Vec4<int>
-Vec4<int>::normalizedExc () const throw (Iex::MathExc)
+Vec4<int>::normalizedExc () const
{
if ((x == 0) && (y == 0) && (z == 0) && (w == 0))
throw NullVecExc ("Cannot normalize null vector.");
}
template <>
+IMATH_EXPORT
Vec4<int>
Vec4<int>::normalizedNonNull () const
{
return v;
}
-} // namespace Imath
+IMATH_INTERNAL_NAMESPACE_SOURCE_EXIT
///////////////////////////////////////////////////////////////////////////
//
-// Copyright (c) 2004, Industrial Light & Magic, a division of Lucas
+// Copyright (c) 2004-2012, Industrial Light & Magic, a division of Lucas
// Digital Ltd. LLC
-//
+//
// All rights reserved.
-//
+//
// Redistribution and use in source and binary forms, with or without
// modification, are permitted provided that the following conditions are
// met:
// distribution.
// * Neither the name of Industrial Light & Magic nor the names of
// its contributors may be used to endorse or promote products derived
-// from this software without specific prior written permission.
-//
+// from this software without specific prior written permission.
+//
// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
#include "ImathExc.h"
#include "ImathLimits.h"
#include "ImathMath.h"
+#include "ImathNamespace.h"
#include <iostream>
#endif
-namespace Imath {
+IMATH_INTERNAL_NAMESPACE_HEADER_ENTER
template <class T> class Vec2;
template <class T> class Vec3;
T * getValue ();
const T * getValue () const;
-
+
//---------
// Equality
//---------
T length2 () const;
const Vec2 & normalize (); // modifies *this
- const Vec2 & normalizeExc () throw (Iex::MathExc);
+ const Vec2 & normalizeExc ();
const Vec2 & normalizeNonNull ();
Vec2<T> normalized () const; // does not modify *this
- Vec2<T> normalizedExc () const throw (Iex::MathExc);
+ Vec2<T> normalizedExc () const;
Vec2<T> normalizedNonNull () const;
//--------------------------------------------------------------
// Base type -- in templates, which accept a parameter, V, which
- // could be either a Vec2<T>, a Vec3<T>, or a Vec4<T> you can
+ // could be either a Vec2<T>, a Vec3<T>, or a Vec4<T> you can
// refer to T as V::BaseType
//--------------------------------------------------------------
T length2 () const;
const Vec3 & normalize (); // modifies *this
- const Vec3 & normalizeExc () throw (Iex::MathExc);
+ const Vec3 & normalizeExc ();
const Vec3 & normalizeNonNull ();
Vec3<T> normalized () const; // does not modify *this
- Vec3<T> normalizedExc () const throw (Iex::MathExc);
+ Vec3<T> normalizedExc () const;
Vec3<T> normalizedNonNull () const;
//--------------------------------------------------------------
// Base type -- in templates, which accept a parameter, V, which
- // could be either a Vec2<T>, a Vec3<T>, or a Vec4<T> you can
+ // could be either a Vec2<T>, a Vec3<T>, or a Vec4<T> you can
// refer to T as V::BaseType
//--------------------------------------------------------------
// Access to elements
//-------------------
- T x, y, z, w;
+ T x, y, z, w;
T & operator [] (int i);
const T & operator [] (int i) const;
T length2 () const;
const Vec4 & normalize (); // modifies *this
- const Vec4 & normalizeExc () throw (Iex::MathExc);
+ const Vec4 & normalizeExc ();
const Vec4 & normalizeNonNull ();
Vec4<T> normalized () const; // does not modify *this
- Vec4<T> normalizedExc () const throw (Iex::MathExc);
+ Vec4<T> normalizedExc () const;
Vec4<T> normalizedNonNull () const;
//--------------------------------------------------------------
// Base type -- in templates, which accept a parameter, V, which
- // could be either a Vec2<T>, a Vec3<T>, or a Vec4<T> you can
+ // could be either a Vec2<T>, a Vec3<T>, or a Vec4<T> you can
// refer to T as V::BaseType
//--------------------------------------------------------------
Vec2<short>::normalize ();
template <> const Vec2<short> &
-Vec2<short>::normalizeExc () throw (Iex::MathExc);
+Vec2<short>::normalizeExc ();
template <> const Vec2<short> &
Vec2<short>::normalizeNonNull ();
Vec2<short>::normalized () const;
template <> Vec2<short>
-Vec2<short>::normalizedExc () const throw (Iex::MathExc);
+Vec2<short>::normalizedExc () const;
template <> Vec2<short>
Vec2<short>::normalizedNonNull () const;
Vec2<int>::normalize ();
template <> const Vec2<int> &
-Vec2<int>::normalizeExc () throw (Iex::MathExc);
+Vec2<int>::normalizeExc ();
template <> const Vec2<int> &
Vec2<int>::normalizeNonNull ();
Vec2<int>::normalized () const;
template <> Vec2<int>
-Vec2<int>::normalizedExc () const throw (Iex::MathExc);
+Vec2<int>::normalizedExc () const;
template <> Vec2<int>
Vec2<int>::normalizedNonNull () const;
Vec3<short>::normalize ();
template <> const Vec3<short> &
-Vec3<short>::normalizeExc () throw (Iex::MathExc);
+Vec3<short>::normalizeExc ();
template <> const Vec3<short> &
Vec3<short>::normalizeNonNull ();
Vec3<short>::normalized () const;
template <> Vec3<short>
-Vec3<short>::normalizedExc () const throw (Iex::MathExc);
+Vec3<short>::normalizedExc () const;
template <> Vec3<short>
Vec3<short>::normalizedNonNull () const;
Vec3<int>::normalize ();
template <> const Vec3<int> &
-Vec3<int>::normalizeExc () throw (Iex::MathExc);
+Vec3<int>::normalizeExc ();
template <> const Vec3<int> &
Vec3<int>::normalizeNonNull ();
Vec3<int>::normalized () const;
template <> Vec3<int>
-Vec3<int>::normalizedExc () const throw (Iex::MathExc);
+Vec3<int>::normalizedExc () const;
template <> Vec3<int>
Vec3<int>::normalizedNonNull () const;
Vec4<short>::normalize ();
template <> const Vec4<short> &
-Vec4<short>::normalizeExc () throw (Iex::MathExc);
+Vec4<short>::normalizeExc ();
template <> const Vec4<short> &
Vec4<short>::normalizeNonNull ();
Vec4<short>::normalized () const;
template <> Vec4<short>
-Vec4<short>::normalizedExc () const throw (Iex::MathExc);
+Vec4<short>::normalizedExc () const;
template <> Vec4<short>
Vec4<short>::normalizedNonNull () const;
Vec4<int>::normalize ();
template <> const Vec4<int> &
-Vec4<int>::normalizeExc () throw (Iex::MathExc);
+Vec4<int>::normalizeExc ();
template <> const Vec4<int> &
Vec4<int>::normalizeNonNull ();
Vec4<int>::normalized () const;
template <> Vec4<int>
-Vec4<int>::normalizedExc () const throw (Iex::MathExc);
+Vec4<int>::normalizedExc () const;
template <> Vec4<int>
Vec4<int>::normalizedNonNull () const;
Vec2<T>::equalWithAbsError (const Vec2<T> &v, T e) const
{
for (int i = 0; i < 2; i++)
- if (!Imath::equalWithAbsError ((*this)[i], v[i], e))
- return false;
+ if (!IMATH_INTERNAL_NAMESPACE::equalWithAbsError ((*this)[i], v[i], e))
+ return false;
return true;
}
Vec2<T>::equalWithRelError (const Vec2<T> &v, T e) const
{
for (int i = 0; i < 2; i++)
- if (!Imath::equalWithRelError ((*this)[i], v[i], e))
- return false;
+ if (!IMATH_INTERNAL_NAMESPACE::equalWithRelError ((*this)[i], v[i], e))
+ return false;
return true;
}
{
T absX = (x >= T (0))? x: -x;
T absY = (y >= T (0))? y: -y;
-
+
T max = absX;
if (max < absY)
- max = absY;
+ max = absY;
if (max == T (0))
- return T (0);
+ return T (0);
//
// Do not replace the divisions by max with multiplications by 1/max.
T length2 = dot (*this);
if (length2 < T (2) * limits<T>::smallest())
- return lengthTiny();
+ return lengthTiny();
return Math<T>::sqrt (length2);
}
// produce results less than or equal to 1.
//
- x /= l;
- y /= l;
+ x /= l;
+ y /= l;
}
return *this;
template <class T>
const Vec2<T> &
-Vec2<T>::normalizeExc () throw (Iex::MathExc)
+Vec2<T>::normalizeExc ()
{
T l = length();
if (l == T (0))
- throw NullVecExc ("Cannot normalize null vector.");
+ throw NullVecExc ("Cannot normalize null vector.");
x /= l;
y /= l;
T l = length();
if (l == T (0))
- return Vec2 (T (0));
+ return Vec2 (T (0));
return Vec2 (x / l, y / l);
}
template <class T>
Vec2<T>
-Vec2<T>::normalizedExc () const throw (Iex::MathExc)
+Vec2<T>::normalizedExc () const
{
T l = length();
if (l == T (0))
- throw NullVecExc ("Cannot normalize null vector.");
+ throw NullVecExc ("Cannot normalize null vector.");
return Vec2 (x / l, y / l);
}
if (absW < 1)
{
T m = baseTypeMax() * absW;
-
+
if (vx <= -m || vx >= m || vy <= -m || vy >= m || vz <= -m || vz >= m)
throw InfPointExc ("Cannot normalize point at infinity.");
}
Vec3<T>::equalWithAbsError (const Vec3<T> &v, T e) const
{
for (int i = 0; i < 3; i++)
- if (!Imath::equalWithAbsError ((*this)[i], v[i], e))
- return false;
+ if (!IMATH_INTERNAL_NAMESPACE::equalWithAbsError ((*this)[i], v[i], e))
+ return false;
return true;
}
Vec3<T>::equalWithRelError (const Vec3<T> &v, T e) const
{
for (int i = 0; i < 3; i++)
- if (!Imath::equalWithRelError ((*this)[i], v[i], e))
- return false;
+ if (!IMATH_INTERNAL_NAMESPACE::equalWithRelError ((*this)[i], v[i], e))
+ return false;
return true;
}
Vec3<T>::cross (const Vec3 &v) const
{
return Vec3 (y * v.z - z * v.y,
- z * v.x - x * v.z,
- x * v.y - y * v.x);
+ z * v.x - x * v.z,
+ x * v.y - y * v.x);
}
template <class T>
Vec3<T>::operator % (const Vec3 &v) const
{
return Vec3 (y * v.z - z * v.y,
- z * v.x - x * v.z,
- x * v.y - y * v.x);
+ z * v.x - x * v.z,
+ x * v.y - y * v.x);
}
template <class T>
T absX = (x >= T (0))? x: -x;
T absY = (y >= T (0))? y: -y;
T absZ = (z >= T (0))? z: -z;
-
+
T max = absX;
if (max < absY)
- max = absY;
+ max = absY;
if (max < absZ)
- max = absZ;
+ max = absZ;
if (max == T (0))
- return T (0);
+ return T (0);
//
// Do not replace the divisions by max with multiplications by 1/max.
T length2 = dot (*this);
if (length2 < T (2) * limits<T>::smallest())
- return lengthTiny();
+ return lengthTiny();
return Math<T>::sqrt (length2);
}
// produce results less than or equal to 1.
//
- x /= l;
- y /= l;
- z /= l;
+ x /= l;
+ y /= l;
+ z /= l;
}
return *this;
template <class T>
const Vec3<T> &
-Vec3<T>::normalizeExc () throw (Iex::MathExc)
+Vec3<T>::normalizeExc ()
{
T l = length();
if (l == T (0))
- throw NullVecExc ("Cannot normalize null vector.");
+ throw NullVecExc ("Cannot normalize null vector.");
x /= l;
y /= l;
T l = length();
if (l == T (0))
- return Vec3 (T (0));
+ return Vec3 (T (0));
return Vec3 (x / l, y / l, z / l);
}
template <class T>
Vec3<T>
-Vec3<T>::normalizedExc () const throw (Iex::MathExc)
+Vec3<T>::normalizedExc () const
{
T l = length();
if (l == T (0))
- throw NullVecExc ("Cannot normalize null vector.");
+ throw NullVecExc ("Cannot normalize null vector.");
return Vec3 (x / l, y / l, z / l);
}
Vec4<T>::equalWithAbsError (const Vec4<T> &v, T e) const
{
for (int i = 0; i < 4; i++)
- if (!Imath::equalWithAbsError ((*this)[i], v[i], e))
+ if (!IMATH_INTERNAL_NAMESPACE::equalWithAbsError ((*this)[i], v[i], e))
return false;
return true;
Vec4<T>::equalWithRelError (const Vec4<T> &v, T e) const
{
for (int i = 0; i < 4; i++)
- if (!Imath::equalWithRelError ((*this)[i], v[i], e))
+ if (!IMATH_INTERNAL_NAMESPACE::equalWithRelError ((*this)[i], v[i], e))
return false;
return true;
T absY = (y >= T (0))? y: -y;
T absZ = (z >= T (0))? z: -z;
T absW = (w >= T (0))? w: -w;
-
+
T max = absX;
if (max < absY)
template <class T>
const Vec4<T> &
-Vec4<T>::normalizeExc () throw (Iex::MathExc)
+Vec4<T>::normalizeExc ()
{
T l = length();
template <class T>
Vec4<T>
-Vec4<T>::normalizedExc () const throw (Iex::MathExc)
+Vec4<T>::normalizedExc () const
{
T l = length();
#pragma warning(pop)
#endif
-} // namespace Imath
+IMATH_INTERNAL_NAMESPACE_HEADER_EXIT
-#endif
+#endif // INCLUDED_IMATHVEC_H
///////////////////////////////////////////////////////////////////////////
//
-// Copyright (c) 2002, Industrial Light & Magic, a division of Lucas
+// Copyright (c) 2002-2012, Industrial Light & Magic, a division of Lucas
// Digital Ltd. LLC
-//
+//
// All rights reserved.
-//
+//
// Redistribution and use in source and binary forms, with or without
// modification, are permitted provided that the following conditions are
// met:
// distribution.
// * Neither the name of Industrial Light & Magic nor the names of
// its contributors may be used to endorse or promote products derived
-// from this software without specific prior written permission.
-//
+// from this software without specific prior written permission.
+//
// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
#include "ImathVec.h"
#include "ImathLimits.h"
+#include "ImathNamespace.h"
-namespace Imath {
+IMATH_INTERNAL_NAMESPACE_HEADER_ENTER
//-----------------------------------------------------------------
template <class Vec> Vec closestVertex (const Vec &v0,
const Vec &v1,
- const Vec &v2,
+ const Vec &v2,
const Vec &p);
//---------------
Vec
closestVertex(const Vec &v0,
const Vec &v1,
- const Vec &v2,
+ const Vec &v2,
const Vec &p)
{
Vec nearest = v0;
}
-} // namespace Imath
+IMATH_INTERNAL_NAMESPACE_HEADER_EXIT
-#endif
+#endif // INCLUDED_IMATHVECALGO_H
// used by any OpenEXR library or application code.
//
-#undef HAVE_LINUX_PROCFS
+#cmakedefine OPENEXR_IMF_HAVE_LINUX_PROCFS
//
// Define and set to 1 if the target system is a Darwin-based system
// (e.g., OS X).
//
-#undef HAVE_DARWIN
+#cmakedefine OPENEXR_IMF_HAVE_DARWIN
//
// Define and set to 1 if the target system has a complete <iomanip>
// formatter.
//
-#undef HAVE_COMPLETE_IOMANIP
+#cmakedefine OPENEXR_IMF_HAVE_COMPLETE_IOMANIP
//
// Define and set to 1 if the target system has support for large
// stack sizes.
//
-#undef HAVE_LARGE_STACK
+#cmakedefine OPENEXR_IMF_HAVE_LARGE_STACK
+
+//
+// Define if we can support GCC style inline asm with AVX instructions
+//
+
+#cmakedefine OPENEXR_IMF_HAVE_GCC_INLINE_ASM_AVX
+
+//
+// Define if we can use sysconf(_SC_NPROCESSORS_ONLN) to get CPU count
+//
+
+#cmakedefine OPENEXR_IMF_HAVE_SYSCONF_NPROCESSORS_ONLN
+
+//
+// Current internal library namepace name
+//
+#define OPENEXR_IMF_INTERNAL_NAMESPACE_CUSTOM @OPENEXR_IMF_INTERNAL_NAMESPACE_CUSTOM@
+#define OPENEXR_IMF_INTERNAL_NAMESPACE @OPENEXR_IMF_INTERNAL_NAMESPACE@
+
+//
+// Current public user namepace name
+//
+
+#define OPENEXR_IMF_NAMESPACE_CUSTOM @OPENEXR_IMF_NAMESPACE_CUSTOM@
+#define OPENEXR_IMF_NAMESPACE @OPENEXR_IMF_NAMESPACE@
//
// Version string for runtime access
//
-#define OPENEXR_VERSION_STRING "1.7.1"
-#define OPENEXR_PACKAGE_STRING "OpenEXR 1.7.1"
+
+#define OPENEXR_VERSION_STRING @OPENEXR_VERSION_STRING@
+#define OPENEXR_PACKAGE_STRING @OPENEXR_PACKAGE_STRING@
+
+#define OPENEXR_VERSION_MAJOR @OPENEXR_VERSION_MAJOR@
+#define OPENEXR_VERSION_MINOR @OPENEXR_VERSION_MINOR@
+#define OPENEXR_VERSION_PATCH @OPENEXR_VERSION_PATCH@
+
+// Version as a single hex number, e.g. 0x01000300 == 1.0.3
+#define OPENEXR_VERSION_HEX ((OPENEXR_VERSION_MAJOR << 24) | \
+ (OPENEXR_VERSION_MINOR << 16) | \
+ (OPENEXR_VERSION_PATCH << 8))
+
+++ /dev/null
-diff --git a/3rdparty/openexr/IlmImf/ImfAcesFile.cpp b/3rdparty/openexr/IlmImf/ImfAcesFile.cpp
-index de4bf83..9418b9d 100644
---- a/3rdparty/openexr/IlmImf/ImfAcesFile.cpp
-+++ b/3rdparty/openexr/IlmImf/ImfAcesFile.cpp
-@@ -42,6 +42,7 @@
- #include <ImfRgbaFile.h>
- #include <ImfStandardAttributes.h>
- #include <Iex.h>
-+#include <algorithm> // for std::max()
-
- using namespace std;
- using namespace Imath;
-diff --git a/3rdparty/openexr/IlmImf/ImfOutputFile.cpp b/3rdparty/openexr/IlmImf/ImfOutputFile.cpp
-index 8831ec9..e69b92b 100644
---- a/3rdparty/openexr/IlmImf/ImfOutputFile.cpp
-+++ b/3rdparty/openexr/IlmImf/ImfOutputFile.cpp
-@@ -58,6 +58,7 @@
- #include <vector>
- #include <fstream>
- #include <assert.h>
-+#include <algorithm> // for std::max()
-
-
- namespace Imf {
-diff --git a/3rdparty/openexr/IlmImf/ImfScanLineInputFile.cpp b/3rdparty/openexr/IlmImf/ImfScanLineInputFile.cpp
-index f7a12a3..5d8b522 100644
---- a/3rdparty/openexr/IlmImf/ImfScanLineInputFile.cpp
-+++ b/3rdparty/openexr/IlmImf/ImfScanLineInputFile.cpp
-@@ -56,6 +56,7 @@
- #include <string>
- #include <vector>
- #include <assert.h>
-+#include <algorithm> // for std::max()
-
-
- namespace Imf {
-diff --git a/3rdparty/openexr/IlmImf/ImfTiledMisc.cpp b/3rdparty/openexr/IlmImf/ImfTiledMisc.cpp
-index 57f52f1..9588e78 100644
---- a/3rdparty/openexr/IlmImf/ImfTiledMisc.cpp
-+++ b/3rdparty/openexr/IlmImf/ImfTiledMisc.cpp
-@@ -43,6 +43,7 @@
- #include "Iex.h"
- #include <ImfMisc.h>
- #include <ImfChannelList.h>
-+#include <algorithm> // for std::max()
-
-
- namespace Imf {
-diff --git a/3rdparty/openexr/IlmImf/ImfTiledOutputFile.cpp b/3rdparty/openexr/IlmImf/ImfTiledOutputFile.cpp
-index 0882106..0bc3cb3 100644
---- a/3rdparty/openexr/IlmImf/ImfTiledOutputFile.cpp
-+++ b/3rdparty/openexr/IlmImf/ImfTiledOutputFile.cpp
-@@ -63,6 +63,7 @@
- #include <fstream>
- #include <assert.h>
- #include <map>
-+#include <algorithm> // for std::max()
-
-
- namespace Imf {
-diff --git a/3rdparty/openexr/Imath/ImathMatrixAlgo.cpp b/3rdparty/openexr/Imath/ImathMatrixAlgo.cpp
-index f0d2ed6..7ddc649 100644
---- a/3rdparty/openexr/Imath/ImathMatrixAlgo.cpp
-+++ b/3rdparty/openexr/Imath/ImathMatrixAlgo.cpp
-@@ -44,6 +44,7 @@
-
- #include "ImathMatrixAlgo.h"
- #include <cmath>
-+#include <algorithm> // for std::max()
-
- #if defined(OPENEXR_DLL)
- #define EXPORT_CONST __declspec(dllexport)
OCV_OPTION(WITH_WEBP "Include WebP support" ON
VISIBLE_IF NOT WINRT
VERIFY HAVE_WEBP)
-OCV_OPTION(WITH_OPENEXR "Include ILM support via OpenEXR" ON
- VISIBLE_IF NOT IOS AND NOT WINRT
+OCV_OPTION(WITH_OPENEXR "Include ILM support via OpenEXR" BUILD_OPENEXR OR NOT CMAKE_CROSSCOMPILING
+ VISIBLE_IF NOT APPLE_FRAMEWORK AND NOT WINRT
VERIFY HAVE_OPENEXR)
OCV_OPTION(WITH_OPENGL "Include OpenGL support" OFF
VISIBLE_IF NOT ANDROID AND NOT WINRT
endif()
if(WITH_OPENEXR OR HAVE_OPENEXR)
- status(" OpenEXR:" OPENEXR_FOUND THEN "${OPENEXR_LIBRARIES} (ver ${OPENEXR_VERSION})" ELSE "build (ver ${OPENEXR_VERSION})")
+ if(HAVE_OPENEXR)
+ status(" OpenEXR:" OPENEXR_FOUND THEN "${OPENEXR_LIBRARIES} (ver ${OPENEXR_VERSION})" ELSE "build (ver ${OPENEXR_VERSION})")
+ else()
+ status(" OpenEXR:" "NO")
+ endif()
endif()
if(WITH_GDAL OR HAVE_GDAL)
# --- OpenEXR (optional) ---
if(WITH_OPENEXR)
- if(BUILD_OPENEXR)
- ocv_clear_vars(OPENEXR_FOUND)
- else()
+ ocv_clear_vars(HAVE_OPENEXR)
+ if(NOT BUILD_OPENEXR)
include("${OpenCV_SOURCE_DIR}/cmake/OpenCVFindOpenEXR.cmake")
endif()
- if(NOT OPENEXR_FOUND)
+ if(OPENEXR_FOUND)
+ set(HAVE_OPENEXR YES)
+ else()
ocv_clear_vars(OPENEXR_INCLUDE_PATHS OPENEXR_LIBRARIES OPENEXR_ILMIMF_LIBRARY OPENEXR_VERSION)
set(OPENEXR_LIBRARIES IlmImf)
- set(OPENEXR_ILMIMF_LIBRARY IlmImf)
add_subdirectory("${OpenCV_SOURCE_DIR}/3rdparty/openexr")
+ if(OPENEXR_VERSION) # check via TARGET doesn't work
+ set(HAVE_OPENEXR YES)
+ endif()
endif()
-
- set(HAVE_OPENEXR YES)
endif()
# --- GDAL (optional) ---